2001-07-12 08:32:05 +02:00
|
|
|
|
/*
|
|
|
|
|
* PROGRAM: JRD Backup and Restore Program
|
2001-12-24 03:51:06 +01:00
|
|
|
|
* MODULE: restore.epp
|
2001-07-12 08:32:05 +02:00
|
|
|
|
* DESCRIPTION: Restore routine
|
|
|
|
|
*
|
|
|
|
|
* The contents of this file are subject to the Interbase Public
|
|
|
|
|
* License Version 1.0 (the "License"); you may not use this file
|
|
|
|
|
* except in compliance with the License. You may obtain a copy
|
|
|
|
|
* of the License at http://www.Inprise.com/IPL.html
|
|
|
|
|
*
|
|
|
|
|
* Software distributed under the License is distributed on an
|
|
|
|
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
|
|
|
|
* or implied. See the License for the specific language governing
|
|
|
|
|
* rights and limitations under the License.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code was created by Inprise Corporation
|
|
|
|
|
* and its predecessors. Portions created by Inprise Corporation are
|
|
|
|
|
* Copyright (C) Inprise Corporation.
|
|
|
|
|
*
|
|
|
|
|
* All Rights Reserved.
|
|
|
|
|
* Contributor(s): ______________________________________.
|
|
|
|
|
* Toni Martir: Verbose records restored as RESTORE_VERBOSE_INTERVAL,
|
|
|
|
|
* also verbose restoring indexes as DEFERRED when verbose
|
2001-12-24 03:51:06 +01:00
|
|
|
|
*
|
2001-07-12 08:32:05 +02:00
|
|
|
|
*/
|
|
|
|
|
/*
|
2002-11-21 00:18:16 +01:00
|
|
|
|
$Id: restore.epp,v 1.12 2002-11-20 23:09:20 hippoman Exp $
|
2001-07-12 08:32:05 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
|
#include "firebird.h"
|
2001-07-12 08:32:05 +02:00
|
|
|
|
#include "../jrd/ib_stdio.h"
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include "../burp/burp.h"
|
|
|
|
|
#include "../jrd/align.h"
|
|
|
|
|
#include "../jrd/common.h"
|
|
|
|
|
#include "../jrd/flags.h"
|
|
|
|
|
#include "../jrd/license.h"
|
|
|
|
|
#include "../jrd/obj.h"
|
|
|
|
|
#include "../jrd/ods.h"
|
2001-12-24 03:51:06 +01:00
|
|
|
|
#include "../jrd/thd_proto.h"
|
2001-07-12 08:32:05 +02:00
|
|
|
|
#include "../burp/burp_proto.h"
|
|
|
|
|
#include "../burp/canon_proto.h"
|
|
|
|
|
#include "../burp/misc_proto.h"
|
|
|
|
|
#include "../burp/mvol_proto.h"
|
|
|
|
|
#include "../burp/resto_proto.h"
|
|
|
|
|
#include "../intl/charsets.h"
|
|
|
|
|
#include "../jrd/gdsassert.h"
|
|
|
|
|
#include "../remote/protocol.h"
|
|
|
|
|
|
|
|
|
|
/* For netware the follow DB handle is #defined to be a value stored */
|
|
|
|
|
/* in thread data. This is also done for other statics generated by */
|
|
|
|
|
/* GPRE. This is to avoid multiple threading problems with module */
|
|
|
|
|
/* level statics. */
|
|
|
|
|
DATABASE
|
|
|
|
|
DB = STATIC FILENAME "yachts.lnk";
|
|
|
|
|
|
|
|
|
|
#define DB tdgbl->db_handle
|
|
|
|
|
#define gds_trans tdgbl->tr_handle
|
|
|
|
|
#define isc_status tdgbl->status
|
|
|
|
|
|
|
|
|
|
/***
|
|
|
|
|
#define DEBUG 1
|
|
|
|
|
***/
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
|
#define STUFF(byte) {*blr++ = (UCHAR) (byte);}
|
2001-07-12 08:32:05 +02:00
|
|
|
|
#define STUFF_WORD(word) {STUFF (word); STUFF ((word) >> 8);}
|
|
|
|
|
#define STUFF_LONG(lword) {STUFF_WORD (lword); STUFF_WORD ((lword) >> 16);}
|
|
|
|
|
#define STUFF_INT64(i64) {STUFF_LONG (i64); STUFF_LONG ((i64) >> 32);}
|
|
|
|
|
|
|
|
|
|
#define DB_VERSION_DDL4 4 /* ods4 db */
|
|
|
|
|
#define DB_VERSION_DDL5 5 /* ods5 db */
|
|
|
|
|
#define DB_VERSION_DDL8 8 /* ods8 db */
|
|
|
|
|
#define DB_VERSION_CURRENT DB_VERSION_DDL8 /* v4.0 is ods8 */
|
2001-12-24 03:51:06 +01:00
|
|
|
|
#define FOREIGN_KEY "FOREIGN KEY"
|
2001-07-12 08:32:05 +02:00
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
|
#define DEFERRED_ACTIVE 3 /* RDB$INDEX_INACTIVE setting for Foreign Keys
|
2001-07-12 08:32:05 +02:00
|
|
|
|
* This setting is used temporarily while
|
|
|
|
|
* restoring a database. This was required
|
|
|
|
|
* in order to differentiate a partial
|
|
|
|
|
* "inactive" state of SOME indices from
|
|
|
|
|
* "inactive" state of ALL indices (gbak -i)
|
2001-12-24 03:51:06 +01:00
|
|
|
|
* -bsriram, 11-May-1999 BUG: 10016
|
2001-07-12 08:32:05 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define RESTORE_VERBOSE_INTERVAL 10000
|
|
|
|
|
#define cvtbl_len 28
|
|
|
|
|
static CONST struct s_t_cvtbl {
|
|
|
|
|
SSHORT sub_type;
|
|
|
|
|
SSHORT character_set_id;
|
|
|
|
|
SSHORT collation_id;
|
|
|
|
|
} sub_type_cvtbl [] = {
|
|
|
|
|
/* NOTE: The magic numbers for collation_id come from ordinal
|
|
|
|
|
* position of the COLLATION() entries in jrd/intlnames.h
|
|
|
|
|
*/
|
2002-01-04 12:34:22 +01:00
|
|
|
|
{101, CS_DOS_437, 1}, /* PDOX_ASCII */
|
|
|
|
|
{102, CS_DOS_437, 2}, /* PDOX_INTL */
|
|
|
|
|
{106, CS_DOS_437, 3}, /* PDOX_SWEDFIN */
|
|
|
|
|
{160, CS_DOS_850, 0}, /* codepoint collation */
|
|
|
|
|
{107, CS_DOS_865, 0}, /* codepoint collation */
|
|
|
|
|
{105, CS_DOS_865, 1}, /* PDOX_NORDAN4 */
|
|
|
|
|
{139, CS_LATIN1, 1}, /* DA_DA */
|
|
|
|
|
{140, CS_LATIN1, 2}, /* DU_NL */
|
|
|
|
|
{141, CS_LATIN1, 3}, /* FI_FI */
|
|
|
|
|
{142, CS_LATIN1, 4}, /* FR_FR */
|
|
|
|
|
{143, CS_LATIN1, 5}, /* FR_CA */
|
|
|
|
|
{144, CS_LATIN1, 6}, /* DE_DE */
|
|
|
|
|
{145, CS_LATIN1, 7}, /* IS_IS */
|
|
|
|
|
{146, CS_LATIN1, 8}, /* IT_IT */
|
|
|
|
|
{148, CS_LATIN1, 9}, /* NO_NO */
|
|
|
|
|
{149, CS_LATIN1, 10}, /* ES_ES */
|
|
|
|
|
{151, CS_LATIN1, 11}, /* SV_SV */
|
|
|
|
|
{152, CS_LATIN1, 12}, /* EN_UK */
|
|
|
|
|
{153, CS_LATIN1, 14}, /* EN_US */
|
|
|
|
|
{154, CS_LATIN1, 15}, /* PT_PT */
|
2002-06-29 07:39:38 +02:00
|
|
|
|
{160, CS_LATIN2, 1}, /* CS_CZ */
|
2002-01-04 12:34:22 +01:00
|
|
|
|
{180, CS_NEXT, 1}, /* NXT_US */
|
|
|
|
|
{181, CS_NEXT, 2}, /* NXT_GERMANY */
|
|
|
|
|
{182, CS_NEXT, 3}, /* NXT_FRANCE */
|
|
|
|
|
{183, CS_NEXT, 4}, /* NXT_ITALY */
|
|
|
|
|
{184, CS_NEXT, 5}, /* NXT_SPAIN */
|
|
|
|
|
{201, CS_UNICODE_FSS, 0}, /* codepoint collation */
|
|
|
|
|
{220, CS_SJIS, 0}, /* codepoint collation */
|
|
|
|
|
{230, CS_EUCJ, 0} /* codepoint collation */
|
2001-07-12 08:32:05 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void add_files (UCHAR *);
|
|
|
|
|
static void bad_attribute (UCHAR, ATT_TYPE, USHORT);
|
|
|
|
|
static USHORT check_db_version (void);
|
|
|
|
|
static void create_database (UCHAR *);
|
|
|
|
|
static void decompress (UCHAR *, USHORT);
|
|
|
|
|
static void eat_blob (void);
|
2002-11-17 01:04:19 +01:00
|
|
|
|
static BURP_REL find_relation (TEXT *);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
static int get_acl (TEXT *, ISC_QUAD *, ISC_QUAD *);
|
2002-11-17 01:04:19 +01:00
|
|
|
|
static void get_array (BURP_REL, UCHAR *);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
static void get_blob (FLD, UCHAR *);
|
|
|
|
|
static void get_blr_blob (ISC_QUAD *, USHORT);
|
|
|
|
|
static BOOLEAN get_character_set (void);
|
|
|
|
|
static BOOLEAN get_chk_constraint (void);
|
|
|
|
|
static BOOLEAN get_collation (void);
|
2002-11-17 01:04:19 +01:00
|
|
|
|
static REC_TYPE get_data (BURP_REL);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
static BOOLEAN get_exception (void);
|
2002-11-17 01:04:19 +01:00
|
|
|
|
static FLD get_field (BURP_REL);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
static BOOLEAN get_field_dimensions (void);
|
|
|
|
|
static BOOLEAN get_files (void);
|
|
|
|
|
static BOOLEAN get_filter (void);
|
|
|
|
|
static BOOLEAN get_function (void);
|
|
|
|
|
static void get_function_arg (GDS_NAME);
|
|
|
|
|
static BOOLEAN get_generator (void);
|
|
|
|
|
static BOOLEAN get_global_field (void);
|
2002-11-17 01:04:19 +01:00
|
|
|
|
static BOOLEAN get_index (BURP_REL);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
static void get_misc_blob (ISC_QUAD *, USHORT, USHORT);
|
|
|
|
|
static SLONG get_numeric (void);
|
|
|
|
|
static SINT64 get_int64 (void);
|
|
|
|
|
static BOOLEAN get_procedure (void);
|
|
|
|
|
static BOOLEAN get_procedure_prm (GDS_NAME );
|
|
|
|
|
static BOOLEAN get_ref_constraint (void);
|
|
|
|
|
static BOOLEAN get_rel_constraint (void);
|
|
|
|
|
static BOOLEAN get_relation (void);
|
|
|
|
|
static BOOLEAN get_relation_data (void);
|
|
|
|
|
static BOOLEAN get_sql_roles (void);
|
|
|
|
|
static BOOLEAN get_security_class (void);
|
|
|
|
|
static void get_source_blob (ISC_QUAD *, USHORT);
|
|
|
|
|
static USHORT get_text (TEXT *, ULONG);
|
|
|
|
|
static BOOLEAN get_trigger (void);
|
|
|
|
|
static BOOLEAN get_trigger_message (void);
|
2002-11-17 01:04:19 +01:00
|
|
|
|
static BOOLEAN get_trigger_old (BURP_REL);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
static BOOLEAN get_type (void);
|
|
|
|
|
static BOOLEAN get_user_privilege (void);
|
2002-11-17 01:04:19 +01:00
|
|
|
|
static BOOLEAN get_view (BURP_REL);
|
|
|
|
|
static void ignore_array (BURP_REL);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
static void ignore_blob (void);
|
2002-11-17 01:04:19 +01:00
|
|
|
|
static REC_TYPE ignore_data (BURP_REL);
|
|
|
|
|
static void realign (UCHAR *, BURP_REL);
|
|
|
|
|
static USHORT recompute_length (BURP_REL);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
static BOOLEAN restore (TEXT *, TEXT *);
|
|
|
|
|
static void restore_security_class (TEXT *, TEXT *);
|
|
|
|
|
static void store_blr_gen_id (GDS_NAME, SINT64);
|
|
|
|
|
static void stuff_string (SCHAR **, TEXT *);
|
|
|
|
|
static void update_global_field (void);
|
|
|
|
|
static void general_on_error (void);
|
|
|
|
|
static BOOLEAN bug_8183 (TGBL);
|
|
|
|
|
|
|
|
|
|
static UCHAR debug_on = 0; /* able to turn this on in the debugger */
|
|
|
|
|
|
|
|
|
|
static USHORT flag_on_line = TRUE; /* indicates whether we will bring
|
|
|
|
|
the database on-line :
|
|
|
|
|
TRUE - we will
|
|
|
|
|
FALSE - we will not */
|
|
|
|
|
#ifdef sparc
|
|
|
|
|
static CONST SSHORT old_sparcs[] =
|
|
|
|
|
{0, 0, 0, 2, 0, 0, 0, 0, 2, 4, 4, 4, 8, 8, 0, 0, 8, 8, 8};
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define GET() (--(tdgbl->io_cnt) >= 0 ? *(tdgbl->io_ptr)++ : MVOL_read (&tdgbl->io_cnt, &tdgbl->io_ptr))
|
|
|
|
|
#define GET_SKIP(n) MVOL_skip_block (tdgbl, n)
|
|
|
|
|
#define GET_BLOCK(p,n) MVOL_read_block (tdgbl, (p), (n))
|
|
|
|
|
#define GET_ATTRIBUTE(att) ((att) = (ATT_TYPE) GET())
|
|
|
|
|
#define GET_RECORD(att) ((att) = (REC_TYPE) GET())
|
2001-12-24 03:51:06 +01:00
|
|
|
|
#define GET_TEXT(text) get_text((text), sizeof(text))
|
2001-07-12 08:32:05 +02:00
|
|
|
|
|
|
|
|
|
/* When skipping started, scan_next_attr will be changed from NO_SKIP */
|
|
|
|
|
/* to BEFORE_SKIP. When scanning for next valid attribute after skipping, */
|
|
|
|
|
/* it will flip-flop between BEFORE_SKIP and AFTER_SKIP. When next valid */
|
|
|
|
|
/* attribute is found, it will be changed back to NO_SKIP by 'SKIP_SCAN' */
|
|
|
|
|
|
|
|
|
|
#define NO_SKIP 0 /* Not in skipping and scanning mode */
|
|
|
|
|
#define BEFORE_SKIP 1 /* After skipping, before scanning next byte for valid attribute */
|
|
|
|
|
#define AFTER_SKIP 2 /* After skipping and after scanning next byte for valid attribute */
|
|
|
|
|
|
|
|
|
|
#define SKIP_INIT (scan_next_attr = NO_SKIP)
|
|
|
|
|
#define SKIP_SCAN (scan_next_attr == AFTER_SKIP ? \
|
|
|
|
|
scan_next_attr = BEFORE_SKIP : \
|
|
|
|
|
scan_next_attr == BEFORE_SKIP ? \
|
|
|
|
|
scan_next_attr = NO_SKIP : 0)
|
|
|
|
|
/* User Privilege Flags */
|
|
|
|
|
|
|
|
|
|
#define USER_PRIV_USER 1
|
|
|
|
|
#define USER_PRIV_GRANTOR 2
|
|
|
|
|
#define USER_PRIV_PRIVILEGE 4
|
|
|
|
|
#define USER_PRIV_GRANT_OPTION 8
|
|
|
|
|
#define USER_PRIV_OBJECT_NAME 16
|
|
|
|
|
#define USER_PRIV_FIELD_NAME 32
|
|
|
|
|
#define USER_PRIV_USER_TYPE 64
|
|
|
|
|
#define USER_PRIV_OBJECT_TYPE 128
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int RESTORE_restore (
|
|
|
|
|
TEXT *file_name,
|
|
|
|
|
TEXT *database_name)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* R E S T O R E _ r e s t o r e
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Recreate a database from a backup.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
2002-10-29 17:31:02 +01:00
|
|
|
|
UINT64 cumul_count;
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_REL relation;
|
|
|
|
|
BURP_PRC procedure;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
isc_req_handle req_handle1 = NULL, req_handle2 = NULL, req_handle4 = NULL;
|
2002-10-24 11:01:44 +02:00
|
|
|
|
STATUS req_status[ISC_STATUS_LENGTH];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
long db_handle;
|
|
|
|
|
UCHAR dpb[128], *d, *q;
|
|
|
|
|
SSHORT l;
|
|
|
|
|
isc_req_handle req_handle3 = NULL;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
long error_code;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
tdgbl->io_ptr = (UCHAR *) NULL;
|
|
|
|
|
tdgbl->io_cnt = 0;
|
|
|
|
|
|
2002-11-17 01:04:19 +01:00
|
|
|
|
tdgbl->relations = (BURP_REL) NULL;
|
|
|
|
|
tdgbl->procedures = (BURP_PRC) 0;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
tdgbl->RESTORE_format = 0;
|
|
|
|
|
tdgbl->global_trans = 0;
|
|
|
|
|
|
|
|
|
|
tdgbl->gbl_sw_transportable = tdgbl->gbl_sw_compress = FALSE;
|
|
|
|
|
|
|
|
|
|
if (!restore (file_name, database_name))
|
|
|
|
|
return FINI_ERROR;
|
|
|
|
|
|
|
|
|
|
BURP_verbose (76, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 76 creating indexes */
|
|
|
|
|
|
|
|
|
|
COMMIT;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
/* Fix for bug_no 8055:
|
|
|
|
|
don't throw away the database just because an index
|
|
|
|
|
could not be made */
|
|
|
|
|
while (error_code = tdgbl->status_vector[1])
|
|
|
|
|
{
|
|
|
|
|
switch (error_code)
|
|
|
|
|
{
|
|
|
|
|
case gds_sort_mem_err:
|
|
|
|
|
case gds_no_dup:
|
|
|
|
|
strcpy(index_name, (TEXT *)tdgbl->status_vector[3]);
|
|
|
|
|
BURP_print_status(tdgbl->status_vector);
|
|
|
|
|
FOR (REQUEST_HANDLE req_handle3)
|
|
|
|
|
IDX IN RDB$INDICES WITH IDX.RDB$INDEX_NAME EQ index_name
|
|
|
|
|
{
|
|
|
|
|
BURP_verbose(243,index_name,NULL_PTR,NULL_PTR,NULL_PTR,NULL_PTR);
|
|
|
|
|
MODIFY IDX USING IDX.RDB$INDEX_INACTIVE = TRUE;
|
|
|
|
|
}
|
|
|
|
|
BURP_print(240, index_name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 240 Index \"%s\" failed to activate because: */
|
|
|
|
|
if ( error_code == gds_no_dup )
|
|
|
|
|
{
|
|
|
|
|
BURP_print(241, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 241 The unique index has duplicate values or NULLs */
|
|
|
|
|
BURP_print(242, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 242 Delete or Update duplicate values or NULLs, and activate index with */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
BURP_print(244, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 244 Not enough disk space to create the sort file for an index */
|
|
|
|
|
BURP_print(245, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 245 Set the TMP environment variable to a directory on a filesystem that does have enough space, and activate index with */
|
|
|
|
|
}
|
|
|
|
|
BURP_print(243, index_name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 243 ALTER INDEX \"%s\" ACTIVE; */
|
|
|
|
|
END_MODIFY;
|
|
|
|
|
END_FOR;
|
|
|
|
|
/* don't bring the database on-line */
|
|
|
|
|
flag_on_line = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
general_on_error ();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
COMMIT
|
|
|
|
|
ON_ERROR
|
|
|
|
|
continue;
|
|
|
|
|
END_ERROR
|
|
|
|
|
}
|
|
|
|
|
END_ERROR;
|
|
|
|
|
/* Activate the indices for foreign keys and do another commit */
|
|
|
|
|
if (!(tdgbl->gbl_sw_deactivate_indexes))
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* Block added to verbose index creation by Toni Martir */
|
|
|
|
|
if (tdgbl->gbl_sw_verbose)
|
|
|
|
|
{
|
|
|
|
|
EXEC SQL SET TRANSACTION ISOLATION LEVEL READ COMMITTED NO_AUTO_UNDO;
|
|
|
|
|
if (gds_status [1])
|
|
|
|
|
EXEC SQL SET TRANSACTION;
|
|
|
|
|
|
|
|
|
|
/* Activate first indexes that are not foreign keys */
|
|
|
|
|
FOR (REQUEST_HANDLE req_handle1) IDS IN RDB$INDICES WITH
|
|
|
|
|
IDS.RDB$INDEX_INACTIVE EQ DEFERRED_ACTIVE AND
|
|
|
|
|
IDS.RDB$FOREIGN_KEY MISSING
|
|
|
|
|
MODIFY IDS USING IDS.RDB$INDEX_INACTIVE=FALSE;
|
|
|
|
|
END_MODIFY;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
SAVE
|
|
|
|
|
/* existing ON_ERROR continues past error, beck */
|
|
|
|
|
ON_ERROR
|
|
|
|
|
BURP_print (173, IDS.RDB$INDEX_NAME, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
BURP_print_status (tdgbl->status);
|
|
|
|
|
MODIFY IDS USING
|
|
|
|
|
IDS.RDB$INDEX_INACTIVE = TRUE;
|
|
|
|
|
END_MODIFY;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
END_ERROR;
|
|
|
|
|
BURP_verbose(122,IDS.RDB$INDEX_NAME,NULL_PTR,NULL_PTR,NULL_PTR,NULL_PTR);
|
|
|
|
|
END_FOR;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
if (req_handle1)
|
|
|
|
|
isc_release_request (req_status, &req_handle1);
|
|
|
|
|
COMMIT;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
EXEC SQL SET TRANSACTION ISOLATION LEVEL READ COMMITTED NO_AUTO_UNDO;
|
|
|
|
|
if (gds_status [1])
|
|
|
|
|
EXEC SQL SET TRANSACTION;
|
|
|
|
|
|
|
|
|
|
/* Only activate Foreign keys that have been marked for deferred
|
|
|
|
|
* activation.
|
|
|
|
|
* -bsriram, 11-May-1999 BUG: 10016
|
|
|
|
|
*/
|
|
|
|
|
FOR (REQUEST_HANDLE req_handle1)
|
|
|
|
|
CNST IN RDB$RELATION_CONSTRAINTS
|
|
|
|
|
CROSS IDS IN RDB$INDICES WITH
|
|
|
|
|
CNST.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY AND
|
|
|
|
|
CNST.RDB$INDEX_NAME EQ IDS.RDB$INDEX_NAME AND
|
|
|
|
|
IDS.RDB$INDEX_INACTIVE EQ DEFERRED_ACTIVE
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MODIFY IDS USING
|
|
|
|
|
IDS.RDB$INDEX_INACTIVE = FALSE;
|
|
|
|
|
END_MODIFY;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
SAVE
|
|
|
|
|
/* existing ON_ERROR continues past error, beck */
|
|
|
|
|
ON_ERROR
|
|
|
|
|
BURP_print (173, IDS.RDB$INDEX_NAME, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
BURP_print_status (tdgbl->status);
|
|
|
|
|
MODIFY IDS USING
|
|
|
|
|
IDS.RDB$INDEX_INACTIVE = TRUE;
|
|
|
|
|
END_MODIFY;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
END_ERROR;
|
|
|
|
|
BURP_verbose(122,IDS.RDB$INDEX_NAME,NULL_PTR,NULL_PTR,NULL_PTR,NULL_PTR);
|
|
|
|
|
END_FOR;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
if (req_handle1)
|
|
|
|
|
isc_release_request (req_status, &req_handle1);
|
|
|
|
|
COMMIT;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tdgbl->global_trans)
|
|
|
|
|
{
|
|
|
|
|
EXEC SQL COMMIT TRANSACTION tdgbl->global_trans;
|
|
|
|
|
if (gds_status [1])
|
|
|
|
|
general_on_error ();
|
|
|
|
|
/* Check to see if there is a warning */
|
|
|
|
|
if (gds_status [0] == gds_arg_gds && gds_status [1] == 0 && gds_status [2] != gds_arg_end)
|
|
|
|
|
BURP_print_warning (gds_status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EXEC SQL SET TRANSACTION ISOLATION LEVEL READ COMMITTED NO_AUTO_UNDO;
|
|
|
|
|
if (gds_status [1])
|
|
|
|
|
EXEC SQL SET TRANSACTION;
|
|
|
|
|
/*
|
|
|
|
|
** Change ownership of any procedures necessary
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for (procedure = tdgbl->procedures; procedure;
|
|
|
|
|
procedure = procedure->prc_next)
|
|
|
|
|
if (procedure->prc_owner [0])
|
|
|
|
|
FOR (REQUEST_HANDLE req_handle4)
|
|
|
|
|
X IN RDB$PROCEDURES WITH X.RDB$PROCEDURE_NAME EQ procedure->prc_name
|
|
|
|
|
|
|
|
|
|
MODIFY X
|
|
|
|
|
strcpy (X.RDB$OWNER_NAME, procedure->prc_owner);
|
|
|
|
|
END_MODIFY;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
if (req_handle4)
|
|
|
|
|
isc_release_request (req_status, &req_handle4);
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
restore_security_class (procedure->prc_owner, X.RDB$SECURITY_CLASS);
|
|
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
if (req_handle4)
|
|
|
|
|
isc_release_request (req_status, &req_handle4);
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
if (req_handle4)
|
|
|
|
|
isc_release_request (req_status, &req_handle4);
|
|
|
|
|
|
|
|
|
|
/* Change ownership of any relations necessary */
|
|
|
|
|
|
|
|
|
|
for (relation = tdgbl->relations; relation; relation = relation->rel_next)
|
|
|
|
|
if (relation->rel_owner [0])
|
|
|
|
|
FOR (REQUEST_HANDLE req_handle2)
|
|
|
|
|
X IN RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ relation->rel_name
|
|
|
|
|
MODIFY X
|
|
|
|
|
strcpy (X.RDB$OWNER_NAME, relation->rel_owner);
|
|
|
|
|
END_MODIFY;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
if (req_handle2)
|
|
|
|
|
isc_release_request (req_status, &req_handle2);
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
restore_security_class (relation->rel_owner, X.RDB$SECURITY_CLASS);
|
|
|
|
|
restore_security_class (relation->rel_owner, X.RDB$DEFAULT_CLASS);
|
|
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
if (req_handle2)
|
|
|
|
|
isc_release_request (req_status, &req_handle2);
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
if (req_handle2)
|
|
|
|
|
isc_release_request (req_status, &req_handle2);
|
|
|
|
|
|
|
|
|
|
/* Now that changing ownership of tables is over, it is safe to
|
|
|
|
|
update the database security class in RDB$DATABASE */
|
|
|
|
|
|
|
|
|
|
if (tdgbl->database_security_class[0]) /* Do it only if it's not NULL */
|
|
|
|
|
{
|
|
|
|
|
FOR (REQUEST_HANDLE req_handle1)
|
|
|
|
|
X IN RDB$DATABASE
|
|
|
|
|
MODIFY X USING
|
|
|
|
|
strncpy(X.RDB$SECURITY_CLASS, tdgbl->database_security_class,
|
|
|
|
|
sizeof(X.RDB$SECURITY_CLASS));
|
|
|
|
|
END_MODIFY;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
if (req_handle1)
|
|
|
|
|
isc_release_request (req_status, &req_handle1);
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
END_FOR;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
if (req_handle1)
|
|
|
|
|
isc_release_request (req_status, &req_handle1);
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
if (req_handle1)
|
|
|
|
|
isc_release_request (req_status, &req_handle1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COMMIT;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
/* Check to see if there is a warning */
|
|
|
|
|
if (gds_status [0] == gds_arg_gds && gds_status [1] == 0 && gds_status [2] != gds_arg_end)
|
|
|
|
|
BURP_print_warning (gds_status);
|
|
|
|
|
|
|
|
|
|
BURP_verbose (88, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 88 finishing, closing, and going home */
|
|
|
|
|
|
2002-10-29 17:31:02 +01:00
|
|
|
|
cumul_count = MVOL_fini_read();
|
2001-07-12 08:32:05 +02:00
|
|
|
|
|
|
|
|
|
/* attach database again to put it online */
|
|
|
|
|
|
|
|
|
|
d = dpb;
|
|
|
|
|
*d++ = (UCHAR) gds_dpb_version1;
|
|
|
|
|
|
|
|
|
|
if (flag_on_line)
|
|
|
|
|
{
|
|
|
|
|
*d++ = (UCHAR) gds_dpb_online;
|
|
|
|
|
*d++ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_user)
|
|
|
|
|
{
|
|
|
|
|
*d++ = (UCHAR) gds_dpb_user_name;
|
|
|
|
|
*d++ = (UCHAR) strlen (tdgbl->gbl_sw_user);
|
|
|
|
|
for (q = (UCHAR*) tdgbl->gbl_sw_user; *q;)
|
|
|
|
|
*d++ = *q++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_password)
|
|
|
|
|
{
|
|
|
|
|
if (!tdgbl->gbl_sw_service_thd)
|
|
|
|
|
*d++ = (UCHAR) gds_dpb_password;
|
|
|
|
|
else
|
|
|
|
|
*d++ = (UCHAR) gds_dpb_password_enc;
|
|
|
|
|
*d++ = (UCHAR) strlen (tdgbl->gbl_sw_password);
|
|
|
|
|
for (q = (UCHAR*) tdgbl->gbl_sw_password; *q;)
|
|
|
|
|
*d++ = *q++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* set sync writes to engine default */
|
|
|
|
|
*d++ = (UCHAR) gds_dpb_force_write;
|
|
|
|
|
*d++ = 1;
|
|
|
|
|
*d++ = (UCHAR) tdgbl->hdr_forced_writes; /* set forced writes to the value which was in the header */
|
|
|
|
|
|
|
|
|
|
l = d - dpb;
|
|
|
|
|
db_handle = 0;
|
|
|
|
|
if (isc_attach_database (tdgbl->status_vector, 0, GDS_VAL(database_name),
|
|
|
|
|
(isc_db_handle*)GDS_REF( db_handle), l, (SCHAR*) dpb))
|
|
|
|
|
general_on_error();
|
|
|
|
|
if (isc_detach_database (tdgbl->status_vector, (isc_db_handle*)GDS_REF(db_handle)))
|
|
|
|
|
general_on_error();
|
|
|
|
|
|
|
|
|
|
FINISH
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
if (!flag_on_line)
|
|
|
|
|
{
|
|
|
|
|
BURP_print(246, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 246 Database is not online due to failure to activate one or more indices. */
|
|
|
|
|
BURP_print(247, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 247 Run gfix -online to bring database online without active indices. */
|
|
|
|
|
return FINI_DB_NOT_ONLINE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the database is to be restored ReadOnly, set it to read_only now! */
|
|
|
|
|
if (tdgbl->gbl_sw_mode == TRUE && tdgbl->gbl_sw_mode_val == TRUE)
|
|
|
|
|
{
|
|
|
|
|
BURP_verbose (280, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 280: setting database to read-only access */
|
|
|
|
|
|
|
|
|
|
d = dpb;
|
|
|
|
|
*d++ = (UCHAR) gds_dpb_version1;
|
|
|
|
|
if (tdgbl->gbl_sw_user)
|
|
|
|
|
{
|
|
|
|
|
*d++ = (UCHAR) gds_dpb_user_name;
|
|
|
|
|
*d++ = (UCHAR) strlen (tdgbl->gbl_sw_user);
|
|
|
|
|
for (q = (UCHAR*) tdgbl->gbl_sw_user; *q;)
|
|
|
|
|
*d++ = *q++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_password)
|
|
|
|
|
{
|
|
|
|
|
if (!tdgbl->gbl_sw_service_thd)
|
|
|
|
|
*d++ = (UCHAR) gds_dpb_password;
|
|
|
|
|
else
|
|
|
|
|
*d++ = (UCHAR) gds_dpb_password_enc;
|
|
|
|
|
*d++ = (UCHAR) strlen (tdgbl->gbl_sw_password);
|
|
|
|
|
for (q = (UCHAR*) tdgbl->gbl_sw_password; *q;)
|
|
|
|
|
*d++ = *q++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*d++ = (UCHAR) isc_dpb_set_db_readonly;
|
|
|
|
|
*d++ = 1;
|
|
|
|
|
*d++ = TRUE; /* set database to readOnly mode */
|
|
|
|
|
l = d - dpb;
|
|
|
|
|
db_handle = 0;
|
|
|
|
|
if (isc_attach_database (tdgbl->status_vector, 0, GDS_VAL(database_name),
|
|
|
|
|
(isc_db_handle*)GDS_REF( db_handle), l, (SCHAR*) dpb))
|
|
|
|
|
general_on_error();
|
|
|
|
|
if (isc_detach_database (tdgbl->status_vector, (isc_db_handle*)GDS_REF(db_handle)))
|
|
|
|
|
general_on_error();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FINI_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void add_files (
|
|
|
|
|
UCHAR *file_name)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* a d d _ f i l e s
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* This should be a multi-file database.
|
|
|
|
|
* Store files and starting
|
|
|
|
|
* addresses & commit this much.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
SLONG start, count;
|
|
|
|
|
FIL file;
|
|
|
|
|
isc_req_handle req_handle1 = NULL;
|
2002-10-24 11:01:44 +02:00
|
|
|
|
STATUS req_status[ISC_STATUS_LENGTH];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
/* store the RDB$FILES records */
|
|
|
|
|
|
|
|
|
|
start = 201;
|
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
|
|
for (file = tdgbl->gbl_sw_files; file; file = file->fil_next)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp (file->fil_name, (char*) file_name))
|
|
|
|
|
{
|
|
|
|
|
count++;
|
|
|
|
|
STORE (REQUEST_HANDLE req_handle1)
|
|
|
|
|
X IN RDB$FILES
|
|
|
|
|
strcpy (X.RDB$FILE_NAME, file->fil_name);
|
|
|
|
|
X.RDB$FILE_START = start;
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
if (req_handle1)
|
|
|
|
|
isc_release_request (req_status, &req_handle1);
|
|
|
|
|
BURP_verbose (57, file->fil_name, (void*) start, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 57 adding file %s, starting at page %ld */
|
|
|
|
|
}
|
|
|
|
|
else if (((signed long )file->fil_length) >= start - 1)
|
|
|
|
|
file->fil_length -= start - 1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
BURP_print (96, (void*) file->fil_length, (void*) (start - 1), NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 96 length given for initial file (%ld) is less than minimum (%ld) */
|
|
|
|
|
file->fil_length = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
start += file->fil_length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (count)
|
|
|
|
|
{
|
|
|
|
|
BURP_verbose (70, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 70 committing secondary files */
|
|
|
|
|
COMMIT
|
|
|
|
|
/* existing ON_ERROR continues past error, beck */
|
|
|
|
|
ON_ERROR
|
|
|
|
|
BURP_print (174, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 174 cannot commit files */
|
|
|
|
|
BURP_print_status (tdgbl->status_vector);
|
|
|
|
|
ROLLBACK;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
|
|
|
|
|
if (gds_status [1])
|
|
|
|
|
EXEC SQL SET TRANSACTION;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void bad_attribute (
|
|
|
|
|
UCHAR scan_next_attr,
|
|
|
|
|
ATT_TYPE bad_attr,
|
|
|
|
|
USHORT type)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* b a d _ a t t r i b u t e
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* We ran into an unsupported attribute.
|
|
|
|
|
* but it isn't the end of the world.
|
|
|
|
|
* We will try to skip some bad data and
|
|
|
|
|
* look for next valid attribute to continue the process.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
SSHORT skip_l;
|
|
|
|
|
TEXT t_name [128];
|
|
|
|
|
SLONG skip_count;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
skip_count = 0;
|
|
|
|
|
|
|
|
|
|
if (!tdgbl->gbl_sw_skip_count)
|
|
|
|
|
{
|
|
|
|
|
gds__msg_format (NULL_PTR, 12, type, sizeof (t_name), t_name, (TEXT*) NULL_PTR, (TEXT*) NULL_PTR, (TEXT*) NULL_PTR, (TEXT*) NULL_PTR, (TEXT*) NULL_PTR);
|
|
|
|
|
BURP_print (80, t_name, (void*) bad_attr, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 80 don't recognize %s attribute %ld -- continuing */
|
|
|
|
|
skip_l = GET();
|
|
|
|
|
if (skip_l)
|
|
|
|
|
GET_SKIP (skip_l);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (scan_next_attr == NO_SKIP)
|
|
|
|
|
{
|
|
|
|
|
skip_count = tdgbl->gbl_sw_skip_count;
|
|
|
|
|
GET_SKIP (skip_count);
|
|
|
|
|
BURP_print (203, (void*) skip_count, (void*) bad_attr, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/*msg 203: skipped %d bytes after reading a bad attribute %d */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
skip_count ++;
|
|
|
|
|
BURP_print (205, (void*) skip_count, (void*) bad_attr, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 205: skipped %d bytes looking for next valid attribute, encountered attribute %d */
|
|
|
|
|
}
|
|
|
|
|
scan_next_attr = AFTER_SKIP;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static USHORT check_db_version (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* c h e c k _ d b _ v e r s i o n
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Find the version number of the database.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
USHORT db_version;
|
|
|
|
|
isc_req_handle req_handle1 = NULL, req_handle2 = NULL;
|
2002-10-24 11:01:44 +02:00
|
|
|
|
STATUS req_status[ISC_STATUS_LENGTH];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
db_version = DB_VERSION_DDL4;
|
|
|
|
|
FOR (REQUEST_HANDLE req_handle1)
|
|
|
|
|
FIRST 1 X IN RDB$RELATIONS
|
|
|
|
|
WITH X.RDB$RELATION_NAME = "RDB$TRIGGERS"
|
|
|
|
|
db_version = DB_VERSION_DDL5;
|
|
|
|
|
END_FOR;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
if (req_handle1)
|
|
|
|
|
isc_release_request (req_status, &req_handle1);
|
|
|
|
|
FOR (REQUEST_HANDLE req_handle2)
|
|
|
|
|
FIRST 1 X IN RDB$RELATIONS
|
|
|
|
|
WITH X.RDB$RELATION_NAME = "RDB$PROCEDURES"
|
|
|
|
|
db_version = DB_VERSION_DDL8;
|
|
|
|
|
END_FOR;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
if (req_handle2)
|
|
|
|
|
isc_release_request (req_status, &req_handle2);
|
|
|
|
|
|
|
|
|
|
return db_version;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void create_database (
|
|
|
|
|
UCHAR *file_name)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* c r e a t e _ d a t a b a s e
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* create the new database, looking
|
|
|
|
|
* to see if there are any interesting
|
|
|
|
|
* things to do.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
SSHORT l;
|
2002-10-24 11:01:44 +02:00
|
|
|
|
STATUS status_vector[ISC_STATUS_LENGTH];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
REC_TYPE record;
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
UCHAR dpb [128], *d, *q;
|
|
|
|
|
ULONG page_size, sweep_interval, page_buffers;
|
|
|
|
|
USHORT no_reserve, forced_writes;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
USHORT SQL_dialect;
|
|
|
|
|
BOOLEAN db_read_only, SQL_dialect_flag = FALSE;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
/* Get (physical) database record */
|
|
|
|
|
|
|
|
|
|
page_size = DEFAULT_PAGE_SIZE;
|
|
|
|
|
// sweep_interval = -1;
|
2002-04-04 07:32:02 +02:00
|
|
|
|
// sweep_interval = 0xFFFFFFFF;
|
|
|
|
|
sweep_interval = MAX_ULONG;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
no_reserve = FALSE;
|
|
|
|
|
db_read_only = FALSE;
|
|
|
|
|
forced_writes = 2; /* default for the current platform */
|
|
|
|
|
page_buffers = 0;
|
|
|
|
|
|
|
|
|
|
if (GET_RECORD (record) == rec_physical_db)
|
|
|
|
|
{
|
|
|
|
|
while (GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_SQL_dialect:
|
|
|
|
|
SQL_dialect_flag = TRUE;
|
|
|
|
|
SQL_dialect = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_page_size:
|
|
|
|
|
page_size = get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_sweep_interval:
|
|
|
|
|
sweep_interval = get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_forced_writes:
|
|
|
|
|
forced_writes = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_no_reserve:
|
|
|
|
|
no_reserve = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_db_read_only:
|
|
|
|
|
db_read_only = (UCHAR) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_page_buffers:
|
|
|
|
|
page_buffers = get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
l = GET();
|
|
|
|
|
if (l)
|
|
|
|
|
GET_SKIP (l);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
GET_RECORD (record);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (record != rec_database)
|
|
|
|
|
BURP_error_redirect ((STATUS*) NULL_PTR, 32, 0, 0);
|
|
|
|
|
/* msg 32 Expected database description record */
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_page_size &&
|
|
|
|
|
(tdgbl->gbl_sw_page_size < page_size))
|
|
|
|
|
{
|
|
|
|
|
BURP_print (110, (void*) page_size, (void*) tdgbl->gbl_sw_page_size, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 110 Reducing the database page size from %ld bytes to %ld bytes */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_page_size)
|
|
|
|
|
page_size = tdgbl->gbl_sw_page_size;
|
|
|
|
|
|
|
|
|
|
tdgbl->hdr_forced_writes = forced_writes;
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_no_reserve)
|
|
|
|
|
no_reserve = tdgbl->gbl_sw_no_reserve;
|
|
|
|
|
|
|
|
|
|
/* Override attribute setting with user requirement */
|
|
|
|
|
if (tdgbl->gbl_sw_mode == TRUE)
|
|
|
|
|
db_read_only = tdgbl->gbl_sw_mode_val;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* No access mode specified by user. Use attribute settings. Since the
|
|
|
|
|
* database is set to readOnly only after making it Online in
|
|
|
|
|
* RESTORE_restore(), pass on this information through Global structures */
|
|
|
|
|
tdgbl->gbl_sw_mode = TRUE;
|
|
|
|
|
tdgbl->gbl_sw_mode_val = db_read_only;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_page_buffers)
|
|
|
|
|
page_buffers = tdgbl->gbl_sw_page_buffers;
|
|
|
|
|
|
|
|
|
|
d = dpb;
|
|
|
|
|
*d++ = (UCHAR) isc_dpb_version1;
|
|
|
|
|
*d++ = (UCHAR) isc_dpb_page_size;
|
|
|
|
|
*d++ = 2;
|
|
|
|
|
*d++ = 0;
|
|
|
|
|
*d++ = (UCHAR) (page_size >> 8);
|
|
|
|
|
*d++ = (UCHAR) isc_dpb_gbak_attach;
|
|
|
|
|
*d++ = (UCHAR) strlen(GDS_VERSION);
|
|
|
|
|
for (q = (UCHAR*) GDS_VERSION; *q;)
|
|
|
|
|
*d++ = *q++;
|
|
|
|
|
|
2002-04-04 07:32:02 +02:00
|
|
|
|
if (sweep_interval != MAX_ULONG)
|
2001-07-12 08:32:05 +02:00
|
|
|
|
{
|
|
|
|
|
*d++ = (UCHAR) isc_dpb_sweep_interval;
|
|
|
|
|
*d++ = 4;
|
|
|
|
|
*d++ = (UCHAR) sweep_interval;
|
|
|
|
|
*d++ = (UCHAR) (sweep_interval >> 8);
|
|
|
|
|
*d++ = (UCHAR) (sweep_interval >> 16);
|
|
|
|
|
*d++ = (UCHAR) (sweep_interval >> 24);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the database is to be restored "read_only", fillup the data pages */
|
|
|
|
|
if (no_reserve || db_read_only)
|
|
|
|
|
{
|
|
|
|
|
*d++ = (UCHAR) isc_dpb_no_reserve;
|
|
|
|
|
*d++ = 1;
|
|
|
|
|
*d++ = TRUE;
|
|
|
|
|
}
|
|
|
|
|
if (tdgbl->gbl_sw_user)
|
|
|
|
|
{
|
|
|
|
|
*d++ = (UCHAR) isc_dpb_user_name;
|
|
|
|
|
*d++ = (UCHAR) strlen (tdgbl->gbl_sw_user);
|
|
|
|
|
for (q = (UCHAR*) tdgbl->gbl_sw_user; *q;)
|
|
|
|
|
*d++ = *q++;
|
|
|
|
|
}
|
|
|
|
|
if (tdgbl->gbl_sw_password)
|
|
|
|
|
{
|
|
|
|
|
if (!tdgbl->gbl_sw_service_thd)
|
|
|
|
|
*d++ = (UCHAR) isc_dpb_password;
|
|
|
|
|
else
|
|
|
|
|
*d++ = (UCHAR) isc_dpb_password_enc;
|
|
|
|
|
*d++ = (UCHAR) strlen (tdgbl->gbl_sw_password);
|
|
|
|
|
for (q = (UCHAR*) tdgbl->gbl_sw_password; *q;)
|
|
|
|
|
*d++ = *q++;
|
|
|
|
|
}
|
|
|
|
|
if (page_buffers)
|
|
|
|
|
{
|
|
|
|
|
*d++ = (UCHAR) isc_dpb_set_page_buffers;
|
|
|
|
|
*d++ = 4;
|
|
|
|
|
*d++ = (UCHAR) page_buffers;
|
|
|
|
|
*d++ = (UCHAR) (page_buffers >> 8);
|
|
|
|
|
*d++ = (UCHAR) (page_buffers >> 16);
|
|
|
|
|
*d++ = (UCHAR) (page_buffers >> 24);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Turn off sync writes during restore */
|
|
|
|
|
*d++ = (UCHAR) isc_dpb_force_write;
|
|
|
|
|
*d++ = 1;
|
|
|
|
|
*d++ = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
**
|
|
|
|
|
** which SQL dialect that this database speaks
|
|
|
|
|
** When we restore backup files that came from prior
|
|
|
|
|
** to V6, we force the SQL database dialect to 1
|
|
|
|
|
**
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
*d++ = (UCHAR) isc_dpb_sql_dialect;
|
|
|
|
|
*d++ = 1;
|
|
|
|
|
if (SQL_dialect_flag == TRUE)
|
|
|
|
|
*d++ = (UCHAR) SQL_dialect;
|
|
|
|
|
else
|
|
|
|
|
*d++ = (UCHAR) SQL_DIALECT_V5;
|
|
|
|
|
|
|
|
|
|
/* start database up shut down */
|
|
|
|
|
*d++ = (UCHAR) isc_dpb_shutdown;
|
|
|
|
|
*d++ = 1;
|
|
|
|
|
*d++ = (UCHAR) isc_dpb_shut_attachment;
|
|
|
|
|
*d++ = (UCHAR) isc_dpb_shutdown_delay;
|
|
|
|
|
*d++ = 2;
|
|
|
|
|
*d++ = 0;
|
|
|
|
|
*d++ = 0;
|
|
|
|
|
|
|
|
|
|
l = d - dpb;
|
|
|
|
|
|
|
|
|
|
if (isc_create_database (status_vector,
|
|
|
|
|
0,
|
|
|
|
|
(SCHAR*) GDS_VAL (file_name),
|
|
|
|
|
GDS_REF (tdgbl->db_handle),
|
|
|
|
|
l, (SCHAR*) dpb, 0))
|
|
|
|
|
{
|
|
|
|
|
BURP_error_redirect (status_vector, 33, file_name, 0);
|
|
|
|
|
/* msg 33 failed to create database %s */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_version)
|
|
|
|
|
{
|
|
|
|
|
BURP_print (139, file_name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 139 Version(s) for database "%s" */
|
|
|
|
|
isc_version (&tdgbl->db_handle, (void (*)()) BURP_output_version, (void*) "\t%s\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BURP_verbose (74, file_name, (void*) page_size, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 74 created database %s, page_size %ld bytes */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void decompress (
|
|
|
|
|
UCHAR *buffer,
|
|
|
|
|
USHORT length)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* d e c o m p r e s s
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Get a number of compressed bytes.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
UCHAR c, *p, *end;
|
|
|
|
|
SSHORT count;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
p = buffer;
|
|
|
|
|
end = p + length;
|
|
|
|
|
|
|
|
|
|
while (p < end)
|
|
|
|
|
{
|
|
|
|
|
/* This change was made to restore National Semi-Conductor's corrupted */
|
|
|
|
|
/* gbak file and it is in the code base now. -Andrew */
|
|
|
|
|
|
|
|
|
|
count = (SCHAR) GET();
|
|
|
|
|
if (count > 0)
|
|
|
|
|
{
|
|
|
|
|
if (end - p < count)
|
|
|
|
|
{
|
|
|
|
|
BURP_print (202, (void*) count, (void*) (end - p), NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 202: adjusting a decompression length error: invalid length %d was adjusted to %d */
|
|
|
|
|
count = end - p;
|
|
|
|
|
}
|
|
|
|
|
p = GET_BLOCK (p, count);
|
|
|
|
|
}
|
|
|
|
|
else if (count < 0)
|
|
|
|
|
{
|
|
|
|
|
if (end + count < p)
|
|
|
|
|
{
|
|
|
|
|
BURP_print(202, (void*) count, (void*) (p - end), NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 202: adjusting a decompression length error: invalid length %d was adjusted to %d */
|
|
|
|
|
count = p - end;
|
|
|
|
|
}
|
|
|
|
|
c = GET();
|
|
|
|
|
memset (p, c, -count);
|
|
|
|
|
p += -count;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (p > end)
|
|
|
|
|
BURP_error_redirect ((STATUS*) NULL_PTR, 34, 0, 0);
|
|
|
|
|
/* msg 34 RESTORE: decompression length error */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void eat_blob (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* e a t _ b l o b
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Discard a blob from backup file
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
SLONG length;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
length = get_numeric();
|
|
|
|
|
|
|
|
|
|
GET_SKIP (length);
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-17 01:04:19 +01:00
|
|
|
|
static BURP_REL find_relation (
|
2001-07-12 08:32:05 +02:00
|
|
|
|
TEXT *name)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* f i n d _ r e l a t i o n
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Given a relation name, find the relation block. If there isn't
|
|
|
|
|
* one, produce a fatal error.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
TEXT *p, *q;
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_REL relation;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
for (relation = tdgbl->relations; relation; relation = relation->rel_next)
|
|
|
|
|
for (p = relation->rel_name, q = name; *p == *q; p++, q++)
|
|
|
|
|
if (!*p)
|
|
|
|
|
return relation;
|
|
|
|
|
|
|
|
|
|
BURP_error_redirect ((STATUS *) NULL_PTR, 35, name, 0);
|
|
|
|
|
/* msg 35 can't find relation %s */
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void general_on_error (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e n e r a l _ o n _ e r r o r
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Handle any general ON_ERROR clause during restore.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
BURP_print_status (tdgbl->status);
|
|
|
|
|
BURP_abort ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int get_acl (
|
|
|
|
|
TEXT *owner_nm,
|
|
|
|
|
ISC_QUAD *blob_id,
|
|
|
|
|
ISC_QUAD *new_blob_id)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ a c l
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
*
|
|
|
|
|
* open the blob that contains the ACL list
|
|
|
|
|
* get the ACL list of a relation
|
|
|
|
|
* replace the owner of the relation in the ACL list with
|
|
|
|
|
* the creator of the relation
|
|
|
|
|
* create a new blob
|
|
|
|
|
* store the new ACL list in the new blob
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
|
|
static CONST SCHAR blr_items [] = {isc_info_blob_max_segment,
|
|
|
|
|
isc_info_blob_total_length,
|
|
|
|
|
isc_info_blob_num_segments};
|
2002-10-24 11:01:44 +02:00
|
|
|
|
STATUS status_vector[ISC_STATUS_LENGTH];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
SLONG length, n;
|
|
|
|
|
SLONG *blob;
|
|
|
|
|
UCHAR *p, blob_info [32], item, *buffer, static_buffer [1024],
|
|
|
|
|
*new_buffer, *end_buffer;
|
|
|
|
|
USHORT l, max_segment, num_segments, new_len = 0;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
UCHAR *c_1, *from, *to, owner_nm_len;
|
|
|
|
|
SLONG id_person_len, cnt;
|
|
|
|
|
isc_blob_handle blob_handle = NULL;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
new_buffer = (UCHAR*) NULL_PTR;
|
|
|
|
|
|
|
|
|
|
/* If the blob is null, don't store it. It will be restored as null. */
|
|
|
|
|
|
|
|
|
|
if (!blob_id->gds_quad_high && !blob_id->gds_quad_low)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Open the blob and get it's vital statistics */
|
|
|
|
|
|
|
|
|
|
blob = NULL;
|
|
|
|
|
|
|
|
|
|
if (isc_open_blob (status_vector, GDS_REF (tdgbl->db_handle),
|
|
|
|
|
GDS_REF (gds_trans), (void**) GDS_REF (blob),
|
|
|
|
|
GDS_VAL (blob_id)))
|
|
|
|
|
/* msg 24 gds__open_blob failed */
|
|
|
|
|
BURP_error_redirect (status_vector, 24, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
if (isc_blob_info (status_vector, (void**) GDS_REF (blob), sizeof (blr_items),
|
|
|
|
|
(SCHAR *) blr_items, sizeof (blob_info), (SCHAR*) blob_info))
|
|
|
|
|
/* msg 20 gds__blob_info failed */
|
|
|
|
|
BURP_error_redirect (status_vector, 20, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
length = 0;
|
|
|
|
|
p = blob_info;
|
|
|
|
|
|
|
|
|
|
while ((item = *p++) != gds_info_end)
|
|
|
|
|
{
|
|
|
|
|
l = (USHORT) gds__vax_integer (p, 2);
|
|
|
|
|
p += 2;
|
|
|
|
|
n = gds__vax_integer (p, l);
|
|
|
|
|
p += l;
|
|
|
|
|
switch (item)
|
|
|
|
|
{
|
|
|
|
|
case isc_info_blob_max_segment:
|
|
|
|
|
max_segment = (USHORT) n;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case isc_info_blob_total_length:
|
|
|
|
|
length = n;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case isc_info_blob_num_segments:
|
|
|
|
|
num_segments = (USHORT) n;
|
|
|
|
|
/*
|
|
|
|
|
** we assume that the ACL list was written out as
|
|
|
|
|
** in one big segment
|
|
|
|
|
**
|
|
|
|
|
*/
|
2001-12-24 03:51:06 +01:00
|
|
|
|
if (num_segments > 1) {
|
2001-07-12 08:32:05 +02:00
|
|
|
|
assert (num_segments > 1);
|
2001-12-24 03:51:06 +01:00
|
|
|
|
}
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* msg 79 don't understand blob info item %ld */
|
|
|
|
|
BURP_print (79, (void*) item, NULL, NULL, NULL, NULL);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!length)
|
|
|
|
|
{
|
|
|
|
|
if (isc_close_blob (status_vector, (void**) GDS_REF (blob)))
|
|
|
|
|
/* msg 23 gds__close_blob failed */
|
|
|
|
|
BURP_error_redirect (status_vector, 23, NULL, NULL);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Rdb sometimes gets the length messed up */
|
|
|
|
|
|
|
|
|
|
if (length < max_segment)
|
|
|
|
|
length = max_segment;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** Allocate a buffer large enough for the largest segment and start
|
|
|
|
|
** grinding.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (!max_segment || max_segment <= sizeof (static_buffer))
|
|
|
|
|
buffer = static_buffer;
|
|
|
|
|
else
|
|
|
|
|
buffer = BURP_ALLOC (max_segment);
|
|
|
|
|
|
|
|
|
|
isc_get_segment (status_vector,
|
|
|
|
|
(void**) GDS_REF (blob),
|
|
|
|
|
GDS_REF (l),
|
|
|
|
|
max_segment,
|
|
|
|
|
(SCHAR*) GDS_VAL (buffer));
|
|
|
|
|
|
|
|
|
|
if (isc_close_blob (status_vector, (void**) GDS_REF (blob)))
|
|
|
|
|
{
|
|
|
|
|
if (buffer != static_buffer)
|
|
|
|
|
BURP_FREE (buffer);
|
|
|
|
|
/* msg 23 gds__close_blob failed */
|
|
|
|
|
BURP_error_redirect (status_vector, 23, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
from = buffer + 3; /* skip ACL_version, ACL_id_list, and id_person */
|
|
|
|
|
id_person_len = (int)*from;
|
|
|
|
|
|
|
|
|
|
c_1 = (UCHAR*) owner_nm;
|
|
|
|
|
owner_nm_len = strlen (owner_nm);
|
|
|
|
|
|
|
|
|
|
new_buffer = BURP_ALLOC (length - id_person_len + owner_nm_len);
|
|
|
|
|
|
|
|
|
|
from = buffer;
|
|
|
|
|
to = new_buffer;
|
|
|
|
|
*to++ = *from++; /* copy ACL_verion */
|
|
|
|
|
*to++ = *from++; /* copy ACL_id_list */
|
|
|
|
|
*to++ = *from++; /* copy id_person */
|
|
|
|
|
*to++ = owner_nm_len;
|
|
|
|
|
new_len = new_len + 4;
|
|
|
|
|
from = buffer + id_person_len + 4;
|
|
|
|
|
for (cnt = 0; cnt < owner_nm_len; cnt++)
|
|
|
|
|
{
|
|
|
|
|
*to++ = *c_1++;
|
|
|
|
|
new_len++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end_buffer = buffer + length;
|
|
|
|
|
for (from = buffer + id_person_len + 4; from < end_buffer; from++)
|
|
|
|
|
{
|
|
|
|
|
*to++ = *from;
|
|
|
|
|
new_len++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isc_create_blob2 (status_vector,
|
|
|
|
|
GDS_REF (tdgbl->db_handle),
|
|
|
|
|
GDS_REF (gds_trans),
|
|
|
|
|
GDS_REF (blob_handle),
|
|
|
|
|
GDS_VAL (new_blob_id),
|
|
|
|
|
0,
|
|
|
|
|
NULL))
|
|
|
|
|
{
|
|
|
|
|
if (buffer != static_buffer)
|
|
|
|
|
BURP_FREE (buffer);
|
|
|
|
|
if (new_buffer != NULL_PTR)
|
|
|
|
|
BURP_FREE (new_buffer);
|
|
|
|
|
/* msg 37 gds__create_blob failed */
|
|
|
|
|
BURP_error_redirect (status_vector, 37, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isc_put_segment (status_vector,
|
|
|
|
|
GDS_REF (blob_handle),
|
|
|
|
|
new_len,
|
|
|
|
|
(SCHAR*) GDS_VAL (new_buffer)))
|
|
|
|
|
{
|
|
|
|
|
if (buffer != static_buffer)
|
|
|
|
|
BURP_FREE (buffer);
|
|
|
|
|
if (new_buffer != NULL_PTR)
|
|
|
|
|
BURP_FREE (new_buffer);
|
|
|
|
|
/* msg 38 gds__put_segment failed */
|
|
|
|
|
BURP_error_redirect (status_vector, 38, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isc_close_blob (status_vector, GDS_REF (blob_handle)))
|
|
|
|
|
{
|
|
|
|
|
if (buffer != static_buffer)
|
|
|
|
|
BURP_FREE (buffer);
|
|
|
|
|
if (new_buffer != NULL_PTR)
|
|
|
|
|
BURP_FREE (new_buffer);
|
|
|
|
|
/* msg 23 gds__close_blob failed */
|
|
|
|
|
BURP_error_redirect (status_vector, 23, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (buffer != static_buffer)
|
|
|
|
|
BURP_FREE (buffer);
|
|
|
|
|
|
|
|
|
|
if (new_buffer != NULL_PTR)
|
|
|
|
|
BURP_FREE (new_buffer);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void get_array (
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_REL relation,
|
2001-07-12 08:32:05 +02:00
|
|
|
|
UCHAR *record_buffer)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ a r r a y
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Read array data from input file to nice,
|
|
|
|
|
* shiney, new array.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
FLD field;
|
|
|
|
|
ATT_TYPE attribute;
|
2002-10-24 11:01:44 +02:00
|
|
|
|
STATUS status_vector[ISC_STATUS_LENGTH];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
SLONG last_element_dim[MAX_DIMENSION];
|
|
|
|
|
SLONG fld_ranges[2*MAX_DIMENSION];
|
|
|
|
|
SLONG *blob_id, return_length, slice_length, *range, *end_ranges,
|
|
|
|
|
lcount;
|
|
|
|
|
USHORT blr_length, count, field_number, field_length;
|
|
|
|
|
UCHAR *buffer, *p;
|
|
|
|
|
SCHAR *blr, blr_buffer [200]; /* enough for a sdl with 16 dimensions */
|
|
|
|
|
LSTRING xdr_buffer, xdr_slice;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
/* don't free something you don't allocate */
|
|
|
|
|
|
|
|
|
|
xdr_buffer.lstr_allocated = 0;
|
|
|
|
|
|
|
|
|
|
/* Pick up attributes */
|
|
|
|
|
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_blob_data)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_blob_field_number:
|
|
|
|
|
field_number = (USHORT)get_numeric();
|
|
|
|
|
for (field = relation->rel_fields; field; field = field->fld_next)
|
|
|
|
|
if (field->fld_number == field_number)
|
|
|
|
|
break;
|
|
|
|
|
if (!field)
|
|
|
|
|
BURP_error_redirect ((STATUS *) NULL_PTR, 36, 0, 0);
|
|
|
|
|
/* msg 36 Can't find field for blob */
|
|
|
|
|
|
|
|
|
|
field_length = field->fld_length;
|
|
|
|
|
if (field->fld_type == blr_varying)
|
|
|
|
|
field_length += sizeof (USHORT);
|
|
|
|
|
slice_length = field_length;
|
|
|
|
|
/**
|
|
|
|
|
Copy the ranges onto a buffer and let the program
|
|
|
|
|
mess with the copy rather than the original
|
|
|
|
|
**/
|
|
|
|
|
memcpy(fld_ranges,field->fld_ranges, sizeof(fld_ranges));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_array_dimensions:
|
|
|
|
|
field->fld_dimensions = (SSHORT)get_numeric();
|
|
|
|
|
end_ranges = fld_ranges + 2 * field->fld_dimensions;
|
|
|
|
|
for (range = fld_ranges; range < end_ranges; range += 2)
|
|
|
|
|
{
|
|
|
|
|
if (GET_ATTRIBUTE (attribute) != att_array_range_low)
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 58);
|
|
|
|
|
/* msg 58 array */
|
|
|
|
|
else
|
|
|
|
|
range [0] = get_numeric();
|
|
|
|
|
if (GET_ATTRIBUTE (attribute) != att_array_range_high)
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 58);
|
|
|
|
|
/* msg 58 array */
|
|
|
|
|
else
|
|
|
|
|
range [1] = get_numeric();
|
|
|
|
|
slice_length *= (range [1] - range [0] + 1);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 58);
|
|
|
|
|
/* msg 58 array */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return_length = GET();
|
|
|
|
|
return_length |= GET() << 8;
|
|
|
|
|
return_length |= GET() << 16;
|
|
|
|
|
return_length |= GET() << 24;
|
|
|
|
|
|
|
|
|
|
blob_id = (SLONG*) ((UCHAR*) record_buffer + field->fld_offset);
|
|
|
|
|
|
|
|
|
|
if (return_length != slice_length)
|
|
|
|
|
{
|
|
|
|
|
int current_dim,divisor, elements_remaining;
|
|
|
|
|
int data_at, elements_written, upper, lower,dont_write;
|
|
|
|
|
int i1, i2, i3;
|
|
|
|
|
/* Ugh! The full array wasn't returned and versions of gbak prior to
|
|
|
|
|
V3.2I don't explicitly signal this. We must recompute the top
|
|
|
|
|
element to restore.
|
|
|
|
|
|
|
|
|
|
Double Ugh! gbak (Versions prior to 5.0) while backing up calculates
|
|
|
|
|
the top dimensions incorrectly So whatever was written as top dimensions
|
|
|
|
|
is useless. 5.0 gbak has written correct dimensions, but what the heck
|
|
|
|
|
we'll calculate it again
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
elements_remaining = return_length/field_length;
|
|
|
|
|
/**
|
|
|
|
|
Backup (versions prior to 5.0) has surely written wrong dimensions.
|
|
|
|
|
Ignore whatever is read in fld_ranges and calculate the dimensions
|
|
|
|
|
of the last element. field->fld_ranges has the max dimensions.
|
|
|
|
|
last_element_dim holds only the upper bounds of each dimension.
|
|
|
|
|
**/
|
|
|
|
|
for (i1=0,i3=0; i1<field->fld_dimensions; i1++)
|
|
|
|
|
{
|
|
|
|
|
divisor=1;
|
|
|
|
|
for (i2=(2*(i1+1)+1); i2<=field->fld_dimensions*2; i2+=2)
|
|
|
|
|
divisor *= (field->fld_ranges[i2]-field->fld_ranges[i2-1]+1);
|
|
|
|
|
last_element_dim[i1] =
|
|
|
|
|
(elements_remaining-1)/divisor +field->fld_ranges[i3];
|
|
|
|
|
elements_remaining -=
|
|
|
|
|
(last_element_dim[i1]-field->fld_ranges[i3])*divisor;
|
|
|
|
|
i3+=2;
|
|
|
|
|
}
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
ib_fprintf(ib_stderr, "\nLast element upper bounds read from backup file:\n");
|
|
|
|
|
for(current_dim=1;current_dim<field->fld_dimensions*2;current_dim+=2) ib_fprintf(ib_stderr,"%d ",fld_ranges[current_dim]);
|
|
|
|
|
ib_fprintf(ib_stderr, "\nCalculated Last element upper bounds :\n");
|
|
|
|
|
for(current_dim=0;current_dim<field->fld_dimensions;current_dim++) ib_fprintf(ib_stderr,"%d ",last_element_dim[current_dim]);
|
|
|
|
|
ib_fprintf(ib_stderr,"return_length = %d\n", return_length);
|
|
|
|
|
ib_fprintf(ib_stderr,"elements_returned = %d\n", return_length/field_length);
|
|
|
|
|
ib_fprintf(ib_stderr,"Max dims[");
|
|
|
|
|
for(current_dim=1;current_dim<field->fld_dimensions*2;current_dim+=2) ib_fprintf(ib_stderr,"%d ",field->fld_ranges[current_dim]);
|
|
|
|
|
ib_fprintf(ib_stderr,"]");
|
|
|
|
|
#endif
|
|
|
|
|
data_at = 0;
|
|
|
|
|
/**
|
|
|
|
|
We have an irregurlar shaped slice to write. The following for loop
|
|
|
|
|
chops the array into writable rectangular/square slice and sends it
|
|
|
|
|
to the engine. When the loop cycles through all dimensions, we would
|
|
|
|
|
have written the whole of the irregular slice.
|
|
|
|
|
**/
|
|
|
|
|
for (current_dim=0; current_dim<field->fld_dimensions; current_dim++)
|
|
|
|
|
{
|
|
|
|
|
blr = blr_buffer;
|
|
|
|
|
dont_write = 0;
|
|
|
|
|
|
|
|
|
|
/* build the sdl */
|
|
|
|
|
|
|
|
|
|
STUFF (gds_sdl_version1);
|
|
|
|
|
|
|
|
|
|
STUFF (gds_sdl_struct);
|
|
|
|
|
STUFF (1);
|
|
|
|
|
|
|
|
|
|
if (field->fld_type == blr_text ||
|
|
|
|
|
field->fld_type == blr_varying)
|
|
|
|
|
{
|
|
|
|
|
if (field->fld_type == blr_text)
|
|
|
|
|
STUFF (blr_text2)
|
|
|
|
|
else
|
|
|
|
|
STUFF (blr_varying2);
|
|
|
|
|
STUFF_WORD (field->fld_character_set_id);
|
|
|
|
|
STUFF_WORD (field->fld_length);
|
|
|
|
|
}
|
|
|
|
|
else if (field->fld_type == blr_short ||
|
|
|
|
|
field->fld_type == blr_long ||
|
2002-06-27 12:14:54 +02:00
|
|
|
|
field->fld_type == blr_quad ||
|
|
|
|
|
field->fld_type == blr_int64)
|
2001-07-12 08:32:05 +02:00
|
|
|
|
{
|
|
|
|
|
STUFF (field->fld_type);
|
|
|
|
|
STUFF (field->fld_scale);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
STUFF (field->fld_type);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
STUFF (gds_sdl_relation);
|
|
|
|
|
stuff_string (&blr, relation->rel_name);
|
|
|
|
|
STUFF (gds_sdl_field);
|
|
|
|
|
stuff_string (&blr, field->fld_name);
|
|
|
|
|
|
|
|
|
|
/* each element spec starts here */
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
ib_fprintf(ib_stderr,"\nBounds written [");
|
|
|
|
|
#endif
|
|
|
|
|
elements_written=1;
|
|
|
|
|
end_ranges = field->fld_ranges + 2 * field->fld_dimensions;
|
|
|
|
|
/**
|
|
|
|
|
Here is the important work. Calculate the the bounds to be written
|
|
|
|
|
so that the resulting slice is a rectangular/square slice.
|
|
|
|
|
For a 2 dimensional array of size 1..N, 1..M, which is partially
|
|
|
|
|
filled, we have already calculated the dims of last element. Say
|
|
|
|
|
if this was x,y (x is row, y is column) then we do
|
|
|
|
|
isc_put_slice(1..x-1, 1..M);
|
|
|
|
|
isc_put_slice(x..x, 1..y);
|
|
|
|
|
similarly for a 3D array [N,M,K] whose last element dims are (x,y,z)
|
|
|
|
|
isc_put_slice(1..x-1, 1..M, 1..K);
|
|
|
|
|
isc_put_slice(x..x, 1..y-1, 1..K);
|
|
|
|
|
isc_put_slice(x..x, y..y, 1..z);
|
|
|
|
|
This is applicable for any number of dimensions.
|
|
|
|
|
Special cases:
|
|
|
|
|
for example in case of a 2D array (10,10) and if the last element
|
|
|
|
|
dims were (1,2), we would just do a isc_put_slice(1..1, 1..2).
|
|
|
|
|
This is applied for any number of dimensions.
|
|
|
|
|
**/
|
|
|
|
|
for (range = field->fld_ranges, count = 0; range < end_ranges; range += 2, count++)
|
|
|
|
|
{
|
|
|
|
|
STUFF (gds_sdl_do2); STUFF (count);
|
|
|
|
|
/**
|
|
|
|
|
Normally we loop through all dimensions chopping off slices
|
|
|
|
|
and writing them. This works fine but this also means that
|
|
|
|
|
we blindly put slices without actually figuring out if we
|
|
|
|
|
really need to do so. For eg: if we have a 2D array of
|
|
|
|
|
size [10,4] and the last element dims are [6,4] then all
|
|
|
|
|
we need to do is is to put one slice as
|
|
|
|
|
isc_put_slice(1..6,1..4)
|
|
|
|
|
rather than looping through the dimensions and putting
|
|
|
|
|
isc_put_slice(1..5,1..4)
|
|
|
|
|
isc_put_slice(6..6,1..4)
|
|
|
|
|
we could extend this logic to any no of dims. The following
|
|
|
|
|
if condition figures out such cases. This combined with
|
|
|
|
|
the Special case should optimize the no of isc_put_slice
|
|
|
|
|
we perform.
|
|
|
|
|
**/
|
|
|
|
|
if( current_dim+1 == field->fld_dimensions-1 &&
|
|
|
|
|
field->fld_dimensions-count == 2 &&
|
|
|
|
|
last_element_dim[count+1] == range [3] )
|
|
|
|
|
{
|
|
|
|
|
STUFF (gds_sdl_long_integer); STUFF_LONG (range [0]);
|
|
|
|
|
lower = range [0];
|
|
|
|
|
STUFF (gds_sdl_long_integer);
|
|
|
|
|
STUFF_LONG (last_element_dim [count]);
|
|
|
|
|
upper=last_element_dim [count];
|
|
|
|
|
elements_written *= (upper-lower+1);
|
|
|
|
|
range+=2;
|
|
|
|
|
count++;
|
|
|
|
|
STUFF (gds_sdl_do2); STUFF (count);
|
|
|
|
|
STUFF (gds_sdl_long_integer); STUFF_LONG (range [0]);
|
|
|
|
|
lower = range [0];
|
|
|
|
|
STUFF (gds_sdl_long_integer);
|
|
|
|
|
STUFF_LONG (last_element_dim [count]);
|
|
|
|
|
upper=last_element_dim [count];
|
|
|
|
|
elements_written *= (upper-lower+1);
|
|
|
|
|
++current_dim;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if( current_dim==count)
|
|
|
|
|
{
|
|
|
|
|
STUFF (gds_sdl_long_integer); STUFF_LONG (range [0]);
|
|
|
|
|
lower = range [0];
|
|
|
|
|
STUFF (gds_sdl_long_integer);
|
|
|
|
|
upper = (current_dim==field->fld_dimensions-1)?
|
|
|
|
|
last_element_dim [count] : (last_element_dim [count]-1);
|
|
|
|
|
if( upper < range[0] )
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
see Special Case above
|
|
|
|
|
**/
|
|
|
|
|
dont_write = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
STUFF_LONG (upper);
|
|
|
|
|
}
|
|
|
|
|
else if (current_dim<count)
|
|
|
|
|
{
|
|
|
|
|
STUFF (gds_sdl_long_integer); STUFF_LONG (range [0]);
|
|
|
|
|
STUFF (gds_sdl_long_integer); STUFF_LONG (range [1]);
|
|
|
|
|
upper = range[1]; lower = range[0];
|
|
|
|
|
}
|
|
|
|
|
else if (current_dim>count)
|
|
|
|
|
{
|
|
|
|
|
STUFF (gds_sdl_long_integer);
|
|
|
|
|
STUFF_LONG (last_element_dim [count]);
|
|
|
|
|
STUFF (gds_sdl_long_integer);
|
|
|
|
|
STUFF_LONG (last_element_dim [count]);
|
|
|
|
|
upper=lower=last_element_dim [count];
|
|
|
|
|
}
|
|
|
|
|
elements_written *= (upper-lower+1);
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
ib_fprintf(ib_stderr,"%d..%d ",lower,upper);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
if( dont_write ) continue;
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
ib_fprintf(ib_stderr,"]");
|
|
|
|
|
ib_fprintf(ib_stderr,"\n Elements Written=%d ",elements_written);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
STUFF (gds_sdl_element); STUFF (1);
|
|
|
|
|
STUFF (gds_sdl_scalar); STUFF (0); STUFF (field->fld_dimensions);
|
|
|
|
|
|
|
|
|
|
for (count = 0; count < field->fld_dimensions; count++)
|
|
|
|
|
{
|
|
|
|
|
STUFF (gds_sdl_variable);
|
|
|
|
|
STUFF (count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STUFF (gds_sdl_eoc);
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
if (debug_on)
|
|
|
|
|
PRETTY_print_sdl (blr_buffer, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
blr_length = blr - blr_buffer;
|
|
|
|
|
|
|
|
|
|
if(data_at==0)
|
|
|
|
|
{
|
|
|
|
|
buffer = BURP_ALLOC (return_length);
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_transportable)
|
|
|
|
|
{
|
|
|
|
|
if (GET_ATTRIBUTE (attribute) != att_xdr_array)
|
|
|
|
|
/* msg 55 Expected XDR record length */
|
|
|
|
|
BURP_error_redirect ((STATUS *) NULL_PTR, 55, 0, 0);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
xdr_buffer.lstr_allocated = GET();
|
|
|
|
|
xdr_buffer.lstr_allocated |= GET() << 8;
|
|
|
|
|
xdr_buffer.lstr_allocated |= GET() << 16;
|
|
|
|
|
xdr_buffer.lstr_allocated |= GET() << 24;
|
|
|
|
|
lcount = xdr_buffer.lstr_length = xdr_buffer.lstr_allocated;
|
|
|
|
|
xdr_buffer.lstr_address = BURP_ALLOC (xdr_buffer.lstr_allocated);
|
|
|
|
|
xdr_slice.lstr_allocated = xdr_slice.lstr_length = return_length;
|
|
|
|
|
xdr_slice.lstr_address = buffer;
|
|
|
|
|
p = xdr_buffer.lstr_address;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
p = buffer;
|
|
|
|
|
lcount = return_length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lcount)
|
|
|
|
|
(void) GET_BLOCK (p, lcount);
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_transportable)
|
|
|
|
|
CAN_slice (&xdr_buffer, &xdr_slice, FALSE, blr_length, (UCHAR*) blr_buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isc_put_slice (status_vector,
|
|
|
|
|
GDS_REF (tdgbl->db_handle),
|
|
|
|
|
GDS_REF (gds_trans),
|
|
|
|
|
(ISC_QUAD*)GDS_VAL (blob_id),
|
|
|
|
|
blr_length,
|
|
|
|
|
blr_buffer,
|
|
|
|
|
0, /* param length for subset of an array handling */
|
|
|
|
|
(ISC_LONG*) 0, /* param for subset of an array handling */
|
|
|
|
|
elements_written*field->fld_length,
|
|
|
|
|
GDS_VAL (buffer+data_at)))
|
|
|
|
|
{
|
|
|
|
|
BURP_print (81, field->fld_name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 81 error accessing blob field %s -- continuing */
|
|
|
|
|
BURP_print_status (status_vector);
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
PRETTY_print_sdl (blr_buffer, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
#endif
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
data_at += elements_written*field->fld_length;
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
ib_fprintf(ib_stderr,"next data_at = %d\n", data_at);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ /** This is the regular case we've got the entire array **/
|
|
|
|
|
blr = blr_buffer;
|
|
|
|
|
|
|
|
|
|
/* build the sdl */
|
|
|
|
|
|
|
|
|
|
STUFF (gds_sdl_version1);
|
|
|
|
|
|
|
|
|
|
STUFF (gds_sdl_struct);
|
|
|
|
|
STUFF (1);
|
|
|
|
|
|
|
|
|
|
if (field->fld_type == blr_text ||
|
|
|
|
|
field->fld_type == blr_varying)
|
|
|
|
|
{
|
|
|
|
|
if (field->fld_type == blr_text)
|
|
|
|
|
STUFF (blr_text2)
|
|
|
|
|
else
|
|
|
|
|
STUFF (blr_varying2);
|
|
|
|
|
STUFF_WORD (field->fld_character_set_id);
|
|
|
|
|
STUFF_WORD (field->fld_length);
|
|
|
|
|
}
|
|
|
|
|
else if (field->fld_type == blr_short ||
|
|
|
|
|
field->fld_type == blr_long ||
|
2002-06-27 12:14:54 +02:00
|
|
|
|
field->fld_type == blr_quad ||
|
|
|
|
|
field->fld_type == blr_int64)
|
2001-07-12 08:32:05 +02:00
|
|
|
|
{
|
|
|
|
|
STUFF (field->fld_type);
|
|
|
|
|
STUFF (field->fld_scale);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
STUFF (field->fld_type);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
STUFF (gds_sdl_relation);
|
|
|
|
|
stuff_string (&blr, relation->rel_name);
|
|
|
|
|
STUFF (gds_sdl_field);
|
|
|
|
|
stuff_string (&blr, field->fld_name);
|
|
|
|
|
|
|
|
|
|
/* each element spec starts here */
|
|
|
|
|
|
|
|
|
|
for (range = fld_ranges, count = 0; range < end_ranges; range += 2, count++)
|
|
|
|
|
{
|
|
|
|
|
STUFF (gds_sdl_do2); STUFF (count);
|
|
|
|
|
STUFF (gds_sdl_long_integer); STUFF_LONG (range [0]);
|
|
|
|
|
STUFF (gds_sdl_long_integer); STUFF_LONG (range [1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STUFF (gds_sdl_element); STUFF (1);
|
|
|
|
|
STUFF (gds_sdl_scalar); STUFF (0); STUFF (field->fld_dimensions);
|
|
|
|
|
|
|
|
|
|
for (count = 0; count < field->fld_dimensions; count++)
|
|
|
|
|
{
|
|
|
|
|
STUFF (gds_sdl_variable);
|
|
|
|
|
STUFF (count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STUFF (gds_sdl_eoc);
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
if (debug_on)
|
|
|
|
|
PRETTY_print_sdl (blr_buffer, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
blr_length = blr - blr_buffer;
|
|
|
|
|
|
|
|
|
|
buffer = BURP_ALLOC (return_length);
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_transportable)
|
|
|
|
|
{
|
|
|
|
|
if (GET_ATTRIBUTE (attribute) != att_xdr_array)
|
|
|
|
|
BURP_error_redirect ((STATUS *) NULL_PTR, 55, 0, 0);
|
|
|
|
|
/* msg 55 Expected XDR record length */
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
xdr_buffer.lstr_allocated = GET();
|
|
|
|
|
xdr_buffer.lstr_allocated |= GET() << 8;
|
|
|
|
|
xdr_buffer.lstr_allocated |= GET() << 16;
|
|
|
|
|
xdr_buffer.lstr_allocated |= GET() << 24;
|
|
|
|
|
lcount = xdr_buffer.lstr_length = xdr_buffer.lstr_allocated;
|
|
|
|
|
xdr_buffer.lstr_address = BURP_ALLOC (xdr_buffer.lstr_allocated);
|
|
|
|
|
xdr_slice.lstr_allocated = xdr_slice.lstr_length = return_length;
|
|
|
|
|
xdr_slice.lstr_address = buffer;
|
|
|
|
|
p = xdr_buffer.lstr_address;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
p = buffer;
|
|
|
|
|
lcount = return_length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lcount)
|
|
|
|
|
(void) GET_BLOCK (p, lcount);
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_transportable)
|
|
|
|
|
CAN_slice (&xdr_buffer, &xdr_slice, FALSE, blr_length, (UCHAR*) blr_buffer);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (isc_put_slice (status_vector,
|
|
|
|
|
GDS_REF (tdgbl->db_handle),
|
|
|
|
|
GDS_REF (gds_trans),
|
|
|
|
|
(ISC_QUAD*)GDS_VAL (blob_id),
|
|
|
|
|
blr_length,
|
|
|
|
|
blr_buffer,
|
|
|
|
|
0, /* param length for subset of an array handling */
|
|
|
|
|
(ISC_LONG*) 0, /* param for subset of an array handling */
|
|
|
|
|
return_length,
|
|
|
|
|
GDS_VAL (buffer)))
|
|
|
|
|
{
|
|
|
|
|
BURP_print (81, field->fld_name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 81 error accessing blob field %s -- continuing */
|
|
|
|
|
BURP_print_status (status_vector);
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
PRETTY_print_sdl (blr_buffer, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
#endif
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BURP_FREE (buffer);
|
|
|
|
|
if (tdgbl->gbl_sw_transportable && xdr_buffer.lstr_allocated)
|
|
|
|
|
BURP_FREE (xdr_buffer.lstr_address);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void get_blob (
|
|
|
|
|
FLD fields,
|
|
|
|
|
UCHAR *record_buffer)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ b l o b
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Read blob attributes and copy data from input file to nice,
|
|
|
|
|
* shiny, new blob.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
FLD field;
|
|
|
|
|
ATT_TYPE attribute;
|
2002-10-24 11:01:44 +02:00
|
|
|
|
STATUS status_vector[ISC_STATUS_LENGTH];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
ULONG segments;
|
|
|
|
|
ISC_QUAD *blob_id;
|
|
|
|
|
SLONG *blob;
|
|
|
|
|
USHORT field_number, max_segment, length;
|
|
|
|
|
UCHAR *buffer, static_buffer [1024];
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
/* Pick up attributes */
|
|
|
|
|
|
|
|
|
|
segments = 0;
|
|
|
|
|
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_blob_data)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_blob_field_number:
|
|
|
|
|
field_number = (USHORT)get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_blob_max_segment:
|
|
|
|
|
max_segment = (USHORT)get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_blob_number_segments:
|
|
|
|
|
segments = get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_blob_type:
|
|
|
|
|
(void) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 64);
|
|
|
|
|
/* msg 64 blob */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find the field associated with the blob */
|
|
|
|
|
|
|
|
|
|
for (field = fields; field; field = field->fld_next)
|
|
|
|
|
if (field->fld_number == field_number)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (!field)
|
|
|
|
|
BURP_error_redirect ((STATUS *) NULL_PTR, 36, 0, 0);
|
|
|
|
|
/* msg 36 Can't find field for blob */
|
|
|
|
|
|
|
|
|
|
/* Create new blob */
|
|
|
|
|
|
|
|
|
|
blob_id = (ISC_QUAD*) ((UCHAR*) record_buffer + field->fld_offset);
|
|
|
|
|
blob = NULL;
|
|
|
|
|
|
|
|
|
|
if (isc_create_blob (status_vector,
|
|
|
|
|
GDS_REF (tdgbl->db_handle),
|
|
|
|
|
GDS_REF (gds_trans),
|
|
|
|
|
(void**) GDS_REF (blob),
|
|
|
|
|
(ISC_QUAD*)GDS_VAL (blob_id)))
|
|
|
|
|
BURP_error_redirect (status_vector, 37, 0, 0);
|
|
|
|
|
/* msg 37 gds__create_blob failed */
|
|
|
|
|
|
|
|
|
|
/* Allocate blob buffer is static buffer is too short */
|
|
|
|
|
|
|
|
|
|
if (!max_segment || max_segment <= sizeof (static_buffer))
|
|
|
|
|
buffer = static_buffer;
|
|
|
|
|
else
|
|
|
|
|
buffer = BURP_ALLOC (max_segment);
|
|
|
|
|
|
|
|
|
|
/* Eat up blob segments */
|
|
|
|
|
|
|
|
|
|
for (; segments > 0; --segments )
|
|
|
|
|
{
|
|
|
|
|
length = GET();
|
|
|
|
|
length |= GET() << 8;
|
|
|
|
|
if (length)
|
|
|
|
|
{
|
|
|
|
|
(void) GET_BLOCK (buffer, length);
|
|
|
|
|
}
|
|
|
|
|
if (isc_put_segment (status_vector,
|
|
|
|
|
(void**) GDS_REF (blob),
|
|
|
|
|
length,
|
|
|
|
|
(SCHAR*) GDS_VAL (buffer)))
|
|
|
|
|
BURP_error_redirect (status_vector, 38, 0, 0);
|
|
|
|
|
/* msg 38 gds__put_segment failed */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isc_close_blob (status_vector, (void**) GDS_REF (blob)))
|
|
|
|
|
BURP_error_redirect (status_vector, 23, 0, 0);
|
|
|
|
|
/* msg 23 gds__close_blob failed */
|
|
|
|
|
|
|
|
|
|
if (buffer != static_buffer)
|
|
|
|
|
BURP_FREE (buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void get_blr_blob (
|
|
|
|
|
ISC_QUAD *blob_id,
|
|
|
|
|
USHORT glb_trans)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ b l r _ b l o b
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Read blob attributes and copy data from input file to nice,
|
|
|
|
|
* shiney, new blob.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
2002-10-24 11:01:44 +02:00
|
|
|
|
STATUS status_vector[ISC_STATUS_LENGTH];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
SLONG *blob;
|
|
|
|
|
USHORT length, l;
|
|
|
|
|
UCHAR *buffer, static_buffer [1024], *p;
|
|
|
|
|
isc_tr_handle local_trans;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
length = (USHORT)get_numeric();
|
|
|
|
|
|
|
|
|
|
/* Create new blob */
|
|
|
|
|
|
|
|
|
|
blob = NULL;
|
|
|
|
|
|
|
|
|
|
if (glb_trans && tdgbl->global_trans)
|
|
|
|
|
local_trans = tdgbl->global_trans;
|
|
|
|
|
else
|
|
|
|
|
local_trans = gds_trans;
|
|
|
|
|
|
|
|
|
|
if (isc_create_blob (status_vector,
|
|
|
|
|
GDS_REF (tdgbl->db_handle),
|
|
|
|
|
GDS_REF (local_trans),
|
|
|
|
|
(void**) GDS_REF (blob),
|
|
|
|
|
GDS_VAL (blob_id)))
|
|
|
|
|
BURP_error_redirect (status_vector, 37, 0, 0);
|
|
|
|
|
/* msg 37 gds__create_blob failed */
|
|
|
|
|
|
|
|
|
|
/* Allocate blob buffer is static buffer is too short */
|
|
|
|
|
|
2002-04-04 07:32:02 +02:00
|
|
|
|
if (!length || length + 1 <= (USHORT)(sizeof (static_buffer)) )
|
2001-07-12 08:32:05 +02:00
|
|
|
|
buffer = static_buffer;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
l = length + 1;
|
|
|
|
|
buffer = BURP_ALLOC (l);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (l = length)
|
|
|
|
|
{
|
|
|
|
|
p = buffer;
|
|
|
|
|
p = GET_BLOCK (p, l);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make sure it has an eoc */
|
|
|
|
|
if ((*--p) != blr_eoc)
|
|
|
|
|
{
|
|
|
|
|
length++;
|
|
|
|
|
*++p = blr_eoc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isc_put_segment (status_vector,
|
|
|
|
|
(void**) GDS_REF (blob),
|
|
|
|
|
length,
|
|
|
|
|
(SCHAR*) GDS_VAL (buffer)))
|
|
|
|
|
BURP_error_redirect (status_vector, 38, 0, 0);
|
|
|
|
|
/* msg 38 gds__put_segment failed */
|
|
|
|
|
|
|
|
|
|
if (isc_close_blob (status_vector, (void**) GDS_REF (blob)))
|
|
|
|
|
BURP_error_redirect (status_vector, 23, 0, 0);
|
|
|
|
|
/* msg 23 gds__close_blob failed */
|
|
|
|
|
|
|
|
|
|
if (buffer != static_buffer)
|
|
|
|
|
BURP_FREE (buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_character_set (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ c h a r a c t e r _ s e t s
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Restore data for user defined character sets
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_character_sets_req_handle1)
|
|
|
|
|
X IN RDB$CHARACTER_SETS
|
|
|
|
|
X.RDB$CHARACTER_SET_NAME.NULL = TRUE;
|
|
|
|
|
X.RDB$FORM_OF_USE.NULL = TRUE;
|
|
|
|
|
X.RDB$NUMBER_OF_CHARACTERS.NULL = TRUE;
|
|
|
|
|
X.RDB$DEFAULT_COLLATE_NAME.NULL = TRUE;
|
|
|
|
|
X.RDB$CHARACTER_SET_ID.NULL = TRUE;
|
|
|
|
|
X.RDB$SYSTEM_FLAG.NULL = TRUE;
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = TRUE;
|
|
|
|
|
X.RDB$FUNCTION_NAME.NULL = TRUE;
|
|
|
|
|
X.RDB$BYTES_PER_CHARACTER.NULL = TRUE;
|
|
|
|
|
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
case att_charset_name:
|
|
|
|
|
X.RDB$CHARACTER_SET_NAME.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$CHARACTER_SET_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
BURP_verbose (msgVerbose_restore_charset, X.RDB$CHARACTER_SET_NAME, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_charset_form:
|
|
|
|
|
X.RDB$FORM_OF_USE.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$FORM_OF_USE);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_charset_numchar:
|
|
|
|
|
X.RDB$NUMBER_OF_CHARACTERS.NULL = FALSE;
|
|
|
|
|
X.RDB$NUMBER_OF_CHARACTERS = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_charset_coll:
|
|
|
|
|
X.RDB$DEFAULT_COLLATE_NAME.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$DEFAULT_COLLATE_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_charset_id:
|
|
|
|
|
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
|
|
|
|
|
X.RDB$CHARACTER_SET_ID = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_charset_sysflag:
|
|
|
|
|
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
|
|
|
|
X.RDB$SYSTEM_FLAG = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_charset_description:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$DESCRIPTION, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_charset_funct:
|
|
|
|
|
X.RDB$FUNCTION_NAME.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$FUNCTION_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_charset_bytes_char:
|
|
|
|
|
X.RDB$BYTES_PER_CHARACTER.NULL = FALSE;
|
|
|
|
|
X.RDB$BYTES_PER_CHARACTER = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, msgErr_restore_charset);
|
|
|
|
|
/* RDB$CHARSETS */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_chk_constraint (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ c h k _ c o n s t r a i n t
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Restore data for check constraints.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_chk_constraint_req_handle1)
|
|
|
|
|
X IN RDB$CHECK_CONSTRAINTS
|
|
|
|
|
X.RDB$CONSTRAINT_NAME.NULL = TRUE;
|
|
|
|
|
X.RDB$TRIGGER_NAME.NULL = TRUE;
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_chk_constraint_name:
|
|
|
|
|
X.RDB$CONSTRAINT_NAME.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$CONSTRAINT_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_chk_trigger_name:
|
|
|
|
|
X.RDB$TRIGGER_NAME.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$TRIGGER_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 208);
|
|
|
|
|
/* msg 208 relation constraint */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_collation (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ c o l l a t i o n
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Restore data for user defined collations
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_collation_req_handle1)
|
|
|
|
|
X IN RDB$COLLATIONS
|
|
|
|
|
X.RDB$COLLATION_NAME.NULL = TRUE;
|
|
|
|
|
X.RDB$COLLATION_ID.NULL = TRUE;
|
|
|
|
|
X.RDB$CHARACTER_SET_ID.NULL = TRUE;
|
|
|
|
|
X.RDB$COLLATION_ATTRIBUTES.NULL = TRUE;
|
|
|
|
|
X.RDB$SYSTEM_FLAG.NULL = TRUE;
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = TRUE;
|
|
|
|
|
X.RDB$FUNCTION_NAME.NULL = TRUE;
|
|
|
|
|
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
case att_coll_name:
|
|
|
|
|
X.RDB$COLLATION_NAME.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$COLLATION_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
BURP_verbose (msgVerbose_restore_collation, X.RDB$COLLATION_NAME, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_coll_id:
|
|
|
|
|
X.RDB$COLLATION_ID.NULL = FALSE;
|
|
|
|
|
X.RDB$COLLATION_ID = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_coll_cs_id:
|
|
|
|
|
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
|
|
|
|
|
X.RDB$CHARACTER_SET_ID = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_coll_attr:
|
|
|
|
|
X.RDB$COLLATION_ATTRIBUTES.NULL = FALSE;
|
|
|
|
|
X.RDB$COLLATION_ATTRIBUTES = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_coll_subtype: /* No longer used: 93-11-15 DBS */
|
|
|
|
|
/* still present to handle V4 R&D
|
|
|
|
|
gbak files */
|
|
|
|
|
(void) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_coll_sysflag:
|
|
|
|
|
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
|
|
|
|
X.RDB$SYSTEM_FLAG = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_coll_description:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$DESCRIPTION, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_coll_funct:
|
|
|
|
|
X.RDB$FUNCTION_NAME.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$FUNCTION_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, msgErr_restore_collation);
|
|
|
|
|
/* Bad RDB$COLLATION */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static REC_TYPE get_data (
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_REL relation)
|
2001-07-12 08:32:05 +02:00
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ d a t a
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Write data records for a relation.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
FLD field;
|
|
|
|
|
int *request, records;
|
|
|
|
|
TEXT *p;
|
|
|
|
|
SCHAR *blr, *blr_buffer;
|
|
|
|
|
RCRD_OFFSET offset;
|
|
|
|
|
USHORT l;
|
|
|
|
|
ULONG length, old_length;
|
|
|
|
|
SSHORT count, blr_length, alignment, dtype;
|
|
|
|
|
SSHORT *buffer;
|
|
|
|
|
LSTRING data;
|
2002-10-24 11:01:44 +02:00
|
|
|
|
STATUS status_vector[ISC_STATUS_LENGTH];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
SLONG *blob_id;
|
|
|
|
|
REC_TYPE record;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
isc_req_handle req_handle = NULL;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
long error_code;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
/* If we're only doing meta-data, ignore data records */
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_meta)
|
|
|
|
|
return ignore_data (relation);
|
|
|
|
|
|
|
|
|
|
/* Start by counting the interesting fields */
|
|
|
|
|
|
|
|
|
|
offset = length = 0;
|
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
|
|
for (field = relation->rel_fields; field; field = field->fld_next)
|
|
|
|
|
if (!(field->fld_flags & FLD_computed))
|
|
|
|
|
{
|
|
|
|
|
count++;
|
|
|
|
|
length += field->fld_name_length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tdgbl->RESTORE_format >= 2)
|
|
|
|
|
count += count;
|
|
|
|
|
|
|
|
|
|
/* Time to generate blr to store data. Whoppee. */
|
|
|
|
|
|
|
|
|
|
blr = blr_buffer = (SCHAR*) BURP_ALLOC (200 + length + count * 18);
|
|
|
|
|
STUFF (blr_version4);
|
|
|
|
|
STUFF (blr_begin);
|
|
|
|
|
STUFF (blr_message);
|
|
|
|
|
STUFF (0); /* Message number */
|
|
|
|
|
STUFF_WORD (count); /* Number of fields, counting eof */
|
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
|
|
for (field = relation->rel_fields; field; field = field->fld_next)
|
|
|
|
|
{
|
|
|
|
|
if (field->fld_flags & FLD_computed)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* arrays are of various fld_types but are really blobs */
|
|
|
|
|
|
|
|
|
|
dtype = field->fld_type;
|
|
|
|
|
length = field->fld_length;
|
|
|
|
|
alignment = 4;
|
|
|
|
|
|
|
|
|
|
if (field->fld_flags & FLD_array)
|
|
|
|
|
dtype = blr_blob;
|
|
|
|
|
|
|
|
|
|
if (dtype <= DTYPE_BLR_MAX)
|
|
|
|
|
{
|
|
|
|
|
l = gds_cvt_blr_dtype [dtype];
|
|
|
|
|
alignment = type_alignments [l];
|
|
|
|
|
if (l = type_lengths [l])
|
|
|
|
|
length = l;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (dtype)
|
|
|
|
|
{
|
|
|
|
|
case blr_text:
|
|
|
|
|
case blr_varying:
|
|
|
|
|
if (dtype == blr_text)
|
|
|
|
|
STUFF (blr_text2)
|
|
|
|
|
else
|
|
|
|
|
STUFF (blr_varying2);
|
|
|
|
|
STUFF_WORD (field->fld_character_set_id);
|
|
|
|
|
STUFF_WORD (field->fld_length);
|
|
|
|
|
if (dtype == blr_varying)
|
|
|
|
|
length += sizeof (USHORT);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case blr_short:
|
|
|
|
|
case blr_long:
|
|
|
|
|
case blr_quad:
|
|
|
|
|
case blr_int64:
|
|
|
|
|
STUFF (field->fld_type);
|
|
|
|
|
STUFF (field->fld_scale);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case blr_float:
|
|
|
|
|
case blr_double:
|
|
|
|
|
case blr_timestamp:
|
|
|
|
|
case blr_sql_time:
|
|
|
|
|
case blr_sql_date:
|
|
|
|
|
STUFF (field->fld_type);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case blr_blob:
|
|
|
|
|
alignment = type_alignments [dtype_blob];
|
|
|
|
|
length = type_lengths [dtype_blob];
|
|
|
|
|
STUFF (blr_quad);
|
|
|
|
|
STUFF (0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
#ifdef SUPERSERVER
|
2001-12-24 03:51:06 +01:00
|
|
|
|
BURP_svc_error (26, isc_arg_number, (void*)field->fld_type,
|
2001-07-12 08:32:05 +02:00
|
|
|
|
0, NULL, 0, NULL, 0, NULL, 0, NULL);
|
|
|
|
|
#else
|
|
|
|
|
BURP_error (26, (void*) field->fld_type, 0, 0, 0, 0);
|
|
|
|
|
/* msg 26 datatype %ld not understood */
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (alignment)
|
|
|
|
|
offset = FB_ALIGN(offset, alignment);
|
|
|
|
|
field->fld_offset = offset;
|
|
|
|
|
field->fld_parameter = count++;
|
|
|
|
|
offset += length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If this is format version 2, build fields for null flags */
|
|
|
|
|
|
|
|
|
|
if (tdgbl->RESTORE_format >= 2)
|
|
|
|
|
for (field = relation->rel_fields; field; field = field->fld_next)
|
|
|
|
|
{
|
|
|
|
|
if (field->fld_flags & FLD_computed)
|
|
|
|
|
continue;
|
|
|
|
|
STUFF (blr_short); STUFF (0);
|
|
|
|
|
offset = FB_ALIGN(offset, sizeof (SSHORT));
|
|
|
|
|
field->fld_missing_parameter = count++;
|
|
|
|
|
offset += sizeof (SSHORT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
length = offset;
|
|
|
|
|
|
|
|
|
|
/* Build STORE statement */
|
|
|
|
|
|
|
|
|
|
STUFF (blr_receive); STUFF (0);
|
|
|
|
|
STUFF (blr_store);
|
|
|
|
|
STUFF (blr_relation);
|
|
|
|
|
stuff_string (&blr, relation->rel_name);
|
|
|
|
|
STUFF (0); /* context variable */
|
|
|
|
|
STUFF (blr_begin);
|
|
|
|
|
|
|
|
|
|
for (field = relation->rel_fields; field; field = field->fld_next)
|
|
|
|
|
{
|
|
|
|
|
if (field->fld_flags & FLD_computed)
|
|
|
|
|
continue;
|
|
|
|
|
STUFF (blr_assignment);
|
|
|
|
|
if (tdgbl->RESTORE_format >= 2)
|
|
|
|
|
{
|
|
|
|
|
STUFF (blr_parameter2); STUFF (0);
|
|
|
|
|
STUFF_WORD (field->fld_parameter);
|
|
|
|
|
STUFF_WORD (field->fld_missing_parameter);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
STUFF (blr_parameter); STUFF (0);
|
|
|
|
|
STUFF_WORD (field->fld_parameter);
|
|
|
|
|
}
|
|
|
|
|
STUFF (blr_field); STUFF (0);
|
|
|
|
|
stuff_string (&blr, field->fld_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STUFF (blr_end);
|
|
|
|
|
STUFF (blr_end);
|
|
|
|
|
STUFF (blr_eoc);
|
|
|
|
|
|
|
|
|
|
/* Compile request */
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
isc_print_blr (blr_buffer, NULL_PTR, NULL_PTR, 0);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
request = NULL;
|
|
|
|
|
blr_length = blr - blr_buffer;
|
|
|
|
|
if (isc_compile_request (status_vector,
|
|
|
|
|
GDS_REF (tdgbl->db_handle),
|
|
|
|
|
(void**) GDS_REF (request),
|
|
|
|
|
blr_length,
|
|
|
|
|
GDS_VAL (blr_buffer)))
|
|
|
|
|
{
|
|
|
|
|
isc_print_blr (blr_buffer, (isc_callback)NULL_PTR, NULL_PTR, 0);
|
|
|
|
|
if (!tdgbl->gbl_sw_incremental)
|
|
|
|
|
BURP_error_redirect (status_vector, 27, 0, 0);
|
|
|
|
|
/* msg 27 gds__compile_request failed */
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
BURP_print_status (status_vector);
|
|
|
|
|
BURP_FREE (blr_buffer);
|
|
|
|
|
return ignore_data (relation);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BURP_FREE (blr_buffer);
|
|
|
|
|
buffer = NULL;
|
|
|
|
|
|
|
|
|
|
data.lstr_allocated = records = 0;
|
|
|
|
|
|
|
|
|
|
BURP_verbose (124, relation->rel_name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 124 restoring data for relation %s */
|
|
|
|
|
|
|
|
|
|
data.lstr_address = NULL;
|
|
|
|
|
old_length = 0;
|
|
|
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
|
{
|
|
|
|
|
if (GET() != att_data_length)
|
|
|
|
|
BURP_error_redirect ((STATUS *) NULL_PTR, 39, 0, 0);
|
|
|
|
|
/* msg 39 expected record length */
|
|
|
|
|
l = (USHORT) get_numeric();
|
|
|
|
|
if (!tdgbl->gbl_sw_transportable && l != length)
|
|
|
|
|
{
|
|
|
|
|
if (!old_length)
|
|
|
|
|
old_length = recompute_length (relation);
|
|
|
|
|
if (l != old_length)
|
|
|
|
|
#ifdef SUPERSERVER
|
2001-12-24 03:51:06 +01:00
|
|
|
|
BURP_svc_error(40, isc_arg_number, (void*)length,
|
|
|
|
|
isc_arg_number, (void*)l,
|
|
|
|
|
0, NULL, 0, NULL, 0, NULL);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
#else
|
|
|
|
|
BURP_error (40, (void*) length, (void*) l, 0, 0, 0);
|
|
|
|
|
/* msg 40 wrong length record, expected %ld encountered %ld */
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
if (!buffer)
|
|
|
|
|
buffer = (SSHORT *) BURP_ALLOC (MAX (length, l));
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_transportable)
|
|
|
|
|
if (GET () != att_xdr_length)
|
|
|
|
|
BURP_error_redirect ((STATUS *) NULL_PTR, 55, 0, 0);
|
|
|
|
|
/* msg 55 Expected XDR record length */
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
data.lstr_length = l = (USHORT) get_numeric();
|
|
|
|
|
if (l > data.lstr_allocated)
|
|
|
|
|
{
|
|
|
|
|
data.lstr_allocated = l;
|
|
|
|
|
if (data.lstr_address)
|
|
|
|
|
BURP_FREE (data.lstr_address);
|
|
|
|
|
data.lstr_address = (UCHAR *) BURP_ALLOC (data.lstr_allocated);
|
|
|
|
|
}
|
|
|
|
|
p = (TEXT*) data.lstr_address;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
p = (TEXT*) buffer;
|
|
|
|
|
if (GET () != att_data_data)
|
|
|
|
|
BURP_error_redirect ((STATUS *) NULL_PTR, 41, 0, 0);
|
|
|
|
|
/* msg 41 expected data attribute */
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_compress)
|
|
|
|
|
decompress ((UCHAR*) p, l);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
(void) GET_BLOCK ((UCHAR*) p, l);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (old_length)
|
|
|
|
|
realign ((UCHAR *)buffer, relation);
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_transportable)
|
|
|
|
|
CAN_encode_decode (relation, &data, (UCHAR *)buffer, FALSE);
|
|
|
|
|
|
|
|
|
|
records++;
|
|
|
|
|
|
|
|
|
|
if ((records % RESTORE_VERBOSE_INTERVAL)==0)
|
|
|
|
|
BURP_verbose(107,(void*) records,NULL_PTR,NULL_PTR,NULL_PTR,NULL_PTR);
|
|
|
|
|
|
|
|
|
|
for (field = relation->rel_fields; field; field = field->fld_next)
|
|
|
|
|
if ((field->fld_type == blr_blob) || (field->fld_flags & FLD_array))
|
|
|
|
|
{
|
|
|
|
|
blob_id = (SLONG*) ((SCHAR*) buffer + field->fld_offset);
|
|
|
|
|
blob_id [0] = blob_id [1] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GET_RECORD (record);
|
|
|
|
|
while (record == rec_blob || record == rec_array)
|
|
|
|
|
{
|
|
|
|
|
if (record == rec_blob)
|
|
|
|
|
get_blob (relation->rel_fields, (UCHAR *) buffer);
|
|
|
|
|
|
|
|
|
|
else if (record == rec_array)
|
|
|
|
|
get_array (relation, (UCHAR *) buffer);
|
|
|
|
|
|
|
|
|
|
GET_RECORD (record);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (isc_start_and_send (status_vector,
|
|
|
|
|
(void**) GDS_REF (request),
|
|
|
|
|
GDS_REF (gds_trans),
|
|
|
|
|
0,
|
|
|
|
|
(USHORT) length,
|
|
|
|
|
GDS_VAL (buffer),
|
|
|
|
|
0))
|
|
|
|
|
if (status_vector [1] == gds_not_valid)
|
|
|
|
|
if (tdgbl->gbl_sw_incremental)
|
|
|
|
|
{
|
|
|
|
|
BURP_print (138, relation->rel_name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 138 validation error on field in relation %s */
|
|
|
|
|
BURP_print_status (status_vector);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
BURP_error_redirect (status_vector, 47, 0, 0);
|
|
|
|
|
/* msg 47 warning -- record could not be restored */
|
|
|
|
|
else
|
|
|
|
|
if (tdgbl->gbl_sw_incremental)
|
|
|
|
|
{
|
|
|
|
|
BURP_print (114, relation->rel_name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 114 restore failed for record in relation %s */
|
|
|
|
|
BURP_print_status (status_vector);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
BURP_error_redirect (status_vector, 48, 0, 0);
|
|
|
|
|
/* msg 48 gds__send failed */
|
|
|
|
|
if (record != rec_data)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BURP_FREE (buffer);
|
|
|
|
|
if (data.lstr_address)
|
|
|
|
|
BURP_FREE (data.lstr_address);
|
|
|
|
|
|
|
|
|
|
isc_release_request (status_vector,
|
|
|
|
|
(void**) GDS_REF (request));
|
|
|
|
|
if (tdgbl->gbl_sw_incremental)
|
|
|
|
|
{
|
|
|
|
|
BURP_verbose (72, relation->rel_name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 72 committing data for relation %s */
|
|
|
|
|
COMMIT
|
|
|
|
|
/* existing ON_ERROR continues past error, beck */
|
|
|
|
|
ON_ERROR
|
|
|
|
|
|
|
|
|
|
/* Fix for bug_no 8055:
|
|
|
|
|
don't throw away the database just because an index
|
|
|
|
|
could not be made */
|
|
|
|
|
while (error_code = tdgbl->status_vector[1])
|
|
|
|
|
{
|
|
|
|
|
switch (error_code)
|
|
|
|
|
{
|
|
|
|
|
case gds_sort_mem_err:
|
|
|
|
|
case gds_no_dup:
|
|
|
|
|
strcpy(index_name, (TEXT *)tdgbl->status_vector[3]);
|
|
|
|
|
BURP_print_status(tdgbl->status_vector);
|
|
|
|
|
FOR (REQUEST_HANDLE req_handle)
|
|
|
|
|
IDX IN RDB$INDICES WITH IDX.RDB$INDEX_NAME EQ index_name
|
|
|
|
|
MODIFY IDX USING IDX.RDB$INDEX_INACTIVE = TRUE;
|
|
|
|
|
BURP_print(240, index_name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 240 Index \"%s\" failed to activate because: */
|
|
|
|
|
if ( error_code == gds_no_dup )
|
|
|
|
|
{
|
|
|
|
|
BURP_print(241, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 241 The unique index has duplicate values or NULLs */
|
|
|
|
|
BURP_print(242, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 242 Delete or Update duplicate values or NULLs, and activate index with */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
BURP_print(244, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 244 Not enough disk space to create the sort file for an index */
|
|
|
|
|
BURP_print(245, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 245 Set the TMP environment variable to a directory on a filesystem that does have enough space, and activate index with */
|
|
|
|
|
}
|
|
|
|
|
BURP_print(243, index_name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 243 ALTER INDEX \"%s\" ACTIVE; */
|
|
|
|
|
END_MODIFY;
|
|
|
|
|
END_FOR;
|
|
|
|
|
/* don't bring the database on-line */
|
|
|
|
|
flag_on_line = FALSE;
|
|
|
|
|
/* commit one more time */
|
|
|
|
|
COMMIT
|
|
|
|
|
ON_ERROR
|
|
|
|
|
continue;
|
|
|
|
|
END_ERROR
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
BURP_print (69, relation->rel_name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 69 commit failed on relation %s */
|
|
|
|
|
BURP_print_status (tdgbl->status_vector);
|
|
|
|
|
ROLLBACK;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
break;
|
|
|
|
|
} /* end of switch */
|
|
|
|
|
} /* end of while */
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
|
|
|
|
|
if (gds_status [1])
|
|
|
|
|
EXEC SQL SET TRANSACTION;
|
|
|
|
|
}
|
|
|
|
|
BURP_verbose (107, (void*) records, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 107 %ld records restored */
|
|
|
|
|
|
|
|
|
|
return record;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_exception(void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ e x c e p t i o n
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Reconstruct a exception.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
2002-06-29 07:39:38 +02:00
|
|
|
|
TEXT temp [GDS_NAME_LEN];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
ULONG l;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_exception_req_handle1)
|
|
|
|
|
X IN RDB$EXCEPTIONS
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = TRUE;
|
|
|
|
|
X.RDB$MESSAGE.NULL = TRUE;
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_exception_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
l = GET_TEXT(X.RDB$EXCEPTION_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
MISC_terminate ((UCHAR*) X.RDB$EXCEPTION_NAME, (UCHAR*) temp, l, sizeof (temp));
|
|
|
|
|
BURP_verbose (199, temp, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 199 restoring exception %s */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_exception_description:
|
|
|
|
|
get_misc_blob (&X.RDB$DESCRIPTION, 0, 0);
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_exception_description2:
|
|
|
|
|
get_source_blob (&X.RDB$DESCRIPTION, 0);
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_exception_msg:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$MESSAGE);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
X.RDB$MESSAGE.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 89);
|
|
|
|
|
/* msg 89 function */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN cvt_v3_to_v4_intl (
|
|
|
|
|
SSHORT dtype,
|
|
|
|
|
SSHORT *scale,
|
|
|
|
|
SSHORT *sub_type,
|
|
|
|
|
SSHORT *character_set_id,
|
|
|
|
|
SSHORT *collation_id)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* c v t _ v 3 _ t o _ v 4 _ i n t l
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Convert a V3 scale / sub_type to V4 character_set / collate_sequence
|
|
|
|
|
*
|
|
|
|
|
* Version 3.2 & 3.3 of InterBase used different methodologies
|
|
|
|
|
* to tag international text character sets and country collation
|
|
|
|
|
* sequences. This routine will convert a V3 metadata definition
|
|
|
|
|
* into the corresponding V4 definition.
|
|
|
|
|
*
|
|
|
|
|
* In V3.x, sub-type 0 is normal text, subtype 1 is "text that can
|
|
|
|
|
* contain a NULL byte, and can therefore not be represented
|
|
|
|
|
* using a c-string datatype, always use fixed".
|
|
|
|
|
*
|
|
|
|
|
* Return TRUE if a conversion was performed, FALSE otherwise.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
SSHORT i;
|
|
|
|
|
|
|
|
|
|
switch (dtype)
|
|
|
|
|
{
|
|
|
|
|
case blr_text2:
|
|
|
|
|
case blr_varying2:
|
|
|
|
|
case blr_cstring2:
|
|
|
|
|
|
|
|
|
|
case blr_text:
|
|
|
|
|
case blr_varying:
|
|
|
|
|
case blr_cstring:
|
|
|
|
|
|
|
|
|
|
/* Japanese V3.2 used SCALE 5 to indicate SJIS text */
|
|
|
|
|
if (*scale == 5 && ((*sub_type == 0) || (*sub_type == 1)))
|
|
|
|
|
{
|
|
|
|
|
*character_set_id = CS_JIS_0208;
|
|
|
|
|
*collation_id = 0;
|
|
|
|
|
BURP_verbose (237, (void*) *scale, (void*) *character_set_id,
|
|
|
|
|
(void*) *collation_id, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 237: Converted V3 scale: %d to
|
|
|
|
|
character_set_id: %d and callate_id: %d. */
|
|
|
|
|
*scale = 0;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Japanese V3.2 used SCALE 6 to indicate EUCJ text */
|
|
|
|
|
if (*scale == 6 && (*sub_type == 0 || *sub_type == 1))
|
|
|
|
|
{
|
|
|
|
|
*character_set_id = CS_EUCJ;
|
|
|
|
|
*collation_id = 0;
|
|
|
|
|
BURP_verbose (237, (void*) *scale, (void*) *character_set_id,
|
|
|
|
|
(void*) *collation_id, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 237: Converted V3 scale: %d to
|
|
|
|
|
character_set_id: %d and callate_id: %d. */
|
|
|
|
|
*scale = 0;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* V3.3 used SCALE 0 and Subtypes in range 100 - 255 for
|
|
|
|
|
European text types and collations */
|
|
|
|
|
|
|
|
|
|
if (*scale != 0)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (*sub_type == 0 || *sub_type == 1)
|
|
|
|
|
/* Do not process sub_type 0,1 conversion */
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < cvtbl_len; i ++)
|
|
|
|
|
if (sub_type_cvtbl [i].sub_type == *sub_type)
|
|
|
|
|
{
|
|
|
|
|
*character_set_id = sub_type_cvtbl [i].character_set_id;
|
|
|
|
|
*collation_id = sub_type_cvtbl [i].collation_id;
|
|
|
|
|
|
|
|
|
|
BURP_verbose (236, (void*) *sub_type, (void*) *character_set_id,
|
|
|
|
|
(void*) *collation_id, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 236: Converted V3 sub_type: %d to
|
|
|
|
|
character_set_id: %d and callate_id: %d. */
|
|
|
|
|
|
|
|
|
|
*sub_type = 0;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* Do not process sub_type conversion on non-text field */
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static FLD get_field (
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_REL relation)
|
2001-07-12 08:32:05 +02:00
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ f i e l d
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Reconstruct a local field.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
FLD field;
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
USHORT n,
|
|
|
|
|
global_tr = FALSE;
|
|
|
|
|
SLONG *rp;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
FLD f;
|
|
|
|
|
isc_tr_handle local_trans;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
/* If it is a view and there is a global transaction then use it */
|
|
|
|
|
|
|
|
|
|
if ((relation->rel_flags & REL_view) && (tdgbl->global_trans))
|
|
|
|
|
{
|
|
|
|
|
local_trans = tdgbl->global_trans;
|
|
|
|
|
global_tr = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
local_trans = gds_trans;
|
|
|
|
|
|
|
|
|
|
field = (FLD) BURP_ALLOC_ZERO (sizeof (struct fld));
|
|
|
|
|
|
|
|
|
|
STORE (TRANSACTION_HANDLE local_trans
|
|
|
|
|
REQUEST_HANDLE tdgbl->handles_get_field_req_handle1)
|
|
|
|
|
X IN RDB$RELATION_FIELDS
|
|
|
|
|
strcpy (X.RDB$RELATION_NAME, relation->rel_name);
|
|
|
|
|
X.RDB$FIELD_POSITION = 0;
|
|
|
|
|
memset (X.RDB$QUERY_NAME, ' ', sizeof (X.RDB$QUERY_NAME));
|
|
|
|
|
X.RDB$VIEW_CONTEXT.NULL = TRUE;
|
|
|
|
|
X.RDB$BASE_FIELD.NULL = TRUE;
|
|
|
|
|
X.RDB$SECURITY_CLASS.NULL = TRUE;
|
|
|
|
|
X.RDB$QUERY_NAME.NULL = TRUE;
|
|
|
|
|
X.RDB$QUERY_HEADER.NULL = TRUE;
|
|
|
|
|
X.RDB$EDIT_STRING.NULL = TRUE;
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = TRUE;
|
|
|
|
|
X.RDB$FIELD_POSITION.NULL = TRUE;
|
|
|
|
|
X.RDB$SYSTEM_FLAG.NULL = TRUE;
|
|
|
|
|
X.RDB$COMPLEX_NAME.NULL = TRUE;
|
|
|
|
|
X.RDB$UPDATE_FLAG.NULL = TRUE;
|
|
|
|
|
X.RDB$DEFAULT_SOURCE.NULL = TRUE;
|
|
|
|
|
X.RDB$DEFAULT_VALUE.NULL = TRUE;
|
|
|
|
|
X.RDB$NULL_FLAG.NULL = TRUE;
|
|
|
|
|
X.RDB$COLLATION_ID.NULL = TRUE;
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (SKIP_SCAN, attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_field_name:
|
|
|
|
|
field->fld_name_length =
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(field->fld_name);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
BURP_verbose (115, field->fld_name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 115 restoring field %s */
|
|
|
|
|
strcpy (X.RDB$FIELD_NAME, field->fld_name);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_source:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$FIELD_SOURCE);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_security_class:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$SECURITY_CLASS);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
X.RDB$SECURITY_CLASS.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_query_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$QUERY_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
X.RDB$QUERY_NAME.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_query_header:
|
|
|
|
|
X.RDB$QUERY_HEADER.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$QUERY_HEADER, global_tr);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_edit_string:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$EDIT_STRING);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
X.RDB$EDIT_STRING.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_position:
|
|
|
|
|
X.RDB$FIELD_POSITION.NULL = FALSE;
|
|
|
|
|
X.RDB$FIELD_POSITION = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_number:
|
|
|
|
|
field->fld_number = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_type:
|
|
|
|
|
field->fld_type = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_length:
|
|
|
|
|
field->fld_length = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_scale:
|
|
|
|
|
field->fld_scale = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_sub_type:
|
|
|
|
|
field->fld_sub_type = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_system_flag:
|
|
|
|
|
X.RDB$SYSTEM_FLAG = (USHORT) get_numeric();
|
|
|
|
|
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_view_context:
|
|
|
|
|
X.RDB$VIEW_CONTEXT = (USHORT) get_numeric();
|
|
|
|
|
X.RDB$VIEW_CONTEXT.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_computed_flag:
|
|
|
|
|
if (get_numeric())
|
|
|
|
|
field->fld_flags |= FLD_computed;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_base_field:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$BASE_FIELD);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
X.RDB$BASE_FIELD.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_description:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_misc_blob (&X.RDB$DESCRIPTION, 1, global_tr);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_description2:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$DESCRIPTION, (UCHAR) global_tr);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_complex_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$COMPLEX_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
X.RDB$COMPLEX_NAME.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_dimensions:
|
|
|
|
|
field->fld_dimensions = (USHORT) get_numeric();
|
|
|
|
|
field->fld_flags |= FLD_array;
|
|
|
|
|
for (rp = field->fld_ranges, n = field->fld_dimensions; n; rp+=2, n--)
|
|
|
|
|
{
|
|
|
|
|
if (GET_ATTRIBUTE (attribute) != att_field_range_low)
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 58);
|
|
|
|
|
/* msg 58 array */
|
|
|
|
|
else
|
|
|
|
|
*rp = get_numeric();
|
|
|
|
|
if (GET_ATTRIBUTE (attribute) != att_field_range_high)
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 58);
|
|
|
|
|
/* msg 58 array */
|
|
|
|
|
else
|
|
|
|
|
*(rp+1) = get_numeric();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_update_flag:
|
|
|
|
|
X.RDB$UPDATE_FLAG.NULL = FALSE;
|
|
|
|
|
X.RDB$UPDATE_FLAG = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_character_length:
|
|
|
|
|
field->fld_character_length = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_default_source:
|
|
|
|
|
X.RDB$DEFAULT_SOURCE.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$DEFAULT_SOURCE, global_tr);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_default_value:
|
|
|
|
|
X.RDB$DEFAULT_VALUE.NULL = FALSE;
|
|
|
|
|
get_blr_blob (&X.RDB$DEFAULT_VALUE, global_tr);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_null_flag:
|
|
|
|
|
X.RDB$NULL_FLAG.NULL = FALSE;
|
|
|
|
|
X.RDB$NULL_FLAG = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_character_set:
|
|
|
|
|
field->fld_character_set_id = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_collation_id:
|
|
|
|
|
field->fld_collation_id = (USHORT) get_numeric();
|
|
|
|
|
X.RDB$COLLATION_ID.NULL = FALSE;
|
|
|
|
|
X.RDB$COLLATION_ID = field->fld_collation_id;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 84);
|
|
|
|
|
/* msg 84 field */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* For migration from V3.3 to V4.0 format of International text
|
|
|
|
|
* information - search the list of global fields which were
|
|
|
|
|
* remapped from V3.3 format into V4.0 format. If we find that
|
|
|
|
|
* this local field's source is one of those global fields, then
|
|
|
|
|
* remap the local field's information. This is used to compose
|
|
|
|
|
* the BLR which sends data to the newly restored database.
|
|
|
|
|
*/
|
|
|
|
|
for (f = tdgbl->v3_cvt_fld_list; f; f = f->fld_next)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp(X.RDB$FIELD_SOURCE, f->fld_name))
|
|
|
|
|
{
|
|
|
|
|
field->fld_sub_type = f->fld_sub_type;
|
|
|
|
|
field->fld_scale = f->fld_scale;
|
|
|
|
|
field->fld_character_set_id = f->fld_character_set_id;
|
|
|
|
|
field->fld_collation_id = f->fld_collation_id;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
return field;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_field_dimensions (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ f i e l d _ d i m e n s i o n s
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Get array field dimensions in rdb$field_dimensions.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_field_dimensions_req_handle1)
|
|
|
|
|
X IN RDB$FIELD_DIMENSIONS
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
{
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_field_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$FIELD_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_dimensions:
|
|
|
|
|
X.RDB$DIMENSION = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_range_low:
|
|
|
|
|
X.RDB$LOWER_BOUND = get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_range_high:
|
|
|
|
|
X.RDB$UPPER_BOUND = get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 58);
|
|
|
|
|
/* msg 58 array */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_files (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ f i l e s
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Get any files that were stored; let
|
|
|
|
|
* somebody else worry about what to do with them.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_files_req_handle1)
|
|
|
|
|
X IN RDB$FILES
|
|
|
|
|
X.RDB$FILE_FLAGS = 0;
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_file_filename:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$FILE_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
BURP_verbose (116,
|
|
|
|
|
/* msg 116 restoring file %s */
|
|
|
|
|
X.RDB$FILE_NAME, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_file_sequence:
|
|
|
|
|
X.RDB$FILE_SEQUENCE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_file_start:
|
|
|
|
|
X.RDB$FILE_START = get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_file_length:
|
|
|
|
|
X.RDB$FILE_LENGTH = get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_file_flags:
|
|
|
|
|
X.RDB$FILE_FLAGS |= get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_shadow_number:
|
|
|
|
|
X.RDB$SHADOW_NUMBER = (USHORT) get_numeric();
|
|
|
|
|
if (tdgbl->gbl_sw_kill && X.RDB$SHADOW_NUMBER)
|
|
|
|
|
X.RDB$FILE_FLAGS |= FILE_inactive;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 85);
|
|
|
|
|
/* msg 85 file */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_filter (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ f i l t e r
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Get a type definition in rdb$filters.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_filter_req_handle1)
|
|
|
|
|
X IN RDB$FILTERS
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = TRUE;
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
{
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_filter_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$FUNCTION_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
BURP_verbose (117, X.RDB$FUNCTION_NAME, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 117 restoring filter %s */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_filter_description:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_misc_blob (&X.RDB$DESCRIPTION, 1, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_filter_description2:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$DESCRIPTION, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_filter_module_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$MODULE_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_filter_entrypoint:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$ENTRYPOINT);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_filter_input_sub_type:
|
|
|
|
|
X.RDB$INPUT_SUB_TYPE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_filter_output_sub_type:
|
|
|
|
|
X.RDB$OUTPUT_SUB_TYPE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 87);
|
|
|
|
|
/* msg 87 filter */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_function (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ f u n c t i o n
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Reconstruct a function.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
GDS_NAME function_name;
|
2002-06-29 07:39:38 +02:00
|
|
|
|
TEXT temp [GDS_NAME_LEN];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
SSHORT l;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_function_req_handle1)
|
|
|
|
|
X IN RDB$FUNCTIONS
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_function_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
l = GET_TEXT(X.RDB$FUNCTION_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
MISC_terminate ((UCHAR*) X.RDB$FUNCTION_NAME, (UCHAR*) temp, l, sizeof (temp));
|
|
|
|
|
BURP_verbose (118, temp, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 118 restoring function %s */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_function_description:
|
|
|
|
|
get_misc_blob (&X.RDB$DESCRIPTION, 0, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_function_description2:
|
|
|
|
|
get_source_blob (&X.RDB$DESCRIPTION, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_function_module_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$MODULE_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_function_entrypoint:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$ENTRYPOINT);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_function_return_arg:
|
|
|
|
|
X.RDB$RETURN_ARGUMENT = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_function_query_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$QUERY_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_function_type:
|
|
|
|
|
X.RDB$FUNCTION_TYPE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 89);
|
|
|
|
|
/* msg 89 function */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
strcpy (function_name, X.RDB$FUNCTION_NAME);
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
/* at the end of args for a function is the rec_function_end marker */
|
|
|
|
|
while (GET () == rec_function_arg)
|
|
|
|
|
get_function_arg (function_name);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void get_function_arg (
|
|
|
|
|
GDS_NAME funcptr)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ f u n c t i o n _ a r g
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Reconstruct function argument.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
SSHORT l;
|
2002-06-29 07:39:38 +02:00
|
|
|
|
TEXT temp [GDS_NAME_LEN];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
if (tdgbl->RESTORE_format >= 6)
|
|
|
|
|
{
|
|
|
|
|
/* with RDB$FIELD_PRECISION */
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_function_arg_req_handle1)
|
|
|
|
|
X IN RDB$FUNCTION_ARGUMENTS
|
|
|
|
|
X.RDB$FIELD_SUB_TYPE.NULL = TRUE;
|
|
|
|
|
X.RDB$CHARACTER_SET_ID.NULL = TRUE;
|
|
|
|
|
X.RDB$FIELD_PRECISION.NULL = TRUE;
|
|
|
|
|
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_functionarg_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
l = GET_TEXT(X.RDB$FUNCTION_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
MISC_terminate ((UCHAR*) X.RDB$FUNCTION_NAME, (UCHAR*) temp, l, sizeof (temp));
|
|
|
|
|
BURP_verbose (119, temp, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 119 restoring argument for function %s */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_functionarg_position:
|
|
|
|
|
X.RDB$ARGUMENT_POSITION = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_functionarg_mechanism:
|
|
|
|
|
X.RDB$MECHANISM = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_functionarg_field_type:
|
|
|
|
|
X.RDB$FIELD_TYPE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_functionarg_field_scale:
|
|
|
|
|
X.RDB$FIELD_SCALE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_functionarg_field_length:
|
|
|
|
|
X.RDB$FIELD_LENGTH = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_functionarg_field_sub_type:
|
|
|
|
|
X.RDB$FIELD_SUB_TYPE.NULL = FALSE;
|
|
|
|
|
X.RDB$FIELD_SUB_TYPE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_functionarg_character_set:
|
|
|
|
|
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
|
|
|
|
|
X.RDB$CHARACTER_SET_ID = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_functionarg_field_precision:
|
|
|
|
|
X.RDB$FIELD_PRECISION.NULL = FALSE;
|
|
|
|
|
X.RDB$FIELD_PRECISION = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 90);
|
|
|
|
|
/* msg 90 function argument */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* without RDB$FIELD_PRECISION */
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_function_arg_req_handle1)
|
|
|
|
|
X IN RDB$FUNCTION_ARGUMENTS
|
|
|
|
|
X.RDB$FIELD_SUB_TYPE.NULL = TRUE;
|
|
|
|
|
X.RDB$CHARACTER_SET_ID.NULL = TRUE;
|
|
|
|
|
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_functionarg_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
l = GET_TEXT(X.RDB$FUNCTION_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
MISC_terminate ((UCHAR*) X.RDB$FUNCTION_NAME, (UCHAR*) temp, l, sizeof (temp));
|
|
|
|
|
BURP_verbose (119, temp, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 119 restoring argument for function %s */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_functionarg_position:
|
|
|
|
|
X.RDB$ARGUMENT_POSITION = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_functionarg_mechanism:
|
|
|
|
|
X.RDB$MECHANISM = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_functionarg_field_type:
|
|
|
|
|
X.RDB$FIELD_TYPE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_functionarg_field_scale:
|
|
|
|
|
X.RDB$FIELD_SCALE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_functionarg_field_length:
|
|
|
|
|
X.RDB$FIELD_LENGTH = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_functionarg_field_sub_type:
|
|
|
|
|
X.RDB$FIELD_SUB_TYPE.NULL = FALSE;
|
|
|
|
|
X.RDB$FIELD_SUB_TYPE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_functionarg_character_set:
|
|
|
|
|
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
|
|
|
|
|
X.RDB$CHARACTER_SET_ID = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 90);
|
|
|
|
|
/* msg 90 function argument */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_generator (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ g e n e r a t o r
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Pick up a gen-id. Like most things, there is ughly history.
|
|
|
|
|
* In the modern world, gen_id are free floating records. In the
|
|
|
|
|
* bad old days they were attributes of relations. Handle both
|
|
|
|
|
* nicely.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
SINT64 value;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
BASED_ON RDB$GENERATORS.RDB$GENERATOR_NAME name;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_gen_generator:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(name);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_gen_value:
|
|
|
|
|
/* IB v5 or earlier, gen_id value is an SLONG */
|
|
|
|
|
value = (SINT64) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_gen_value_int64:
|
|
|
|
|
/* IB v6 or later, gen_id value is an SINT64 */
|
|
|
|
|
value = get_int64();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 93);
|
|
|
|
|
/* msg 93 index */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
store_blr_gen_id (name, value);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_global_field (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ g l o b a l _ f i e l d
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Reconstruct a global field.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
2002-06-29 07:39:38 +02:00
|
|
|
|
TEXT temp [GDS_NAME_LEN];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
SSHORT l;
|
|
|
|
|
GFLD gfld;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
SSHORT save_subtype;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
gfld = (GFLD) NULL_PTR;
|
|
|
|
|
|
|
|
|
|
if (tdgbl->RESTORE_format >= 6)
|
|
|
|
|
{
|
|
|
|
|
/* with rdb$field_precision */
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_global_field_req_handle1)
|
|
|
|
|
X IN RDB$FIELDS
|
|
|
|
|
|
|
|
|
|
X.RDB$FIELD_SCALE = X.RDB$SEGMENT_LENGTH = 0;
|
|
|
|
|
X.RDB$CHARACTER_SET_ID = X.RDB$COLLATION_ID = 0;
|
|
|
|
|
X.RDB$FIELD_SUB_TYPE = 0;
|
|
|
|
|
X.RDB$COMPUTED_BLR.NULL = TRUE;
|
|
|
|
|
X.RDB$COMPUTED_SOURCE.NULL = TRUE;
|
|
|
|
|
X.RDB$QUERY_NAME.NULL = TRUE;
|
|
|
|
|
X.RDB$EDIT_STRING.NULL = TRUE;
|
|
|
|
|
X.RDB$QUERY_HEADER.NULL = TRUE;
|
|
|
|
|
X.RDB$MISSING_VALUE.NULL = TRUE;
|
|
|
|
|
X.RDB$DEFAULT_VALUE.NULL = TRUE;
|
|
|
|
|
X.RDB$VALIDATION_BLR.NULL = TRUE;
|
|
|
|
|
X.RDB$VALIDATION_SOURCE.NULL = TRUE;
|
|
|
|
|
X.RDB$SYSTEM_FLAG.NULL = TRUE;
|
|
|
|
|
X.RDB$NULL_FLAG.NULL = TRUE;
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = TRUE;
|
|
|
|
|
X.RDB$DIMENSIONS.NULL = TRUE;
|
|
|
|
|
X.RDB$EXTERNAL_LENGTH.NULL = TRUE;
|
|
|
|
|
X.RDB$EXTERNAL_TYPE.NULL = TRUE;
|
|
|
|
|
X.RDB$EXTERNAL_SCALE.NULL = TRUE;
|
|
|
|
|
X.RDB$SEGMENT_LENGTH.NULL = TRUE;
|
|
|
|
|
X.RDB$CHARACTER_LENGTH.NULL = TRUE;
|
|
|
|
|
X.RDB$MISSING_SOURCE.NULL = TRUE;
|
|
|
|
|
X.RDB$DEFAULT_SOURCE.NULL = TRUE;
|
|
|
|
|
X.RDB$FIELD_SUB_TYPE.NULL = TRUE;
|
|
|
|
|
X.RDB$CHARACTER_SET_ID.NULL = TRUE;
|
|
|
|
|
X.RDB$COLLATION_ID.NULL = TRUE;
|
|
|
|
|
X.RDB$FIELD_PRECISION.NULL = TRUE;
|
|
|
|
|
|
|
|
|
|
memset (X.RDB$QUERY_NAME, ' ', sizeof (X.RDB$QUERY_NAME));
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_field_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
l = GET_TEXT(X.RDB$FIELD_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
MISC_terminate ((UCHAR*) X.RDB$FIELD_NAME, (UCHAR*) temp, l, sizeof (temp));
|
|
|
|
|
BURP_verbose (121, temp, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 121 restoring global field %s */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_query_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$QUERY_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
X.RDB$QUERY_NAME.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_edit_string:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$EDIT_STRING);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
X.RDB$EDIT_STRING.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_query_header:
|
|
|
|
|
X.RDB$QUERY_HEADER.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$QUERY_HEADER, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_type:
|
|
|
|
|
X.RDB$FIELD_TYPE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_length:
|
|
|
|
|
X.RDB$FIELD_LENGTH = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_scale:
|
|
|
|
|
X.RDB$FIELD_SCALE = (USHORT) get_numeric();
|
|
|
|
|
X.RDB$FIELD_SCALE.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_sub_type:
|
|
|
|
|
X.RDB$FIELD_SUB_TYPE = (USHORT) get_numeric();
|
|
|
|
|
X.RDB$FIELD_SUB_TYPE.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_segment_length:
|
|
|
|
|
X.RDB$SEGMENT_LENGTH = (USHORT) get_numeric();
|
|
|
|
|
if (X.RDB$SEGMENT_LENGTH)
|
|
|
|
|
X.RDB$SEGMENT_LENGTH.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_computed_blr:
|
|
|
|
|
X.RDB$COMPUTED_BLR.NULL = FALSE;
|
|
|
|
|
get_blr_blob (&X.RDB$COMPUTED_BLR, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_computed_source:
|
|
|
|
|
X.RDB$COMPUTED_SOURCE.NULL = FALSE;
|
|
|
|
|
get_misc_blob (&X.RDB$COMPUTED_SOURCE, 1, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_computed_source2:
|
|
|
|
|
X.RDB$COMPUTED_SOURCE.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$COMPUTED_SOURCE, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_validation_blr:
|
|
|
|
|
if (tdgbl->gbl_sw_novalidity)
|
|
|
|
|
eat_blob();
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* if we are going against a V4.0 database,
|
|
|
|
|
* restore the global fields in 2 phases.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (tdgbl->global_trans)
|
|
|
|
|
{
|
|
|
|
|
if (!gfld)
|
|
|
|
|
gfld = (GFLD) BURP_ALLOC_ZERO (sizeof (struct gfld));
|
|
|
|
|
|
|
|
|
|
get_blr_blob (&gfld->gfld_vb, 1);
|
|
|
|
|
gfld->gfld_flags |= GFLD_validation_blr;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
X.RDB$VALIDATION_BLR.NULL = FALSE;
|
|
|
|
|
get_blr_blob (&X.RDB$VALIDATION_BLR, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_validation_source:
|
|
|
|
|
if (tdgbl->gbl_sw_novalidity)
|
|
|
|
|
eat_blob();
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* if we are going against a V4.0 database,
|
|
|
|
|
* restore the global fields in 2 phases.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (tdgbl->global_trans)
|
|
|
|
|
{
|
|
|
|
|
if (!gfld)
|
|
|
|
|
gfld = (GFLD) BURP_ALLOC_ZERO (sizeof (struct gfld));
|
|
|
|
|
|
|
|
|
|
get_misc_blob (&gfld->gfld_vs, 0, 1);
|
|
|
|
|
gfld->gfld_flags |= GFLD_validation_source;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
X.RDB$VALIDATION_SOURCE.NULL = FALSE;
|
|
|
|
|
get_misc_blob (&X.RDB$VALIDATION_SOURCE, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_validation_source2:
|
|
|
|
|
if (tdgbl->gbl_sw_novalidity)
|
|
|
|
|
eat_blob();
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* if we are going against a V4.0 database,
|
|
|
|
|
* restore the global fields in 2 phases.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (tdgbl->global_trans)
|
|
|
|
|
{
|
|
|
|
|
if (!gfld)
|
|
|
|
|
gfld = (GFLD) BURP_ALLOC_ZERO (sizeof (struct gfld));
|
|
|
|
|
|
|
|
|
|
get_source_blob (&gfld->gfld_vs2, 1);
|
|
|
|
|
gfld->gfld_flags |= GFLD_validation_source2;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
X.RDB$VALIDATION_SOURCE.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$VALIDATION_SOURCE, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_missing_value:
|
|
|
|
|
X.RDB$MISSING_VALUE.NULL = FALSE;
|
|
|
|
|
get_blr_blob (&X.RDB$MISSING_VALUE, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_default_value:
|
|
|
|
|
X.RDB$DEFAULT_VALUE.NULL = FALSE;
|
|
|
|
|
get_blr_blob (&X.RDB$DEFAULT_VALUE, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_system_flag:
|
|
|
|
|
X.RDB$SYSTEM_FLAG = (USHORT) get_numeric();
|
|
|
|
|
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_null_flag:
|
|
|
|
|
X.RDB$NULL_FLAG = (USHORT) get_numeric();
|
|
|
|
|
X.RDB$NULL_FLAG.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_description:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_misc_blob (&X.RDB$DESCRIPTION, 1, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_description2:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$DESCRIPTION, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_external_length:
|
|
|
|
|
X.RDB$EXTERNAL_LENGTH.NULL = FALSE;
|
|
|
|
|
X.RDB$EXTERNAL_LENGTH = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_external_scale:
|
|
|
|
|
X.RDB$EXTERNAL_SCALE.NULL = FALSE;
|
|
|
|
|
X.RDB$EXTERNAL_SCALE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_external_type:
|
|
|
|
|
X.RDB$EXTERNAL_TYPE.NULL = FALSE;
|
|
|
|
|
X.RDB$EXTERNAL_TYPE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_dimensions:
|
|
|
|
|
X.RDB$DIMENSIONS.NULL = FALSE;
|
|
|
|
|
X.RDB$DIMENSIONS = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_character_length:
|
|
|
|
|
X.RDB$CHARACTER_LENGTH.NULL = FALSE;
|
|
|
|
|
X.RDB$CHARACTER_LENGTH = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_default_source:
|
|
|
|
|
X.RDB$DEFAULT_SOURCE.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$DEFAULT_SOURCE, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_missing_source:
|
|
|
|
|
X.RDB$MISSING_SOURCE.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$MISSING_SOURCE, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_character_set:
|
|
|
|
|
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
|
|
|
|
|
X.RDB$CHARACTER_SET_ID = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_collation_id:
|
|
|
|
|
X.RDB$COLLATION_ID.NULL = FALSE;
|
|
|
|
|
X.RDB$COLLATION_ID = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_precision:
|
|
|
|
|
X.RDB$FIELD_PRECISION.NULL = FALSE;
|
|
|
|
|
X.RDB$FIELD_PRECISION = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 92); /* msg 92 global field */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (X.RDB$FIELD_TYPE <= DTYPE_BLR_MAX)
|
|
|
|
|
{
|
|
|
|
|
l = gds_cvt_blr_dtype [X.RDB$FIELD_TYPE];
|
|
|
|
|
if (l = type_lengths [l])
|
|
|
|
|
X.RDB$FIELD_LENGTH = l;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gfld)
|
|
|
|
|
strcpy (gfld->gfld_name, X.RDB$FIELD_NAME);
|
|
|
|
|
|
|
|
|
|
/* V3.3 used a different method from V4.0 for encoding International
|
|
|
|
|
* text character set & collation information. Here we are
|
|
|
|
|
* looking at the metadata information, deciding if it is
|
|
|
|
|
* the V3.3 method, and converting it to the V4.0 method so
|
|
|
|
|
* V3.3 customers can migrate their database to V4.0.
|
|
|
|
|
*/
|
|
|
|
|
save_subtype = X.RDB$FIELD_SUB_TYPE;
|
|
|
|
|
if (X.RDB$CHARACTER_SET_ID.NULL &&
|
|
|
|
|
X.RDB$COLLATION_ID.NULL &&
|
|
|
|
|
cvt_v3_to_v4_intl (X.RDB$FIELD_TYPE, &X.RDB$FIELD_SCALE,
|
|
|
|
|
&X.RDB$FIELD_SUB_TYPE, &X.RDB$CHARACTER_SET_ID,
|
|
|
|
|
&X.RDB$COLLATION_ID))
|
|
|
|
|
{
|
|
|
|
|
FLD f;
|
|
|
|
|
|
|
|
|
|
/* If some value was reset, set the NULL flag */
|
|
|
|
|
if (save_subtype && !X.RDB$FIELD_SUB_TYPE)
|
|
|
|
|
X.RDB$FIELD_SUB_TYPE.NULL = TRUE;
|
|
|
|
|
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
|
|
|
|
|
X.RDB$COLLATION_ID.NULL = FALSE;
|
|
|
|
|
|
|
|
|
|
/* Add an entry to the converted-field link list
|
|
|
|
|
* so we can also convert local fields based on this
|
|
|
|
|
* global field
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
f = (FLD) BURP_ALLOC_ZERO (sizeof(struct fld));
|
|
|
|
|
strcpy (f->fld_name, X.RDB$FIELD_NAME);
|
|
|
|
|
f->fld_sub_type = X.RDB$FIELD_SUB_TYPE;
|
|
|
|
|
f->fld_scale = X.RDB$FIELD_SCALE;
|
|
|
|
|
f->fld_character_set_id = X.RDB$CHARACTER_SET_ID;
|
|
|
|
|
f->fld_collation_id = X.RDB$COLLATION_ID;
|
|
|
|
|
f->fld_next = tdgbl->v3_cvt_fld_list;
|
|
|
|
|
tdgbl->v3_cvt_fld_list = f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else /* RESTORE_format < 6 */
|
|
|
|
|
{
|
|
|
|
|
/* without rdb$field_precision */
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_global_field_req_handle1)
|
|
|
|
|
X IN RDB$FIELDS
|
|
|
|
|
|
|
|
|
|
X.RDB$FIELD_SCALE = X.RDB$SEGMENT_LENGTH = 0;
|
|
|
|
|
X.RDB$CHARACTER_SET_ID = X.RDB$COLLATION_ID = 0;
|
|
|
|
|
X.RDB$FIELD_SUB_TYPE = 0;
|
|
|
|
|
X.RDB$COMPUTED_BLR.NULL = TRUE;
|
|
|
|
|
X.RDB$COMPUTED_SOURCE.NULL = TRUE;
|
|
|
|
|
X.RDB$QUERY_NAME.NULL = TRUE;
|
|
|
|
|
X.RDB$EDIT_STRING.NULL = TRUE;
|
|
|
|
|
X.RDB$QUERY_HEADER.NULL = TRUE;
|
|
|
|
|
X.RDB$MISSING_VALUE.NULL = TRUE;
|
|
|
|
|
X.RDB$DEFAULT_VALUE.NULL = TRUE;
|
|
|
|
|
X.RDB$VALIDATION_BLR.NULL = TRUE;
|
|
|
|
|
X.RDB$VALIDATION_SOURCE.NULL = TRUE;
|
|
|
|
|
X.RDB$SYSTEM_FLAG.NULL = TRUE;
|
|
|
|
|
X.RDB$NULL_FLAG.NULL = TRUE;
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = TRUE;
|
|
|
|
|
X.RDB$DIMENSIONS.NULL = TRUE;
|
|
|
|
|
X.RDB$EXTERNAL_LENGTH.NULL = TRUE;
|
|
|
|
|
X.RDB$EXTERNAL_TYPE.NULL = TRUE;
|
|
|
|
|
X.RDB$EXTERNAL_SCALE.NULL = TRUE;
|
|
|
|
|
X.RDB$SEGMENT_LENGTH.NULL = TRUE;
|
|
|
|
|
X.RDB$CHARACTER_LENGTH.NULL = TRUE;
|
|
|
|
|
X.RDB$MISSING_SOURCE.NULL = TRUE;
|
|
|
|
|
X.RDB$DEFAULT_SOURCE.NULL = TRUE;
|
|
|
|
|
X.RDB$FIELD_SUB_TYPE.NULL = TRUE;
|
|
|
|
|
X.RDB$CHARACTER_SET_ID.NULL = TRUE;
|
|
|
|
|
X.RDB$COLLATION_ID.NULL = TRUE;
|
|
|
|
|
|
|
|
|
|
memset (X.RDB$QUERY_NAME, ' ', sizeof (X.RDB$QUERY_NAME));
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_field_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
l = GET_TEXT(X.RDB$FIELD_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
MISC_terminate ((UCHAR*) X.RDB$FIELD_NAME, (UCHAR*) temp, l, sizeof (temp));
|
|
|
|
|
BURP_verbose (121, temp, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 121 restoring global field %s */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_query_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$QUERY_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
X.RDB$QUERY_NAME.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_edit_string:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$EDIT_STRING);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
X.RDB$EDIT_STRING.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_query_header:
|
|
|
|
|
X.RDB$QUERY_HEADER.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$QUERY_HEADER, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_type:
|
|
|
|
|
X.RDB$FIELD_TYPE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_length:
|
|
|
|
|
X.RDB$FIELD_LENGTH = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_scale:
|
|
|
|
|
X.RDB$FIELD_SCALE = (USHORT) get_numeric();
|
|
|
|
|
X.RDB$FIELD_SCALE.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_sub_type:
|
|
|
|
|
X.RDB$FIELD_SUB_TYPE = (USHORT) get_numeric();
|
|
|
|
|
X.RDB$FIELD_SUB_TYPE.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_segment_length:
|
|
|
|
|
X.RDB$SEGMENT_LENGTH = (USHORT) get_numeric();
|
|
|
|
|
if (X.RDB$SEGMENT_LENGTH)
|
|
|
|
|
X.RDB$SEGMENT_LENGTH.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_computed_blr:
|
|
|
|
|
X.RDB$COMPUTED_BLR.NULL = FALSE;
|
|
|
|
|
get_blr_blob (&X.RDB$COMPUTED_BLR, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_computed_source:
|
|
|
|
|
X.RDB$COMPUTED_SOURCE.NULL = FALSE;
|
|
|
|
|
get_misc_blob (&X.RDB$COMPUTED_SOURCE, 1, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_computed_source2:
|
|
|
|
|
X.RDB$COMPUTED_SOURCE.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$COMPUTED_SOURCE, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_validation_blr:
|
|
|
|
|
if (tdgbl->gbl_sw_novalidity)
|
|
|
|
|
eat_blob();
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* if we are going against a V4.0 database,
|
|
|
|
|
* restore the global fields in 2 phases.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (tdgbl->global_trans)
|
|
|
|
|
{
|
|
|
|
|
if (!gfld)
|
|
|
|
|
gfld = (GFLD) BURP_ALLOC_ZERO (sizeof (struct gfld));
|
|
|
|
|
|
|
|
|
|
get_blr_blob (&gfld->gfld_vb, 1);
|
|
|
|
|
gfld->gfld_flags |= GFLD_validation_blr;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
X.RDB$VALIDATION_BLR.NULL = FALSE;
|
|
|
|
|
get_blr_blob (&X.RDB$VALIDATION_BLR, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_validation_source:
|
|
|
|
|
if (tdgbl->gbl_sw_novalidity)
|
|
|
|
|
eat_blob();
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* if we are going against a V4.0 database,
|
|
|
|
|
* restore the global fields in 2 phases.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (tdgbl->global_trans)
|
|
|
|
|
{
|
|
|
|
|
if (!gfld)
|
|
|
|
|
gfld = (GFLD) BURP_ALLOC_ZERO (sizeof (struct gfld));
|
|
|
|
|
|
|
|
|
|
get_misc_blob (&gfld->gfld_vs, 0, 1);
|
|
|
|
|
gfld->gfld_flags |= GFLD_validation_source;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
X.RDB$VALIDATION_SOURCE.NULL = FALSE;
|
|
|
|
|
get_misc_blob (&X.RDB$VALIDATION_SOURCE, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_validation_source2:
|
|
|
|
|
if (tdgbl->gbl_sw_novalidity)
|
|
|
|
|
eat_blob();
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* if we are going against a V4.0 database,
|
|
|
|
|
* restore the global fields in 2 phases.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (tdgbl->global_trans)
|
|
|
|
|
{
|
|
|
|
|
if (!gfld)
|
|
|
|
|
gfld = (GFLD) BURP_ALLOC_ZERO (sizeof (struct gfld));
|
|
|
|
|
|
|
|
|
|
get_source_blob (&gfld->gfld_vs2, 1);
|
|
|
|
|
gfld->gfld_flags |= GFLD_validation_source2;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
X.RDB$VALIDATION_SOURCE.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$VALIDATION_SOURCE, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_missing_value:
|
|
|
|
|
X.RDB$MISSING_VALUE.NULL = FALSE;
|
|
|
|
|
get_blr_blob (&X.RDB$MISSING_VALUE, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_default_value:
|
|
|
|
|
X.RDB$DEFAULT_VALUE.NULL = FALSE;
|
|
|
|
|
get_blr_blob (&X.RDB$DEFAULT_VALUE, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_system_flag:
|
|
|
|
|
X.RDB$SYSTEM_FLAG = (USHORT) get_numeric();
|
|
|
|
|
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_null_flag:
|
|
|
|
|
X.RDB$NULL_FLAG = (USHORT) get_numeric();
|
|
|
|
|
X.RDB$NULL_FLAG.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_description:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_misc_blob (&X.RDB$DESCRIPTION, 1, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_description2:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$DESCRIPTION, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_external_length:
|
|
|
|
|
X.RDB$EXTERNAL_LENGTH.NULL = FALSE;
|
|
|
|
|
X.RDB$EXTERNAL_LENGTH = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_external_scale:
|
|
|
|
|
X.RDB$EXTERNAL_SCALE.NULL = FALSE;
|
|
|
|
|
X.RDB$EXTERNAL_SCALE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_external_type:
|
|
|
|
|
X.RDB$EXTERNAL_TYPE.NULL = FALSE;
|
|
|
|
|
X.RDB$EXTERNAL_TYPE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_dimensions:
|
|
|
|
|
X.RDB$DIMENSIONS.NULL = FALSE;
|
|
|
|
|
X.RDB$DIMENSIONS = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_character_length:
|
|
|
|
|
X.RDB$CHARACTER_LENGTH.NULL = FALSE;
|
|
|
|
|
X.RDB$CHARACTER_LENGTH = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_default_source:
|
|
|
|
|
X.RDB$DEFAULT_SOURCE.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$DEFAULT_SOURCE, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_missing_source:
|
|
|
|
|
X.RDB$MISSING_SOURCE.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$MISSING_SOURCE, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_character_set:
|
|
|
|
|
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
|
|
|
|
|
X.RDB$CHARACTER_SET_ID = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_field_collation_id:
|
|
|
|
|
X.RDB$COLLATION_ID.NULL = FALSE;
|
|
|
|
|
X.RDB$COLLATION_ID = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 92); /* msg 92 global field */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (X.RDB$FIELD_TYPE <= DTYPE_BLR_MAX)
|
|
|
|
|
{
|
|
|
|
|
l = gds_cvt_blr_dtype [X.RDB$FIELD_TYPE];
|
|
|
|
|
if (l = type_lengths [l])
|
|
|
|
|
X.RDB$FIELD_LENGTH = l;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gfld)
|
|
|
|
|
strcpy (gfld->gfld_name, X.RDB$FIELD_NAME);
|
|
|
|
|
|
|
|
|
|
/* V3.3 used a different method from V4.0 for encoding International
|
|
|
|
|
* text character set & collation information. Here we are
|
|
|
|
|
* looking at the metadata information, deciding if it is
|
|
|
|
|
* the V3.3 method, and converting it to the V4.0 method so
|
|
|
|
|
* V3.3 customers can migrate their database to V4.0.
|
|
|
|
|
*/
|
|
|
|
|
save_subtype = X.RDB$FIELD_SUB_TYPE;
|
|
|
|
|
if (X.RDB$CHARACTER_SET_ID.NULL &&
|
|
|
|
|
X.RDB$COLLATION_ID.NULL &&
|
|
|
|
|
cvt_v3_to_v4_intl (X.RDB$FIELD_TYPE, &X.RDB$FIELD_SCALE,
|
|
|
|
|
&X.RDB$FIELD_SUB_TYPE, &X.RDB$CHARACTER_SET_ID,
|
|
|
|
|
&X.RDB$COLLATION_ID))
|
|
|
|
|
{
|
|
|
|
|
FLD f;
|
|
|
|
|
|
|
|
|
|
/* If some value was reset, set the NULL flag */
|
|
|
|
|
if (save_subtype && !X.RDB$FIELD_SUB_TYPE)
|
|
|
|
|
X.RDB$FIELD_SUB_TYPE.NULL = TRUE;
|
|
|
|
|
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
|
|
|
|
|
X.RDB$COLLATION_ID.NULL = FALSE;
|
|
|
|
|
|
|
|
|
|
/* Add an entry to the converted-field link list
|
|
|
|
|
* so we can also convert local fields based on this
|
|
|
|
|
* global field
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
f = (FLD) BURP_ALLOC_ZERO (sizeof(struct fld));
|
|
|
|
|
strcpy (f->fld_name, X.RDB$FIELD_NAME);
|
|
|
|
|
f->fld_sub_type = X.RDB$FIELD_SUB_TYPE;
|
|
|
|
|
f->fld_scale = X.RDB$FIELD_SCALE;
|
|
|
|
|
f->fld_character_set_id = X.RDB$CHARACTER_SET_ID;
|
|
|
|
|
f->fld_collation_id = X.RDB$COLLATION_ID;
|
|
|
|
|
f->fld_next = tdgbl->v3_cvt_fld_list;
|
|
|
|
|
tdgbl->v3_cvt_fld_list = f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if (gfld)
|
|
|
|
|
{
|
|
|
|
|
gfld->gfld_next = tdgbl->gbl_global_fields;
|
|
|
|
|
tdgbl->gbl_global_fields = gfld;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_index (
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_REL relation)
|
2001-07-12 08:32:05 +02:00
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ i n d e x
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Build an index. At the end stop
|
|
|
|
|
* and check that all fields are defined.
|
|
|
|
|
* If any fields are missing, delete the
|
|
|
|
|
* index.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
SSHORT count, segments;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
BOOLEAN foreign_index = FALSE;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
count = segments = 0;
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_index_req_handle1)
|
|
|
|
|
X IN RDB$INDICES
|
|
|
|
|
strcpy (X.RDB$RELATION_NAME, relation->rel_name);
|
|
|
|
|
X.RDB$UNIQUE_FLAG = 0;
|
|
|
|
|
if (!tdgbl->gbl_sw_deactivate_indexes)
|
|
|
|
|
X.RDB$INDEX_INACTIVE = FALSE;
|
|
|
|
|
else
|
|
|
|
|
X.RDB$INDEX_INACTIVE = TRUE;
|
|
|
|
|
X.RDB$INDEX_TYPE.NULL = TRUE;
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = TRUE;
|
|
|
|
|
X.RDB$FOREIGN_KEY.NULL = TRUE;
|
|
|
|
|
X.RDB$EXPRESSION_SOURCE.NULL = TRUE;
|
|
|
|
|
X.RDB$EXPRESSION_BLR.NULL = TRUE;
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_index_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$INDEX_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
strcpy (index_name, X.RDB$INDEX_NAME);
|
|
|
|
|
BURP_verbose (122, X.RDB$INDEX_NAME, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_segment_count:
|
|
|
|
|
X.RDB$SEGMENT_COUNT = segments = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_index_unique_flag:
|
|
|
|
|
X.RDB$UNIQUE_FLAG = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_index_inactive:
|
|
|
|
|
X.RDB$INDEX_INACTIVE = (USHORT) get_numeric();
|
|
|
|
|
/* Defer foreign key index activation */
|
|
|
|
|
/* Modified by Toni Martir, all index deferred when verbose */
|
|
|
|
|
if (tdgbl->gbl_sw_verbose)
|
|
|
|
|
{
|
|
|
|
|
if (X.RDB$INDEX_INACTIVE == FALSE)
|
|
|
|
|
X.RDB$INDEX_INACTIVE = DEFERRED_ACTIVE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (X.RDB$INDEX_INACTIVE == FALSE && foreign_index)
|
|
|
|
|
X.RDB$INDEX_INACTIVE = DEFERRED_ACTIVE;
|
|
|
|
|
}
|
|
|
|
|
if (tdgbl->gbl_sw_deactivate_indexes)
|
|
|
|
|
X.RDB$INDEX_INACTIVE = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_index_type:
|
|
|
|
|
X.RDB$INDEX_TYPE.NULL = FALSE;
|
|
|
|
|
X.RDB$INDEX_TYPE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_index_field_name:
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_index_req_handle2)
|
|
|
|
|
Y IN RDB$INDEX_SEGMENTS
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(Y.RDB$FIELD_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
strcpy (Y.RDB$INDEX_NAME, X.RDB$INDEX_NAME);
|
|
|
|
|
Y.RDB$FIELD_POSITION = count++;
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_index_description:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_misc_blob (&X.RDB$DESCRIPTION, 0, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_index_description2:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$DESCRIPTION, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_index_expression_source:
|
|
|
|
|
X.RDB$EXPRESSION_SOURCE.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$EXPRESSION_SOURCE, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_index_expression_blr:
|
|
|
|
|
X.RDB$EXPRESSION_BLR.NULL = FALSE;
|
|
|
|
|
get_blr_blob (&X.RDB$EXPRESSION_BLR, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_index_foreign_key:
|
|
|
|
|
/* BUG 8183: For more information see description of */
|
|
|
|
|
/* "bug_8183" function below. */
|
|
|
|
|
/* Note: ATT_BACKUP_FORMAT for IB3.3 is equal 4 */
|
|
|
|
|
if ( (tdgbl->RESTORE_format <= 4) &&
|
|
|
|
|
(tdgbl->gbl_sw_bug8183 || bug_8183(tdgbl)) )
|
|
|
|
|
{
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$DESCRIPTION, 0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
foreign_index = TRUE;
|
|
|
|
|
/* Defer foreign key index activation */
|
|
|
|
|
if (X.RDB$INDEX_INACTIVE == FALSE)
|
|
|
|
|
X.RDB$INDEX_INACTIVE = DEFERRED_ACTIVE;
|
|
|
|
|
if (tdgbl->gbl_sw_deactivate_indexes)
|
|
|
|
|
X.RDB$INDEX_INACTIVE = TRUE;
|
|
|
|
|
X.RDB$FOREIGN_KEY.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$FOREIGN_KEY);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 93);
|
|
|
|
|
/* msg 93 index */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
count = 0;
|
|
|
|
|
FOR (REQUEST_HANDLE tdgbl->handles_get_index_req_handle3)
|
|
|
|
|
RFR IN RDB$RELATION_FIELDS CROSS I_S IN RDB$INDEX_SEGMENTS
|
|
|
|
|
OVER RDB$FIELD_NAME WITH I_S.RDB$INDEX_NAME = index_name AND
|
|
|
|
|
RFR.RDB$RELATION_NAME = relation->rel_name
|
|
|
|
|
count++;
|
|
|
|
|
END_FOR;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
if (count != segments)
|
|
|
|
|
{
|
|
|
|
|
FOR (REQUEST_HANDLE tdgbl->handles_get_index_req_handle4)
|
|
|
|
|
I_S IN RDB$INDEX_SEGMENTS WITH I_S.RDB$INDEX_NAME = index_name
|
|
|
|
|
ERASE I_S;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
END_FOR;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void get_misc_blob (
|
|
|
|
|
ISC_QUAD *blob_id,
|
|
|
|
|
USHORT sub_type,
|
|
|
|
|
USHORT glb_trans)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ m i s c _ b l o b
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Read blob attributes and copy data from input file to nice,
|
|
|
|
|
* shiney, new blob.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
2002-10-24 11:01:44 +02:00
|
|
|
|
STATUS status_vector[ISC_STATUS_LENGTH];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
SLONG *blob;
|
|
|
|
|
USHORT length;
|
|
|
|
|
UCHAR *buffer, static_buffer [1024];
|
|
|
|
|
USHORT bpb_length;
|
|
|
|
|
UCHAR *bpb;
|
|
|
|
|
isc_tr_handle local_trans;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
length = (USHORT)get_numeric();
|
|
|
|
|
|
|
|
|
|
/* Create new blob */
|
|
|
|
|
|
|
|
|
|
blob = NULL;
|
|
|
|
|
|
|
|
|
|
bpb_length = 0;
|
|
|
|
|
bpb = NULL;
|
|
|
|
|
|
|
|
|
|
if (glb_trans && tdgbl->global_trans)
|
|
|
|
|
local_trans = tdgbl->global_trans;
|
|
|
|
|
else
|
|
|
|
|
local_trans = gds_trans;
|
|
|
|
|
|
|
|
|
|
if (isc_create_blob2 (status_vector,
|
|
|
|
|
GDS_REF (tdgbl->db_handle),
|
|
|
|
|
GDS_REF (local_trans),
|
|
|
|
|
(void**) GDS_REF (blob),
|
|
|
|
|
GDS_VAL (blob_id),
|
|
|
|
|
bpb_length,
|
|
|
|
|
(SCHAR*) bpb))
|
|
|
|
|
BURP_error_redirect (status_vector, 37, 0, 0);
|
|
|
|
|
/* msg 37 gds__create_blob failed */
|
|
|
|
|
|
|
|
|
|
/* Allocate blob buffer is static buffer is too short */
|
|
|
|
|
|
2002-04-04 07:32:02 +02:00
|
|
|
|
if (!length || length <= (USHORT)(sizeof (static_buffer)) )
|
2001-07-12 08:32:05 +02:00
|
|
|
|
buffer = static_buffer;
|
|
|
|
|
else
|
|
|
|
|
buffer = BURP_ALLOC (length);
|
|
|
|
|
|
|
|
|
|
if (length)
|
|
|
|
|
{
|
|
|
|
|
(void) GET_BLOCK (buffer, length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isc_put_segment (status_vector,
|
|
|
|
|
(void**) GDS_REF (blob),
|
|
|
|
|
length,
|
|
|
|
|
(SCHAR*) GDS_VAL (buffer)))
|
|
|
|
|
BURP_error_redirect (status_vector, 38, 0, 0);
|
|
|
|
|
/* msg 38 gds__put_segment failed */
|
|
|
|
|
|
|
|
|
|
if (isc_close_blob (status_vector, (void**) GDS_REF (blob)))
|
|
|
|
|
BURP_error_redirect (status_vector, 23, 0, 0);
|
|
|
|
|
/* msg 23 gds__close_blob failed */
|
|
|
|
|
|
|
|
|
|
if (buffer != static_buffer)
|
|
|
|
|
BURP_FREE (buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static SLONG get_numeric (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ n u m e r i c
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Get a numeric value from the input stream.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
2001-12-24 03:51:06 +01:00
|
|
|
|
SLONG value[2];
|
|
|
|
|
|
|
|
|
|
// get_text needs additional space for the terminator,
|
|
|
|
|
// because it treats everything as strings.
|
|
|
|
|
assert(sizeof(value) > sizeof(SLONG));
|
2001-07-12 08:32:05 +02:00
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
|
SSHORT length = get_text((TEXT*) value, sizeof (value));
|
2001-07-12 08:32:05 +02:00
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
|
return isc_vax_integer ((SCHAR *) value, length);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static SINT64 get_int64 (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ i n t 6 4
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Get a possibly-64-bit numeric value from the input stream.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
2001-12-24 03:51:06 +01:00
|
|
|
|
SLONG value [4];
|
|
|
|
|
|
|
|
|
|
// get_text needs additional space for the terminator,
|
|
|
|
|
// because it treats everything as strings.
|
|
|
|
|
assert (sizeof(value) > sizeof(SINT64));
|
2001-07-12 08:32:05 +02:00
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
|
SSHORT length = get_text ((TEXT *) value, sizeof (value));
|
2001-07-12 08:32:05 +02:00
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
|
return isc_portable_integer ((UCHAR *) value, length);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_procedure (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ p r o c e d u r e
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Reconstruct a stored procedure.
|
|
|
|
|
* Use the global_trans so we don't have to commit
|
|
|
|
|
* until after the indices are activated. This
|
|
|
|
|
* will allow us to use a PLAN in a SP.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
GDS_NAME procedure_name;
|
2002-06-29 07:39:38 +02:00
|
|
|
|
TEXT temp [GDS_NAME_LEN];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
SSHORT l;
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_PRC procedure;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
isc_tr_handle local_trans;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans;
|
|
|
|
|
|
2002-11-21 00:18:16 +01:00
|
|
|
|
procedure = (BURP_PRC) BURP_ALLOC_ZERO (sizeof (struct burp_prc));
|
2001-07-12 08:32:05 +02:00
|
|
|
|
procedure->prc_next = tdgbl->procedures;
|
|
|
|
|
tdgbl->procedures = procedure;
|
|
|
|
|
|
|
|
|
|
STORE (TRANSACTION_HANDLE local_trans
|
|
|
|
|
REQUEST_HANDLE tdgbl->handles_get_procedure_req_handle1)
|
|
|
|
|
X IN RDB$PROCEDURES
|
|
|
|
|
X.RDB$PROCEDURE_SOURCE.NULL = TRUE;
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = TRUE;
|
|
|
|
|
X.RDB$SECURITY_CLASS.NULL = TRUE;
|
|
|
|
|
X.RDB$OWNER_NAME.NULL = TRUE;
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_procedure_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
l = GET_TEXT(X.RDB$PROCEDURE_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
procedure->prc_name_length = l;
|
|
|
|
|
strcpy (procedure->prc_name, X.RDB$PROCEDURE_NAME);
|
|
|
|
|
MISC_terminate ((UCHAR*) X.RDB$PROCEDURE_NAME, (UCHAR*) temp, l, sizeof (temp));
|
|
|
|
|
BURP_verbose (195, temp, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 195 restoring stored procedure %s */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_procedure_description:
|
|
|
|
|
get_misc_blob (&X.RDB$DESCRIPTION, 0, 1);
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_procedure_description2:
|
|
|
|
|
get_source_blob (&X.RDB$DESCRIPTION, 1);
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_procedure_source:
|
|
|
|
|
get_misc_blob (&X.RDB$PROCEDURE_SOURCE, 0, 1);
|
|
|
|
|
X.RDB$PROCEDURE_SOURCE.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_procedure_source2:
|
|
|
|
|
get_source_blob (&X.RDB$PROCEDURE_SOURCE, 1);
|
|
|
|
|
X.RDB$PROCEDURE_SOURCE.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_procedure_blr:
|
|
|
|
|
get_blr_blob (&X.RDB$PROCEDURE_BLR, 1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_procedure_security_class:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$SECURITY_CLASS);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
X.RDB$SECURITY_CLASS.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_procedure_owner_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(procedure->prc_owner);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_procedure_inputs:
|
|
|
|
|
X.RDB$PROCEDURE_INPUTS = (USHORT) get_numeric();
|
|
|
|
|
if (X.RDB$PROCEDURE_INPUTS == 0)
|
|
|
|
|
X.RDB$PROCEDURE_INPUTS.NULL = TRUE;
|
|
|
|
|
else
|
|
|
|
|
X.RDB$PROCEDURE_INPUTS.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_procedure_outputs:
|
|
|
|
|
X.RDB$PROCEDURE_OUTPUTS = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 89);
|
|
|
|
|
/* msg 89 function */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
strcpy (procedure_name, X.RDB$PROCEDURE_NAME);
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
/* at the end of prms for a procedure is the rec_procedure_end marker */
|
|
|
|
|
|
|
|
|
|
while (GET () == rec_procedure_prm)
|
|
|
|
|
get_procedure_prm (procedure_name);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_procedure_prm (
|
|
|
|
|
GDS_NAME procptr)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ p r o c e d u r e _ p r m
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Reconstruct stored procedure parameter.
|
|
|
|
|
* Use the global_trans so we don't have to commit
|
|
|
|
|
* until after the indices are activated. This
|
|
|
|
|
* will allow us to use a PLAN in a SP.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
SSHORT l;
|
2002-06-29 07:39:38 +02:00
|
|
|
|
TEXT temp [GDS_NAME_LEN];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
isc_tr_handle local_trans;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans;
|
|
|
|
|
|
|
|
|
|
STORE (TRANSACTION_HANDLE local_trans
|
|
|
|
|
REQUEST_HANDLE tdgbl->handles_get_procedure_prm_req_handle1)
|
|
|
|
|
X IN RDB$PROCEDURE_PARAMETERS
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = TRUE;
|
|
|
|
|
strcpy (X.RDB$PROCEDURE_NAME, procptr);
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_procedureprm_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
l = GET_TEXT(X.RDB$PARAMETER_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
MISC_terminate ((UCHAR*) X.RDB$PARAMETER_NAME, (UCHAR*) temp, l, sizeof (temp));
|
|
|
|
|
BURP_verbose (196, temp, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 196 restoring parameter %s for stored procedure */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_procedureprm_type:
|
|
|
|
|
X.RDB$PARAMETER_TYPE= (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_procedureprm_number:
|
|
|
|
|
X.RDB$PARAMETER_NUMBER= (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_procedureprm_field_source:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$FIELD_SOURCE);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_procedureprm_description:
|
|
|
|
|
get_misc_blob (&X.RDB$DESCRIPTION, 0, 1);
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_procedureprm_description2:
|
|
|
|
|
get_source_blob (&X.RDB$DESCRIPTION, 1);
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 90);
|
|
|
|
|
/* msg 90 function argument */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_ref_constraint (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ r e f _ c o n s t r a i n t
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Restore data for referential constraints.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_ref_constraint_req_handle1)
|
|
|
|
|
X IN RDB$REF_CONSTRAINTS
|
|
|
|
|
X.RDB$CONSTRAINT_NAME.NULL = TRUE;
|
|
|
|
|
X.RDB$CONST_NAME_UQ.NULL = TRUE;
|
|
|
|
|
X.RDB$MATCH_OPTION.NULL = TRUE;
|
|
|
|
|
X.RDB$UPDATE_RULE.NULL = TRUE;
|
|
|
|
|
X.RDB$DELETE_RULE.NULL = TRUE;
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_ref_constraint_name:
|
|
|
|
|
X.RDB$CONSTRAINT_NAME.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$CONSTRAINT_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_ref_unique_const_name:
|
|
|
|
|
X.RDB$CONST_NAME_UQ.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$CONST_NAME_UQ);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_ref_match_option:
|
|
|
|
|
X.RDB$MATCH_OPTION.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$MATCH_OPTION);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_ref_update_rule:
|
|
|
|
|
X.RDB$UPDATE_RULE.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$UPDATE_RULE);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_ref_delete_rule:
|
|
|
|
|
X.RDB$DELETE_RULE.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$DELETE_RULE);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 208);
|
|
|
|
|
/* msg 208 relation constraint */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_relation (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ r e l a t i o n
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Write relation meta-data and data.
|
|
|
|
|
* Use the default transaction for RELATIONS,
|
|
|
|
|
* and use the global_trans for VIEWS. This
|
|
|
|
|
* enables us to have views of SP and views
|
|
|
|
|
* with plans. Assume it is a view if it has
|
|
|
|
|
* RDB$VIEW_BLR, also assume RDB$VIEW_BLR is
|
|
|
|
|
* the first blob in the backup file.
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_REL relation;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
FLD field, *ptr;
|
2002-06-29 07:39:38 +02:00
|
|
|
|
TEXT temp [GDS_NAME_LEN];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
SSHORT l;
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
REC_TYPE record;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
2002-10-22 10:05:57 +02:00
|
|
|
|
SLONG rel_flags = 0, sys_flag = 0;
|
|
|
|
|
short rel_flags_null = TRUE, sys_flag_null = TRUE;
|
|
|
|
|
GDS_QUAD view_blr = isc_blob_null, view_src = isc_blob_null, rel_desc = isc_blob_null, ext_desc = isc_blob_null;
|
|
|
|
|
USHORT view_blr_null = TRUE, view_src_null = TRUE, rel_desc_null = TRUE, ext_desc_null = TRUE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
|
|
|
|
|
BASED_ON RDB$RELATIONS.RDB$SECURITY_CLASS sec_class;
|
2002-10-22 10:05:57 +02:00
|
|
|
|
short sec_class_null = TRUE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
|
|
|
|
|
BASED_ON RDB$RELATIONS.RDB$EXTERNAL_FILE ext_file_name;
|
2002-10-22 10:05:57 +02:00
|
|
|
|
short ext_file_name_null = TRUE;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
|
|
|
|
|
isc_tr_handle local_trans;
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
/* Pick up relation attributes */
|
|
|
|
|
|
2002-11-21 00:18:16 +01:00
|
|
|
|
relation = (BURP_REL) BURP_ALLOC_ZERO (sizeof (struct burp_rel));
|
2001-07-12 08:32:05 +02:00
|
|
|
|
relation->rel_next = tdgbl->relations;
|
|
|
|
|
tdgbl->relations = relation;
|
|
|
|
|
|
|
|
|
|
sec_class[0] = '\0';
|
|
|
|
|
ext_file_name[0] = '\0';
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_relation_req_handle1)
|
|
|
|
|
X IN RDB$RELATIONS
|
|
|
|
|
X.RDB$SYSTEM_FLAG.NULL = TRUE;
|
|
|
|
|
X.RDB$FLAGS.NULL = TRUE;
|
|
|
|
|
X.RDB$SECURITY_CLASS.NULL = TRUE;
|
|
|
|
|
X.RDB$VIEW_BLR.NULL = TRUE;
|
|
|
|
|
X.RDB$VIEW_SOURCE.NULL = TRUE;
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = TRUE;
|
|
|
|
|
X.RDB$RUNTIME.NULL = TRUE;
|
|
|
|
|
X.RDB$EXTERNAL_DESCRIPTION.NULL = TRUE;
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_relation_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
l = GET_TEXT(relation->rel_name);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
relation->rel_name_length = l;
|
|
|
|
|
MISC_terminate ((UCHAR*) relation->rel_name, (UCHAR*) temp, l, sizeof (temp));
|
|
|
|
|
BURP_verbose (167, temp, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 167 restoring relation %s */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_relation_security_class:
|
|
|
|
|
sec_class_null = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(sec_class);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_relation_view_blr:
|
|
|
|
|
view_blr_null = FALSE;
|
|
|
|
|
get_blr_blob(&view_blr, 1);
|
|
|
|
|
relation->rel_flags |= REL_view;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_relation_view_source:
|
|
|
|
|
view_src_null = FALSE;
|
|
|
|
|
get_misc_blob (&view_src, 1, (USHORT) !view_blr_null);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_relation_view_source2:
|
|
|
|
|
view_src_null = FALSE;
|
|
|
|
|
get_source_blob(&view_src, (USHORT) !view_blr_null);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_relation_description:
|
|
|
|
|
rel_desc_null = FALSE;
|
|
|
|
|
get_misc_blob(&rel_desc, 1, (USHORT) !view_blr_null);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_relation_description2:
|
|
|
|
|
rel_desc_null = FALSE;
|
|
|
|
|
get_source_blob(&rel_desc, (USHORT) !view_blr_null);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case att_relation_flags:
|
|
|
|
|
rel_flags_null = FALSE;
|
|
|
|
|
rel_flags = get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_relation_system_flag:
|
|
|
|
|
sys_flag_null = FALSE;
|
|
|
|
|
sys_flag = get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_relation_ext_description:
|
|
|
|
|
ext_desc_null = FALSE;
|
|
|
|
|
get_misc_blob(&ext_desc, 1, (USHORT) !view_blr_null);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_relation_ext_description2:
|
|
|
|
|
ext_desc_null = FALSE;
|
|
|
|
|
get_source_blob(&ext_desc, (USHORT) !view_blr_null);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_relation_owner_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(relation->rel_owner);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_relation_ext_file_name:
|
|
|
|
|
ext_file_name_null = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(ext_file_name);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 111);
|
|
|
|
|
/* msg 111 relation */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If this is a view and there is a global transaction then use it */
|
|
|
|
|
|
|
|
|
|
if (view_blr_null || !tdgbl->global_trans)
|
|
|
|
|
local_trans = gds_trans;
|
|
|
|
|
else
|
|
|
|
|
local_trans = tdgbl->global_trans;
|
|
|
|
|
|
|
|
|
|
STORE (TRANSACTION_HANDLE local_trans
|
|
|
|
|
REQUEST_HANDLE tdgbl->handles_get_relation_req_handle1)
|
|
|
|
|
X IN RDB$RELATIONS
|
|
|
|
|
|
|
|
|
|
X.RDB$SYSTEM_FLAG.NULL = sys_flag_null;
|
|
|
|
|
X.RDB$FLAGS.NULL = rel_flags_null;
|
|
|
|
|
X.RDB$SECURITY_CLASS.NULL = sec_class_null;
|
|
|
|
|
X.RDB$VIEW_BLR.NULL = view_blr_null;
|
|
|
|
|
X.RDB$VIEW_SOURCE.NULL = view_src_null;
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = rel_desc_null;
|
|
|
|
|
X.RDB$RUNTIME.NULL = TRUE;
|
|
|
|
|
X.RDB$EXTERNAL_DESCRIPTION.NULL = ext_desc_null;
|
|
|
|
|
X.RDB$EXTERNAL_FILE.NULL = ext_file_name_null;
|
|
|
|
|
|
|
|
|
|
X.RDB$SYSTEM_FLAG = (USHORT) sys_flag;
|
|
|
|
|
X.RDB$FLAGS = (USHORT) rel_flags;
|
|
|
|
|
X.RDB$VIEW_BLR = view_blr;
|
|
|
|
|
X.RDB$VIEW_SOURCE = view_src;
|
|
|
|
|
X.RDB$DESCRIPTION = rel_desc;
|
|
|
|
|
X.RDB$EXTERNAL_DESCRIPTION = ext_desc;
|
|
|
|
|
|
|
|
|
|
strcpy(X.RDB$SECURITY_CLASS, sec_class);
|
|
|
|
|
strcpy(X.RDB$RELATION_NAME, relation->rel_name);
|
|
|
|
|
strcpy(X.RDB$EXTERNAL_FILE, ext_file_name);
|
|
|
|
|
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
/* Eat up misc. records */
|
|
|
|
|
ptr = &relation->rel_fields;
|
|
|
|
|
|
|
|
|
|
while (GET_RECORD (record) != rec_data)
|
|
|
|
|
switch (record)
|
|
|
|
|
{
|
|
|
|
|
case rec_relation_end:
|
|
|
|
|
if (tdgbl->gbl_sw_incremental)
|
|
|
|
|
{
|
|
|
|
|
BURP_verbose (170, relation->rel_name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 170: committing metadata for relation %s */
|
|
|
|
|
COMMIT
|
|
|
|
|
/* existing ON_ERROR continues past error, beck */
|
|
|
|
|
ON_ERROR
|
|
|
|
|
BURP_print (171, relation->rel_name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 171: error committing metadata for relation %s */
|
|
|
|
|
BURP_print_status (tdgbl->status_vector);
|
|
|
|
|
ROLLBACK;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
END_ERROR;
|
|
|
|
|
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
|
|
|
|
|
if (gds_status [1])
|
|
|
|
|
EXEC SQL SET TRANSACTION;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
case rec_field:
|
|
|
|
|
*ptr = field = get_field (relation);
|
|
|
|
|
if (!field)
|
|
|
|
|
return FALSE;
|
|
|
|
|
ptr = &field->fld_next;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_view:
|
|
|
|
|
get_view (relation);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
#ifdef SUPERSERVER
|
2001-12-24 03:51:06 +01:00
|
|
|
|
BURP_svc_error (43, isc_arg_number, (void*) record,
|
2001-07-12 08:32:05 +02:00
|
|
|
|
0, NULL, 0, NULL, 0, NULL, 0, NULL);
|
|
|
|
|
#else
|
|
|
|
|
BURP_error (43, (void*) record, 0, 0, 0, 0);
|
|
|
|
|
/* msg 43 don't recognize record type %ld */
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we fall thru, there are data records to be gotten */
|
|
|
|
|
/* we can get here only when restoring ancient gbak'ed files where rec_data
|
|
|
|
|
was once embedded into rec_relation ... otherwise, meta commit happens
|
|
|
|
|
when we see the first rec_relation_data */
|
|
|
|
|
|
|
|
|
|
BURP_verbose (68, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 68 committing meta data */
|
|
|
|
|
|
|
|
|
|
COMMIT;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
|
|
|
|
|
if (gds_status [1])
|
|
|
|
|
EXEC SQL SET TRANSACTION;
|
|
|
|
|
|
|
|
|
|
get_data (relation);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_rel_constraint (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ r e l _ c o n s t r a i n t
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Restore data for relation constraints.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_rel_constraint_req_handle1)
|
|
|
|
|
X IN RDB$RELATION_CONSTRAINTS
|
|
|
|
|
X.RDB$CONSTRAINT_NAME.NULL = TRUE;
|
|
|
|
|
X.RDB$CONSTRAINT_TYPE.NULL = TRUE;
|
|
|
|
|
X.RDB$RELATION_NAME.NULL = TRUE;
|
|
|
|
|
X.RDB$DEFERRABLE.NULL = TRUE;
|
|
|
|
|
X.RDB$INITIALLY_DEFERRED.NULL = TRUE;
|
|
|
|
|
X.RDB$INDEX_NAME.NULL = TRUE;
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_rel_constraint_name:
|
|
|
|
|
X.RDB$CONSTRAINT_NAME.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$CONSTRAINT_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_rel_constraint_type:
|
|
|
|
|
X.RDB$CONSTRAINT_TYPE.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$CONSTRAINT_TYPE);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_rel_constraint_rel_name:
|
|
|
|
|
X.RDB$RELATION_NAME.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$RELATION_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_rel_constraint_defer:
|
|
|
|
|
X.RDB$DEFERRABLE.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$DEFERRABLE);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_rel_constraint_init:
|
|
|
|
|
X.RDB$INITIALLY_DEFERRED.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$INITIALLY_DEFERRED);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_rel_constraint_index:
|
|
|
|
|
X.RDB$INDEX_NAME.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$INDEX_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 208);
|
|
|
|
|
/* msg 208 relation constraint */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_relation_data (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ r e l a t i o n _ d a t a
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Restore data for a relation. This is called when the data is
|
|
|
|
|
* standing free from the relation definition. We first need to
|
|
|
|
|
* find the relation named. If we can't find it, give up.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_REL relation;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
BASED_ON RDB$RELATIONS.RDB$RELATION_NAME name;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
SLONG gen_id;
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
REC_TYPE record;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
relation = NULL;
|
|
|
|
|
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_relation_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(name);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
relation = find_relation (name);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 111);
|
|
|
|
|
/* msg 111 relation */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!relation)
|
|
|
|
|
BURP_error_redirect ((STATUS *) NULL_PTR, 49, 0, 0);
|
|
|
|
|
/* msg 49 no relation name for data */
|
|
|
|
|
|
|
|
|
|
/* Eat up misc. records */
|
|
|
|
|
|
|
|
|
|
GET_RECORD (record);
|
|
|
|
|
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, TRUE)
|
|
|
|
|
switch (record)
|
|
|
|
|
{
|
|
|
|
|
case rec_relation_end:
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
case rec_data:
|
|
|
|
|
record = get_data (relation);
|
|
|
|
|
/* get_data does a GET_RECORD */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_gen_id:
|
|
|
|
|
gen_id = get_numeric();
|
|
|
|
|
store_blr_gen_id (name, gen_id);
|
|
|
|
|
GET_RECORD (record);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_index:
|
|
|
|
|
get_index (relation);
|
|
|
|
|
GET_RECORD (record);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_trigger: /* old style trigger */
|
|
|
|
|
get_trigger_old (relation);
|
|
|
|
|
GET_RECORD (record);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 111);
|
|
|
|
|
/* msg 111 relation */
|
|
|
|
|
GET_RECORD (record);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_sql_roles (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ s q l _ r o l e s
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Restore data for SQL roles
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
2002-06-29 07:39:38 +02:00
|
|
|
|
TEXT temp [GDS_NAME_LEN];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
SSHORT l;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_sql_roles_req_handle1)
|
|
|
|
|
X IN RDB$ROLES
|
|
|
|
|
|
|
|
|
|
X.RDB$ROLE_NAME.NULL = TRUE;
|
|
|
|
|
X.RDB$OWNER_NAME.NULL = TRUE;
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_role_name:
|
|
|
|
|
X.RDB$ROLE_NAME.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
l = GET_TEXT(X.RDB$ROLE_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
MISC_terminate ((UCHAR*) X.RDB$ROLE_NAME, (UCHAR*) temp, l, sizeof (temp));
|
|
|
|
|
/************************************************
|
|
|
|
|
**
|
|
|
|
|
** msg 251, restoring SQL role: %s
|
|
|
|
|
**
|
|
|
|
|
*************************************************/
|
|
|
|
|
BURP_verbose (251, temp, NULL_PTR, NULL_PTR,
|
|
|
|
|
NULL_PTR, NULL_PTR);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_role_owner_name:
|
|
|
|
|
X.RDB$OWNER_NAME.NULL = FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$OWNER_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/*************************************************
|
|
|
|
|
**
|
|
|
|
|
** msg 250, Bad attribute for restoring SQL role
|
|
|
|
|
**
|
|
|
|
|
**************************************************/
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 250);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
END_STORE
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN is_ascii_name (TEXT *name, SSHORT len)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* i s _ a s c i i _ n a m e
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Check if the input text is valid ASCII name
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
SSHORT i;
|
|
|
|
|
|
|
|
|
|
for (i = 0;
|
|
|
|
|
i < len &&
|
|
|
|
|
( (name[i] >= 'A' && name[i] <= 'Z') ||
|
|
|
|
|
(name[i] >= '0' && name[i] <= '9') ||
|
|
|
|
|
name[i] == '_' || name[i] == '$' );
|
|
|
|
|
i ++);
|
|
|
|
|
if (i != len)
|
|
|
|
|
return FALSE;
|
|
|
|
|
else
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_security_class (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ s e c u r i t y _ c l a s s
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Restore a security class record including access control list.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
2002-06-29 07:39:38 +02:00
|
|
|
|
TEXT temp [GDS_NAME_LEN];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
SSHORT l = 0;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
BOOLEAN is_valid_sec_class = FALSE;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_security_class_req_handle1)
|
|
|
|
|
X IN RDB$SECURITY_CLASSES
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
{
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = TRUE;
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_class_security_class:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
l = GET_TEXT(X.RDB$SECURITY_CLASS);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
|
|
|
|
|
/* Bug fix for bug_no 7299: There was a V3 bug that inserted
|
|
|
|
|
garbage security class entry when doing GBAK. In order to
|
|
|
|
|
restore the V3 gbak file with this bad security entry to
|
|
|
|
|
V4 database. We should check if the security class is a
|
|
|
|
|
valid ASCII name. If not, skip this entry by setting
|
|
|
|
|
'is_valid_sec_class' to FALSE.
|
|
|
|
|
*/
|
|
|
|
|
is_valid_sec_class = is_ascii_name(X.RDB$SECURITY_CLASS, l);
|
|
|
|
|
if (!is_valid_sec_class)
|
|
|
|
|
{
|
|
|
|
|
MISC_terminate ((UCHAR*) X.RDB$SECURITY_CLASS, (UCHAR*) temp, l, sizeof (temp));
|
|
|
|
|
BURP_print (234, temp, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 234 Skipped bad security class entry: %s */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MISC_terminate ((UCHAR*) X.RDB$SECURITY_CLASS,(UCHAR*) temp, l, sizeof (temp));
|
|
|
|
|
BURP_verbose (125, temp, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 125 restoring security class %s */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_class_acl:
|
|
|
|
|
get_misc_blob (&X.RDB$ACL, 0, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_class_description:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_misc_blob (&X.RDB$DESCRIPTION, 0, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_class_description2:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$DESCRIPTION, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 131);
|
|
|
|
|
/* msg 131 security class */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* If the security class is not valid ASCII name, don't store it to the */
|
|
|
|
|
/* database. Simply return from here and the entry is discarded. */
|
|
|
|
|
if (!is_valid_sec_class)
|
|
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void get_source_blob (
|
|
|
|
|
ISC_QUAD *blob_id,
|
|
|
|
|
USHORT glb_trans)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ s o u r c e _ b l o b
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Read source blob and query header attributes and copy data from
|
|
|
|
|
* input file to nice, shiney, new blob.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
2002-10-24 11:01:44 +02:00
|
|
|
|
STATUS status_vector[ISC_STATUS_LENGTH];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
SLONG length, *blob;
|
|
|
|
|
USHORT seg_len;
|
|
|
|
|
UCHAR *buffer, static_buffer [1024], *p;
|
|
|
|
|
isc_tr_handle local_trans;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
length = get_numeric();
|
|
|
|
|
|
|
|
|
|
/* Create new blob */
|
|
|
|
|
|
|
|
|
|
blob = NULL;
|
|
|
|
|
|
|
|
|
|
if (glb_trans && tdgbl->global_trans)
|
|
|
|
|
local_trans = tdgbl->global_trans;
|
|
|
|
|
else
|
|
|
|
|
local_trans = gds_trans;
|
|
|
|
|
|
|
|
|
|
if (isc_create_blob (status_vector,
|
|
|
|
|
GDS_REF (tdgbl->db_handle),
|
|
|
|
|
GDS_REF (local_trans),
|
|
|
|
|
(void**) GDS_REF (blob),
|
|
|
|
|
GDS_VAL (blob_id)))
|
|
|
|
|
BURP_error_redirect (status_vector, 37, 0, 0);
|
|
|
|
|
/* msg 37 gds__create_blob failed */
|
|
|
|
|
|
|
|
|
|
/* Allocate blob buffer is static buffer is too short */
|
|
|
|
|
|
2002-04-04 07:32:02 +02:00
|
|
|
|
if (!length || length <= (USHORT)(sizeof (static_buffer)) )
|
2001-07-12 08:32:05 +02:00
|
|
|
|
buffer = static_buffer;
|
|
|
|
|
else
|
|
|
|
|
buffer = BURP_ALLOC (length);
|
|
|
|
|
|
|
|
|
|
while (length)
|
|
|
|
|
{
|
|
|
|
|
p = buffer;
|
|
|
|
|
while (*p++ = GET())
|
|
|
|
|
length--;
|
|
|
|
|
--p;
|
|
|
|
|
--length;
|
|
|
|
|
seg_len = p - buffer;
|
|
|
|
|
|
|
|
|
|
if (isc_put_segment (status_vector,
|
|
|
|
|
(void**) GDS_REF (blob),
|
|
|
|
|
seg_len,
|
|
|
|
|
(SCHAR*) GDS_VAL (buffer)))
|
|
|
|
|
BURP_error_redirect (status_vector, 38, 0, 0);
|
|
|
|
|
/* msg 38 gds__put_segment failed */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isc_close_blob (status_vector, (void**) GDS_REF (blob)))
|
|
|
|
|
BURP_error_redirect (status_vector, 23, 0, 0);
|
|
|
|
|
/* msg 23 gds__close_blob failed */
|
|
|
|
|
|
|
|
|
|
if (buffer != static_buffer)
|
|
|
|
|
BURP_FREE (buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static USHORT get_text (
|
|
|
|
|
TEXT *text,
|
|
|
|
|
ULONG length)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ t e x t
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Move a text attribute to a string and fill.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
2002-06-29 07:39:38 +02:00
|
|
|
|
ULONG l;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
2002-06-29 07:39:38 +02:00
|
|
|
|
l = GET();
|
2001-07-12 08:32:05 +02:00
|
|
|
|
|
2002-06-29 07:39:38 +02:00
|
|
|
|
if (length <= l)
|
2001-07-12 08:32:05 +02:00
|
|
|
|
BURP_error_redirect ((STATUS *) NULL_PTR, 46, 0, 0);
|
|
|
|
|
/* msg 46 string truncated */
|
|
|
|
|
|
|
|
|
|
if (l)
|
|
|
|
|
text = (TEXT*) GET_BLOCK ((UCHAR*) text, l);
|
|
|
|
|
|
|
|
|
|
*text = 0;
|
|
|
|
|
|
2002-06-29 07:39:38 +02:00
|
|
|
|
return (USHORT) l;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_trigger_old (
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_REL relation)
|
2001-07-12 08:32:05 +02:00
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ t r i g g e r _ o l d
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Get a trigger definition for a relation.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
enum trig_t type;
|
|
|
|
|
ATT_TYPE attribute;
|
2002-06-29 07:39:38 +02:00
|
|
|
|
TEXT *q, *p, *end, name [GDS_NAME_LEN];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_trigger_old_req_handle1)
|
|
|
|
|
X IN RDB$TRIGGERS
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = TRUE;
|
|
|
|
|
X.RDB$TRIGGER_BLR.NULL = TRUE;
|
|
|
|
|
X.RDB$TRIGGER_SOURCE.NULL = TRUE;
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
{
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_trig_type:
|
|
|
|
|
type = (enum trig_t) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_trig_blr:
|
|
|
|
|
X.RDB$TRIGGER_BLR.NULL = FALSE;
|
|
|
|
|
get_blr_blob (&X.RDB$TRIGGER_BLR, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_trig_source:
|
|
|
|
|
X.RDB$TRIGGER_SOURCE.NULL = FALSE;
|
|
|
|
|
get_misc_blob (&X.RDB$TRIGGER_SOURCE, 1, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_trig_source2:
|
|
|
|
|
X.RDB$TRIGGER_SOURCE.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$TRIGGER_SOURCE, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 134);
|
|
|
|
|
/* msg 134 trigger */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* fill in rest of attributes unique to new trigger format */
|
|
|
|
|
|
|
|
|
|
p = X.RDB$TRIGGER_NAME;
|
|
|
|
|
end = p + 31;
|
|
|
|
|
q = relation->rel_name;
|
|
|
|
|
while (*q)
|
|
|
|
|
*p++ = *q++;
|
|
|
|
|
|
|
|
|
|
if (type == trig_pre_store)
|
|
|
|
|
{
|
|
|
|
|
X.RDB$TRIGGER_TYPE = TRIG_TYPE_PRE_STORE;
|
|
|
|
|
q = "$STORE";
|
|
|
|
|
}
|
|
|
|
|
else if (type == trig_pre_modify)
|
|
|
|
|
{
|
|
|
|
|
X.RDB$TRIGGER_TYPE = TRIG_TYPE_PRE_MODIFY;
|
|
|
|
|
q = "$MODIFY";
|
|
|
|
|
}
|
|
|
|
|
else if (type == trig_post_erase)
|
|
|
|
|
{
|
|
|
|
|
X.RDB$TRIGGER_TYPE = TRIG_TYPE_POST_ERASE;
|
|
|
|
|
q = "$ERASE";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 136);
|
|
|
|
|
/* msg 136 trigger type */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (*q && p < end)
|
|
|
|
|
*p++ = *q++;
|
|
|
|
|
*p = 0;
|
|
|
|
|
BURP_verbose (126, X.RDB$TRIGGER_NAME, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 126 restoring trigger %s */
|
|
|
|
|
strncpy (X.RDB$RELATION_NAME, relation->rel_name, GDS_NAME_LEN);
|
|
|
|
|
strcpy (name, X.RDB$TRIGGER_NAME);
|
|
|
|
|
X.RDB$TRIGGER_SEQUENCE = TRIGGER_SEQUENCE_DEFAULT;
|
|
|
|
|
X.RDB$SYSTEM_FLAG = 0; /* restore as vanilla user type */
|
|
|
|
|
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_incremental)
|
|
|
|
|
{
|
|
|
|
|
COMMIT
|
|
|
|
|
/* existing ON_ERROR continues past error, beck */
|
|
|
|
|
ON_ERROR
|
|
|
|
|
BURP_print (94, name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 94 trigger %s is invalid */
|
|
|
|
|
BURP_print_status (tdgbl->status_vector);
|
|
|
|
|
ROLLBACK;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
END_ERROR;
|
|
|
|
|
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
|
|
|
|
|
if (gds_status [1])
|
|
|
|
|
EXEC SQL SET TRANSACTION;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_trigger (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ t r i g g e r
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Get a trigger definition in rdb$triggers.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
BASED_ON RDB$TRIGGERS.RDB$TRIGGER_NAME name;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
isc_tr_handle local_trans;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans;
|
|
|
|
|
|
|
|
|
|
STORE (TRANSACTION_HANDLE local_trans
|
|
|
|
|
REQUEST_HANDLE tdgbl->handles_get_trigger_req_handle1)
|
|
|
|
|
X IN RDB$TRIGGERS
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = TRUE;
|
|
|
|
|
X.RDB$TRIGGER_BLR.NULL = TRUE;
|
|
|
|
|
X.RDB$TRIGGER_SOURCE.NULL = TRUE;
|
|
|
|
|
X.RDB$SYSTEM_FLAG.NULL = TRUE;
|
|
|
|
|
X.RDB$FLAGS.NULL = TRUE;
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
{
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_trig_type:
|
|
|
|
|
X.RDB$TRIGGER_TYPE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_trig_flags:
|
|
|
|
|
X.RDB$FLAGS = (USHORT) get_numeric();
|
|
|
|
|
X.RDB$FLAGS.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_trig_blr:
|
|
|
|
|
X.RDB$TRIGGER_BLR.NULL = FALSE;
|
|
|
|
|
get_blr_blob (&X.RDB$TRIGGER_BLR, 1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_trig_source:
|
|
|
|
|
X.RDB$TRIGGER_SOURCE.NULL = FALSE;
|
|
|
|
|
get_misc_blob (&X.RDB$TRIGGER_SOURCE, 1, 1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_trig_source2:
|
|
|
|
|
X.RDB$TRIGGER_SOURCE.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$TRIGGER_SOURCE, 1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_trig_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$TRIGGER_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
strcpy (name, X.RDB$TRIGGER_NAME);
|
|
|
|
|
BURP_verbose (126, X.RDB$TRIGGER_NAME, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 126 restoring trigger %s */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_trig_relation_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$RELATION_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_trig_sequence:
|
|
|
|
|
X.RDB$TRIGGER_SEQUENCE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_trig_description:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_misc_blob (&X.RDB$DESCRIPTION, 1, 1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_trig_description2:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$DESCRIPTION, 1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_trig_system_flag:
|
|
|
|
|
X.RDB$SYSTEM_FLAG = (USHORT) get_numeric();
|
|
|
|
|
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_trig_inactive:
|
|
|
|
|
X.RDB$TRIGGER_INACTIVE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 134);
|
|
|
|
|
/* msg 134 trigger */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_incremental)
|
|
|
|
|
{
|
|
|
|
|
COMMIT
|
|
|
|
|
/* existing ON_ERROR continues past error, beck */
|
|
|
|
|
ON_ERROR
|
|
|
|
|
BURP_print (94, name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 94 trigger %s is invalid */
|
|
|
|
|
BURP_print_status (tdgbl->status_vector);
|
|
|
|
|
ROLLBACK;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
END_ERROR;
|
|
|
|
|
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
|
|
|
|
|
if (gds_status [1])
|
|
|
|
|
EXEC SQL SET TRANSACTION;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_trigger_message (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ t r i g g e r _ m e s s a g e
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Get a trigger message text.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
SSHORT flag;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
isc_tr_handle local_trans;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
BASED_ON RDB$TRIGGER_MESSAGES.RDB$TRIGGER_NAME name;
|
|
|
|
|
BASED_ON RDB$TRIGGER_MESSAGES.RDB$MESSAGE_NUMBER number;
|
|
|
|
|
BASED_ON RDB$TRIGGER_MESSAGES.RDB$MESSAGE message;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
flag = FALSE;
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
{
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_trigmsg_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(name);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
flag = FALSE;
|
|
|
|
|
FOR (REQUEST_HANDLE tdgbl->handles_get_trigger_message_req_handle1)
|
|
|
|
|
FIRST 1 X IN RDB$TRIGGERS WITH
|
|
|
|
|
X.RDB$SYSTEM_FLAG EQ 1 AND X.RDB$TRIGGER_NAME EQ name
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
END_FOR;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
BURP_verbose (127, name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 127 restoring trigger message for %s */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_trigmsg_number:
|
|
|
|
|
number = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_trigmsg_text:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(message);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 135);
|
|
|
|
|
/* msg 135 trigger message */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (flag)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans;
|
|
|
|
|
|
|
|
|
|
STORE (TRANSACTION_HANDLE local_trans
|
|
|
|
|
REQUEST_HANDLE tdgbl->handles_get_trigger_message_req_handle2)
|
|
|
|
|
X IN RDB$TRIGGER_MESSAGES
|
|
|
|
|
strcpy (X.RDB$TRIGGER_NAME, name);
|
|
|
|
|
X.RDB$MESSAGE_NUMBER = number;
|
|
|
|
|
strcpy (X.RDB$MESSAGE, message);
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_incremental)
|
|
|
|
|
{
|
|
|
|
|
COMMIT
|
|
|
|
|
/* existing ON_ERROR continues past error, beck */
|
|
|
|
|
ON_ERROR
|
|
|
|
|
BURP_print (94, name, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 94 trigger %s is invalid */
|
|
|
|
|
BURP_print_status (tdgbl->status_vector);
|
|
|
|
|
ROLLBACK;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
END_ERROR;
|
|
|
|
|
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
|
|
|
|
|
if (gds_status [1])
|
|
|
|
|
EXEC SQL SET TRANSACTION;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_type (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ t y p e
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Get a type definition in rdb$types.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
ULONG l;
|
2002-06-29 07:39:38 +02:00
|
|
|
|
TEXT temp [GDS_NAME_LEN];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_get_type_req_handle1)
|
|
|
|
|
X IN RDB$TYPES
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = TRUE;
|
|
|
|
|
X.RDB$SYSTEM_FLAG.NULL = TRUE;
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
{
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_type_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
l = GET_TEXT(X.RDB$TYPE_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_type_type:
|
|
|
|
|
X.RDB$TYPE = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_type_field_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$FIELD_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_type_description:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_misc_blob (&X.RDB$DESCRIPTION, 1, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_type_description2:
|
|
|
|
|
X.RDB$DESCRIPTION.NULL = FALSE;
|
|
|
|
|
get_source_blob (&X.RDB$DESCRIPTION, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_type_system_flag:
|
|
|
|
|
X.RDB$SYSTEM_FLAG = (USHORT) get_numeric();
|
|
|
|
|
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 136);
|
|
|
|
|
/* msg 136 trigger type */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MISC_terminate ( (UCHAR*) X.RDB$TYPE_NAME, (UCHAR*) temp, l, sizeof (temp));
|
|
|
|
|
BURP_verbose (128, temp, X.RDB$FIELD_NAME, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 128 restoring type %s for field %s */
|
|
|
|
|
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_user_privilege (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ u s e r _ p r i v i l e g e
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Get a user privilege.
|
|
|
|
|
* Get next interesting user privilege.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
UCHAR exists = 0;
|
|
|
|
|
USHORT flags = 0;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
isc_tr_handle local_trans = NULL;
|
|
|
|
|
|
|
|
|
|
BASED_ON RDB$USER_PRIVILEGES.RDB$USER user;
|
|
|
|
|
BASED_ON RDB$USER_PRIVILEGES.RDB$GRANTOR grantor;
|
|
|
|
|
BASED_ON RDB$USER_PRIVILEGES.RDB$PRIVILEGE privilege;
|
|
|
|
|
BASED_ON RDB$USER_PRIVILEGES.RDB$GRANT_OPTION grant_option;
|
|
|
|
|
BASED_ON RDB$USER_PRIVILEGES.RDB$RELATION_NAME relation_name;
|
|
|
|
|
BASED_ON RDB$USER_PRIVILEGES.RDB$FIELD_NAME field_name;
|
|
|
|
|
BASED_ON RDB$USER_PRIVILEGES.RDB$USER_TYPE user_type;
|
|
|
|
|
BASED_ON RDB$USER_PRIVILEGES.RDB$OBJECT_TYPE object_type;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
user_type = obj_user;
|
|
|
|
|
object_type = obj_relation;
|
|
|
|
|
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
{
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_priv_user:
|
|
|
|
|
/* default USER_TYPE to USER */
|
|
|
|
|
flags |= USER_PRIV_USER;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(user);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
BURP_verbose (123, user, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 123 restoring privilege for user %s */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_priv_grantor:
|
|
|
|
|
flags |= USER_PRIV_GRANTOR;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(grantor);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_priv_privilege:
|
|
|
|
|
flags |= USER_PRIV_PRIVILEGE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(privilege);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_priv_grant_option:
|
|
|
|
|
flags |= USER_PRIV_GRANT_OPTION;
|
|
|
|
|
grant_option = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_priv_object_name:
|
|
|
|
|
flags |= USER_PRIV_OBJECT_NAME;
|
|
|
|
|
/* default OBJECT_TYPE to RELATION */
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(relation_name);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_priv_field_name:
|
|
|
|
|
flags |= USER_PRIV_FIELD_NAME;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(field_name);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_priv_user_type:
|
|
|
|
|
flags |= USER_PRIV_USER_TYPE;
|
|
|
|
|
user_type = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_priv_obj_type:
|
|
|
|
|
flags |= USER_PRIV_OBJECT_TYPE;
|
|
|
|
|
object_type = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 105);
|
|
|
|
|
/* msg 105 privilege */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check if object exists */
|
|
|
|
|
|
|
|
|
|
switch (object_type)
|
|
|
|
|
{
|
|
|
|
|
case obj_procedure:
|
|
|
|
|
{
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_PRC proc;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
|
|
|
|
|
for (proc = tdgbl->procedures; proc; proc = proc->prc_next)
|
|
|
|
|
if (!strcmp(proc->prc_name, relation_name))
|
|
|
|
|
{
|
|
|
|
|
exists = 1;
|
|
|
|
|
local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case obj_relation:
|
|
|
|
|
{
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_REL rel;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
|
|
|
|
|
for (rel = tdgbl->relations; rel; rel = rel->rel_next)
|
|
|
|
|
if (!strcmp(rel->rel_name, relation_name))
|
|
|
|
|
{
|
|
|
|
|
exists = 1;
|
|
|
|
|
if (rel->rel_flags & REL_view)
|
|
|
|
|
local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
exists = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (exists)
|
|
|
|
|
{
|
|
|
|
|
if (!local_trans)
|
|
|
|
|
local_trans = gds_trans;
|
|
|
|
|
|
|
|
|
|
STORE (TRANSACTION_HANDLE local_trans
|
|
|
|
|
REQUEST_HANDLE tdgbl->handles_get_user_privilege_req_handle1) X
|
|
|
|
|
IN RDB$USER_PRIVILEGES
|
|
|
|
|
|
|
|
|
|
X.RDB$FIELD_NAME.NULL = TRUE;
|
|
|
|
|
X.RDB$OBJECT_TYPE.NULL = TRUE;
|
|
|
|
|
|
|
|
|
|
if (flags & USER_PRIV_USER)
|
|
|
|
|
strcpy (X.RDB$USER, user);
|
|
|
|
|
|
|
|
|
|
if (flags & USER_PRIV_GRANTOR)
|
|
|
|
|
strcpy (X.RDB$GRANTOR, grantor);
|
|
|
|
|
|
|
|
|
|
if (flags & USER_PRIV_PRIVILEGE)
|
|
|
|
|
strcpy (X.RDB$PRIVILEGE, privilege);
|
|
|
|
|
|
|
|
|
|
if (flags & USER_PRIV_GRANT_OPTION)
|
|
|
|
|
{
|
|
|
|
|
X.RDB$GRANT_OPTION = grant_option;
|
|
|
|
|
if (grant_option == 0)
|
|
|
|
|
X.RDB$GRANT_OPTION.NULL = TRUE;
|
|
|
|
|
else
|
|
|
|
|
X.RDB$GRANT_OPTION.NULL = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (flags & USER_PRIV_OBJECT_NAME)
|
|
|
|
|
strcpy (X.RDB$RELATION_NAME, relation_name);
|
|
|
|
|
|
|
|
|
|
if (flags & USER_PRIV_FIELD_NAME)
|
|
|
|
|
{
|
|
|
|
|
X.RDB$FIELD_NAME.NULL = FALSE;
|
|
|
|
|
strcpy (X.RDB$FIELD_NAME, field_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* USER_TYPE & OBJECT_TYPE are fields that did not exist before
|
|
|
|
|
* V4.0. So, we have to reconstruct them and initialize them to
|
|
|
|
|
* reasonable values. If they existed before then user_type and
|
|
|
|
|
* object_type contain the proper values. If they didn't exist
|
|
|
|
|
* then user_type and object_type contain the reasonable default
|
|
|
|
|
* values.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
X.RDB$USER_TYPE.NULL = FALSE;
|
|
|
|
|
X.RDB$USER_TYPE = user_type;
|
|
|
|
|
|
|
|
|
|
X.RDB$OBJECT_TYPE.NULL = FALSE;
|
|
|
|
|
X.RDB$OBJECT_TYPE = object_type;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If OBJECT_TYPE didn't exist before and we have a field level
|
|
|
|
|
* user privileges, then use obj_field instead.
|
|
|
|
|
*
|
|
|
|
|
* NOTE: Scanning the V4.0 code base, obj_field has never been
|
|
|
|
|
* used at all. The following code should be uncommented
|
|
|
|
|
* in case we ever introduce obj_field to the picture.
|
|
|
|
|
*/
|
|
|
|
|
/***********************************************************
|
|
|
|
|
if ( !(flags & USER_PRIV_OBJECT_TYPE) )
|
|
|
|
|
{
|
|
|
|
|
if ( flags & USER_PRIV_FIELD_NAME )
|
|
|
|
|
{
|
|
|
|
|
X.RDB$OBJECT_TYPE = obj_field;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
***********************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN get_view (
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_REL relation)
|
2001-07-12 08:32:05 +02:00
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* g e t _ v i e w
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Store a record in RDB$VIEW_RELATIONS.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
isc_tr_handle local_trans;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
/* If there is a global transaction then use it */
|
|
|
|
|
|
|
|
|
|
local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans;
|
|
|
|
|
|
|
|
|
|
STORE (TRANSACTION_HANDLE local_trans
|
|
|
|
|
REQUEST_HANDLE tdgbl->handles_get_view_req_handle1)
|
|
|
|
|
X IN RDB$VIEW_RELATIONS
|
|
|
|
|
strcpy (X.RDB$VIEW_NAME, relation->rel_name);
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_view_relation_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$RELATION_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_view_context_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$CONTEXT_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_view_context_id:
|
|
|
|
|
X.RDB$VIEW_CONTEXT = (USHORT) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 140);
|
|
|
|
|
/* msg 140 view */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ignore_array (
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_REL relation)
|
2001-07-12 08:32:05 +02:00
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* i g n o r e _ a r r a y
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Read array data from input file to nice,
|
|
|
|
|
* shiney, new array.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
FLD field;
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
SLONG length, lcount, *range, *end_ranges;
|
|
|
|
|
USHORT field_number;
|
|
|
|
|
LSTRING xdr_buffer;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
/* don't free something you don't allocate */
|
|
|
|
|
xdr_buffer.lstr_allocated = 0;
|
|
|
|
|
|
|
|
|
|
/* Pick up attributes */
|
|
|
|
|
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_blob_data)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_blob_field_number:
|
|
|
|
|
field_number = (USHORT) get_numeric();
|
|
|
|
|
for (field = relation->rel_fields; field; field = field->fld_next)
|
|
|
|
|
if (field->fld_number == field_number)
|
|
|
|
|
break;
|
|
|
|
|
if (!field)
|
|
|
|
|
BURP_error_redirect ((STATUS *) NULL_PTR, 36, 0, 0);
|
|
|
|
|
/* msg 36 Can't find field for blob */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_array_dimensions:
|
|
|
|
|
field->fld_dimensions = (SSHORT)get_numeric();
|
|
|
|
|
end_ranges = field->fld_ranges + 2 * field->fld_dimensions;
|
|
|
|
|
for (range = field->fld_ranges; range < end_ranges; range += 2)
|
|
|
|
|
{
|
|
|
|
|
if (GET_ATTRIBUTE (attribute) != att_array_range_low)
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 58);
|
|
|
|
|
/* msg 58 array */
|
|
|
|
|
else
|
|
|
|
|
range [0] = get_numeric();
|
|
|
|
|
if (GET_ATTRIBUTE (attribute) != att_array_range_high)
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 58);
|
|
|
|
|
/* msg 58 array */
|
|
|
|
|
else
|
|
|
|
|
range [1] = get_numeric();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 58);
|
|
|
|
|
/* msg 58 array */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
length = GET();
|
|
|
|
|
length |= GET() << 8;
|
|
|
|
|
length |= GET() << 16;
|
|
|
|
|
length |= GET() << 24;
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_transportable)
|
|
|
|
|
{
|
|
|
|
|
if (GET_ATTRIBUTE (attribute) != att_xdr_array)
|
|
|
|
|
BURP_error_redirect ((STATUS *) NULL_PTR, 55, 0, 0);
|
|
|
|
|
/* msg 55 Expected XDR record length */
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
xdr_buffer.lstr_allocated = GET();
|
|
|
|
|
xdr_buffer.lstr_allocated |= GET() << 8;
|
|
|
|
|
xdr_buffer.lstr_allocated |= GET() << 16;
|
|
|
|
|
xdr_buffer.lstr_allocated |= GET() << 24;
|
|
|
|
|
lcount = xdr_buffer.lstr_length = xdr_buffer.lstr_allocated;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lcount = length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lcount)
|
|
|
|
|
GET_SKIP (lcount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ignore_blob (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* i g n o r e _ b l o b
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Skip over blob data records.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
SLONG segments;
|
|
|
|
|
USHORT length;
|
|
|
|
|
UCHAR scan_next_attr;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
/* Pick up attributes */
|
|
|
|
|
|
|
|
|
|
segments = 0;
|
|
|
|
|
|
|
|
|
|
SKIP_INIT;
|
|
|
|
|
while (SKIP_SCAN, GET_ATTRIBUTE (attribute) != att_blob_data)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_blob_field_number:
|
|
|
|
|
(void) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_blob_max_segment:
|
|
|
|
|
(void) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_blob_number_segments:
|
|
|
|
|
segments = get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_blob_type:
|
|
|
|
|
(void) get_numeric();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_attribute (scan_next_attr, attribute, 64);
|
|
|
|
|
/* msg 64 blob */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Eat up blob segments */
|
|
|
|
|
|
|
|
|
|
while (--segments >= 0)
|
|
|
|
|
{
|
|
|
|
|
length = GET();
|
|
|
|
|
length |= GET() << 8;
|
|
|
|
|
if (length)
|
|
|
|
|
GET_SKIP (length);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static REC_TYPE ignore_data (
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_REL relation)
|
2001-07-12 08:32:05 +02:00
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* i g n o r e _ d a t a
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Ignore data records for a relation.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
UCHAR *buffer;
|
|
|
|
|
USHORT l, records;
|
|
|
|
|
REC_TYPE record;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
records = 0;
|
|
|
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
|
{
|
|
|
|
|
if (GET () != att_data_length)
|
|
|
|
|
BURP_error_redirect ((STATUS *) NULL_PTR, 39, 0, 0);
|
|
|
|
|
/* msg 39 expected record length */
|
|
|
|
|
l = (USHORT) get_numeric();
|
|
|
|
|
if (tdgbl->gbl_sw_transportable)
|
|
|
|
|
if (GET () != att_xdr_length)
|
|
|
|
|
BURP_error_redirect ((STATUS *) NULL_PTR, 55, 0, 0);
|
|
|
|
|
/* msg 55 Expected XDR record length */
|
|
|
|
|
else
|
|
|
|
|
l = (USHORT) get_numeric();
|
|
|
|
|
if (GET () != att_data_data)
|
|
|
|
|
BURP_error_redirect ((STATUS *) NULL_PTR, 41, 0, 0);
|
|
|
|
|
/* msg 41 expected data attribute */
|
|
|
|
|
if (l)
|
|
|
|
|
if (tdgbl->gbl_sw_compress)
|
|
|
|
|
{
|
|
|
|
|
buffer = (UCHAR*) BURP_ALLOC (l);
|
|
|
|
|
decompress (buffer, l);
|
|
|
|
|
BURP_FREE (buffer);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
GET_SKIP (l);
|
|
|
|
|
records++;
|
|
|
|
|
while (GET_RECORD (record))
|
|
|
|
|
{
|
|
|
|
|
if (record == rec_blob)
|
|
|
|
|
ignore_blob();
|
|
|
|
|
else if (record == rec_array)
|
|
|
|
|
ignore_array (relation);
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (record != rec_data)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BURP_verbose (106, (void*) records, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 106 %ld records ignored */
|
|
|
|
|
|
|
|
|
|
return record;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void realign (
|
|
|
|
|
UCHAR *buffer,
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_REL relation)
|
2001-07-12 08:32:05 +02:00
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* r e a l i g n
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Miserable input record is misaligned.
|
|
|
|
|
* Shuffle fields around. N.B. this one
|
|
|
|
|
* only works if the old buffer is longer
|
|
|
|
|
* than the new.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
FLD field;
|
|
|
|
|
UCHAR *p, *q;
|
|
|
|
|
USHORT l;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
for (field = relation->rel_fields; field; field = field->fld_next)
|
|
|
|
|
{
|
|
|
|
|
if (field->fld_flags & FLD_computed)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
p = buffer + field->fld_offset;
|
|
|
|
|
q = buffer + field->fld_old_offset;
|
|
|
|
|
l = field->fld_length;
|
|
|
|
|
|
|
|
|
|
/* Beware of overlaps here - don't use memcpy */
|
|
|
|
|
while (l--)
|
|
|
|
|
*p++ = *q++;
|
|
|
|
|
|
|
|
|
|
if (field->fld_type == blr_varying)
|
|
|
|
|
{
|
|
|
|
|
*p++ = *q++;
|
|
|
|
|
*p++ = *q++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If this is format version 2, build fields for null flags */
|
|
|
|
|
|
|
|
|
|
if (tdgbl->RESTORE_format >= 2)
|
|
|
|
|
for (field = relation->rel_fields; field; field = field->fld_next)
|
|
|
|
|
{
|
|
|
|
|
if (field->fld_flags & FLD_computed)
|
|
|
|
|
continue;
|
|
|
|
|
p = buffer + FB_ALIGN(p - buffer, sizeof (SSHORT));
|
|
|
|
|
q = buffer + FB_ALIGN(q - buffer, sizeof (SSHORT));
|
|
|
|
|
*p++ = *q++;
|
|
|
|
|
*p++ = *q++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static USHORT recompute_length (
|
2002-11-17 01:04:19 +01:00
|
|
|
|
BURP_REL relation)
|
2001-07-12 08:32:05 +02:00
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* r e c o m p u t e _ l e n g t h
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Recompute length of a record using an old
|
|
|
|
|
* alignment if there is one. At the moment,
|
|
|
|
|
* only SPARC has one.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
|
|
#ifdef sparc
|
|
|
|
|
FLD field;
|
|
|
|
|
ULONG offset, length, dtype, alignment;
|
|
|
|
|
SSHORT *alignments;
|
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
alignments = old_sparcs;
|
|
|
|
|
|
|
|
|
|
for (field = relation->rel_fields; field; field = field->fld_next)
|
|
|
|
|
{
|
|
|
|
|
if (field->fld_flags & FLD_computed)
|
|
|
|
|
continue;
|
|
|
|
|
length = field->fld_length;
|
|
|
|
|
alignment = 4;
|
|
|
|
|
|
|
|
|
|
/* arrays are of various fld_types but are really blobs */
|
|
|
|
|
|
|
|
|
|
dtype = field->fld_type;
|
|
|
|
|
|
|
|
|
|
if (field->fld_flags & FLD_array)
|
|
|
|
|
{
|
|
|
|
|
dtype = blr_blob;
|
|
|
|
|
length = 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
alignment = alignments [gds_cvt_blr_dtype [field->fld_type]];
|
|
|
|
|
if (dtype == blr_varying)
|
|
|
|
|
length += sizeof (USHORT);
|
|
|
|
|
|
|
|
|
|
if (alignment)
|
|
|
|
|
offset = FB_ALIGN(offset, alignment);
|
|
|
|
|
field->fld_old_offset = offset;
|
|
|
|
|
offset += length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If this is format version 2, build fields for null flags */
|
|
|
|
|
|
|
|
|
|
if (tdgbl->RESTORE_format >= 2)
|
|
|
|
|
for (field = relation->rel_fields; field; field = field->fld_next)
|
|
|
|
|
{
|
|
|
|
|
if (field->fld_flags & FLD_computed)
|
|
|
|
|
continue;
|
|
|
|
|
offset = FB_ALIGN(offset, sizeof (SSHORT));
|
|
|
|
|
offset += sizeof (SSHORT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return offset;
|
|
|
|
|
#else
|
|
|
|
|
return FALSE;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN restore (
|
|
|
|
|
TEXT *file_name,
|
|
|
|
|
TEXT *database_name)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* r e s t o r e
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Perform the body of restore.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
SSHORT l, flag;
|
|
|
|
|
REC_TYPE record;
|
|
|
|
|
ATT_TYPE attribute;
|
|
|
|
|
USHORT db_version;
|
|
|
|
|
isc_req_handle req_handle1 = NULL, req_handle2 = NULL, req_handle3 = NULL,
|
|
|
|
|
req_handle4 = NULL, req_handle5 = NULL;
|
2002-10-24 11:01:44 +02:00
|
|
|
|
STATUS req_status[ISC_STATUS_LENGTH];
|
|
|
|
|
TGBL tdgbl;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
SSHORT flag_norel=TRUE; /* To fix bug 10098 */
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
/* Read burp record first */
|
|
|
|
|
|
|
|
|
|
MVOL_init_read ((UCHAR*) tdgbl->gbl_database_file_name, (UCHAR*) file_name,
|
|
|
|
|
&tdgbl->RESTORE_format, &tdgbl->io_cnt, &tdgbl->io_ptr);
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_transportable)
|
|
|
|
|
BURP_verbose (133, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 133 transportable backup -- data in XDR format */
|
|
|
|
|
if (tdgbl->gbl_sw_compress)
|
|
|
|
|
BURP_verbose (61, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 61 backup file is compressed */
|
|
|
|
|
|
|
|
|
|
flag = FALSE;
|
|
|
|
|
|
|
|
|
|
/* restore only from those backup files created by current or previous GBAK */
|
|
|
|
|
|
|
|
|
|
if (tdgbl->RESTORE_format < 1 || tdgbl->RESTORE_format > ATT_BACKUP_FORMAT)
|
|
|
|
|
#ifdef SUPERSERVER
|
2001-12-24 03:51:06 +01:00
|
|
|
|
BURP_svc_error (44, isc_arg_number, (void*)tdgbl->RESTORE_format,
|
2001-07-12 08:32:05 +02:00
|
|
|
|
0, NULL, 0, NULL, 0, NULL, 0, NULL);
|
|
|
|
|
#else
|
|
|
|
|
BURP_error (44, (void*) tdgbl->RESTORE_format, 0, 0, 0, 0);
|
|
|
|
|
/* msg 44 Expected backup version 1, 2, or 3. Found %ld */
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
create_database ((UCHAR*) database_name);
|
|
|
|
|
|
|
|
|
|
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
|
|
|
|
|
if (gds_status [1])
|
|
|
|
|
EXEC SQL SET TRANSACTION;
|
|
|
|
|
|
|
|
|
|
/* For V4.0, start a read commited transaction. This will be used
|
|
|
|
|
* to create blobs for global fields and update the record in the
|
|
|
|
|
* RDB$FIELDS table.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
EXEC SQL SET TRANSACTION NAME tdgbl->global_trans ISOLATION LEVEL READ COMMITTED;
|
|
|
|
|
|
|
|
|
|
db_version = check_db_version();
|
|
|
|
|
if (db_version < DB_VERSION_CURRENT)
|
|
|
|
|
#ifdef SUPERSERVER
|
2001-12-24 03:51:06 +01:00
|
|
|
|
BURP_svc_error (51, isc_arg_number, (void*)db_version,
|
2001-07-12 08:32:05 +02:00
|
|
|
|
0, NULL, 0, NULL, 0, NULL, 0, NULL);
|
|
|
|
|
#else
|
|
|
|
|
BURP_error (51, (void*) db_version, 0, 0, 0, 0);
|
|
|
|
|
/* msg 51 database format %ld is too old to restore to */
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
BURP_verbose (129, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 129 started transaction */
|
|
|
|
|
|
|
|
|
|
while (GET_ATTRIBUTE (attribute) != att_end)
|
|
|
|
|
switch (attribute)
|
|
|
|
|
{
|
|
|
|
|
case att_database_security_class:
|
|
|
|
|
/* Instead of updating the security class in RDB$DATABASE,
|
|
|
|
|
just store the value in tdgbl. It will be updated at
|
|
|
|
|
the very end to prevent security class validation
|
|
|
|
|
failures during change table ownership operation */
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(tdgbl->database_security_class);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_database_description:
|
|
|
|
|
case att_database_description2:
|
|
|
|
|
FOR (REQUEST_HANDLE req_handle2)
|
|
|
|
|
X IN RDB$DATABASE
|
|
|
|
|
MODIFY X USING
|
|
|
|
|
if (attribute == att_database_description2)
|
|
|
|
|
get_source_blob (&X.RDB$DESCRIPTION, 0);
|
|
|
|
|
else
|
|
|
|
|
get_misc_blob (&X.RDB$DESCRIPTION, 1, 0);
|
|
|
|
|
END_MODIFY;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
END_FOR;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case att_database_dfl_charset:
|
|
|
|
|
FOR (REQUEST_HANDLE req_handle3)
|
|
|
|
|
X IN RDB$DATABASE
|
|
|
|
|
MODIFY X USING
|
2001-12-24 03:51:06 +01:00
|
|
|
|
GET_TEXT(X.RDB$CHARACTER_SET_NAME);
|
2001-07-12 08:32:05 +02:00
|
|
|
|
END_MODIFY;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
END_FOR;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
l = GET();
|
|
|
|
|
if (l)
|
|
|
|
|
GET_SKIP (l);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (req_handle1)
|
|
|
|
|
isc_release_request (req_status, &req_handle1);
|
|
|
|
|
if (req_handle2)
|
|
|
|
|
isc_release_request (req_status, &req_handle2);
|
|
|
|
|
if (req_handle3)
|
|
|
|
|
isc_release_request (req_status, &req_handle3);
|
|
|
|
|
|
|
|
|
|
/* If this should be a multi-file database, add the files */
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_files && tdgbl->gbl_sw_files->fil_next)
|
|
|
|
|
add_files ((UCHAR*) database_name);
|
|
|
|
|
|
|
|
|
|
/* Get global fields and relations */
|
|
|
|
|
|
|
|
|
|
while (GET_RECORD (record) != rec_end)
|
|
|
|
|
switch (record)
|
|
|
|
|
{
|
|
|
|
|
case rec_charset:
|
|
|
|
|
if (!get_character_set())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_collation:
|
|
|
|
|
if (!get_collation())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_chk_constraint:
|
|
|
|
|
if (!get_chk_constraint())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_global_field:
|
|
|
|
|
if (!get_global_field())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_field_dimensions:
|
|
|
|
|
if (!get_field_dimensions())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_relation:
|
|
|
|
|
if (!get_relation())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
flag_norel = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_ref_constraint:
|
|
|
|
|
if (!get_ref_constraint())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_rel_constraint:
|
|
|
|
|
if (!get_rel_constraint())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_function:
|
|
|
|
|
if (!get_function())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_procedure:
|
|
|
|
|
if (!get_procedure())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_exception:
|
|
|
|
|
if (!get_exception())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_type: /* rdb$types */
|
|
|
|
|
if (!get_type())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_filter: /* rdb$filters */
|
|
|
|
|
if (!get_filter())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_generator:
|
|
|
|
|
if (!get_generator())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_relation_data:
|
|
|
|
|
if (flag)
|
|
|
|
|
{
|
|
|
|
|
BURP_verbose (68, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 68 committing meta data */
|
|
|
|
|
COMMIT;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
|
|
|
|
|
if (gds_status [1])
|
|
|
|
|
EXEC SQL SET TRANSACTION;
|
|
|
|
|
flag = FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (!get_relation_data())
|
|
|
|
|
return FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_trigger: /* new trigger type */
|
|
|
|
|
if (!get_trigger())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_trigger_message:
|
|
|
|
|
if (!get_trigger_message())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_user_privilege:
|
|
|
|
|
if (!get_user_privilege())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_security_class:
|
|
|
|
|
if (!get_security_class())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_files:
|
|
|
|
|
if (!get_files())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case rec_sql_roles:
|
|
|
|
|
if (!get_sql_roles())
|
|
|
|
|
return FALSE;
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
#ifdef SUPERSERVER
|
2001-12-24 03:51:06 +01:00
|
|
|
|
BURP_svc_error (43, isc_arg_number, (void*) record,
|
2001-07-12 08:32:05 +02:00
|
|
|
|
0, NULL, 0, NULL, 0, NULL, 0, NULL);
|
|
|
|
|
#else
|
|
|
|
|
BURP_error (43, (void*) record, 0, 0, 0, 0);
|
|
|
|
|
/* msg 43 don't recognize record type %ld */
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This piece of code is to fix bug 10098: restore of database with
|
|
|
|
|
only domains and no relations aborts with the message ERROR: deadlock
|
|
|
|
|
This is because insertion of domains into RDB$FIELDS is happening in
|
|
|
|
|
the default transaction, whereas updation of RDB$FIELDS to add
|
|
|
|
|
constraints to the domains is done in tdgbl->global_trans. In case of
|
|
|
|
|
no relations, no COMMIT of default transaction occurs till this point
|
|
|
|
|
because of which rows in RDB$FIELDS for domains are still locked by
|
|
|
|
|
default transaction. The below code COMMITs the default transaction
|
|
|
|
|
in that particular situation */
|
|
|
|
|
|
|
|
|
|
if (flag_norel)
|
|
|
|
|
{
|
|
|
|
|
COMMIT;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
|
|
|
|
|
if (gds_status [1])
|
|
|
|
|
EXEC SQL SET TRANSACTION;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* put validation clauses for global fields */
|
|
|
|
|
|
|
|
|
|
update_global_field ();
|
|
|
|
|
|
|
|
|
|
/* Purge shadow metadata if necessary */
|
|
|
|
|
|
|
|
|
|
if (tdgbl->gbl_sw_kill)
|
|
|
|
|
FOR (REQUEST_HANDLE req_handle5)
|
|
|
|
|
FIL IN RDB$FILES WITH FIL.RDB$SHADOW_NUMBER NOT MISSING
|
|
|
|
|
AND FIL.RDB$SHADOW_NUMBER NE 0
|
|
|
|
|
ERASE FIL;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
END_FOR;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
if (req_handle5)
|
|
|
|
|
isc_release_request (req_status, &req_handle5);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void restore_security_class (
|
|
|
|
|
TEXT *owner_nm,
|
|
|
|
|
TEXT *sec_class_nm)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* r e s t o r e _ s e c u r i t y _ c l a s s
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* restore the ownership of the relation in the ACL list
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
isc_tr_handle local_trans;
|
|
|
|
|
isc_req_handle req_handle2 = NULL;
|
|
|
|
|
ISC_QUAD new_blob_id;
|
2002-10-24 11:01:44 +02:00
|
|
|
|
STATUS req_status[ISC_STATUS_LENGTH];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
local_trans = gds_trans;
|
|
|
|
|
|
|
|
|
|
FOR (REQUEST_HANDLE req_handle2)
|
|
|
|
|
X IN RDB$SECURITY_CLASSES WITH X.RDB$SECURITY_CLASS EQ sec_class_nm
|
|
|
|
|
|
|
|
|
|
new_blob_id.gds_quad_high = 0;
|
|
|
|
|
new_blob_id.gds_quad_low = 0;
|
|
|
|
|
get_acl (owner_nm, &X.RDB$ACL, &new_blob_id);
|
|
|
|
|
|
|
|
|
|
MODIFY X;
|
|
|
|
|
MOVE_FAST (&new_blob_id, &X.RDB$ACL, sizeof (ISC_QUAD));
|
|
|
|
|
END_MODIFY;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
if (req_handle2)
|
|
|
|
|
isc_release_request (req_status, &req_handle2);
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
|
|
ON_ERROR
|
|
|
|
|
if (req_handle2)
|
|
|
|
|
isc_release_request (req_status, &req_handle2);
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
if (req_handle2)
|
|
|
|
|
isc_release_request (req_status, &req_handle2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void store_blr_gen_id (
|
|
|
|
|
GDS_NAME gen_name,
|
|
|
|
|
SINT64 value)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* s t o r e _ b l r _ g e n _ i d
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Store the blr_gen_id for the relation.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
UCHAR *blr;
|
|
|
|
|
UCHAR blr_buffer [100]; /* enough to fit blr */
|
|
|
|
|
SSHORT blr_length;
|
|
|
|
|
SLONG *gen_id_reqh;
|
2002-10-24 11:01:44 +02:00
|
|
|
|
STATUS status_vector[ISC_STATUS_LENGTH];
|
2001-07-12 08:32:05 +02:00
|
|
|
|
TGBL tdgbl;
|
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
STORE (REQUEST_HANDLE tdgbl->handles_store_blr_gen_id_req_handle1)
|
|
|
|
|
X IN RDB$GENERATORS
|
|
|
|
|
strcpy (X.RDB$GENERATOR_NAME, gen_name);
|
|
|
|
|
END_STORE;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
if (!value)
|
|
|
|
|
{
|
|
|
|
|
BURP_verbose (185, gen_name, (void*) value, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 185 restoring generator %s value: %ld */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gen_id_reqh = NULL;
|
|
|
|
|
blr = blr_buffer;
|
|
|
|
|
|
|
|
|
|
/* build the blr with the right relation name */
|
|
|
|
|
|
|
|
|
|
if (tdgbl->RESTORE_format >= 6)
|
|
|
|
|
{
|
|
|
|
|
STUFF (blr_version5);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
STUFF (blr_version4);
|
|
|
|
|
}
|
|
|
|
|
STUFF (blr_begin);
|
|
|
|
|
if (tdgbl->RESTORE_format >= 6)
|
|
|
|
|
{
|
|
|
|
|
STUFF (blr_dcl_variable); STUFF_WORD (0); STUFF (blr_int64); STUFF (0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
STUFF (blr_dcl_variable); STUFF_WORD (0); STUFF (blr_long); STUFF (0);
|
|
|
|
|
}
|
|
|
|
|
STUFF (blr_begin);
|
|
|
|
|
STUFF (blr_assignment);
|
|
|
|
|
STUFF (blr_gen_id);
|
|
|
|
|
stuff_string ((SCHAR**) &blr, gen_name);
|
|
|
|
|
if (tdgbl->RESTORE_format >= 6)
|
|
|
|
|
{
|
|
|
|
|
STUFF (blr_literal); STUFF (blr_int64); STUFF (0); STUFF_INT64 (value);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
STUFF (blr_literal); STUFF (blr_long); STUFF (0); STUFF_LONG ((SLONG)value);
|
|
|
|
|
}
|
|
|
|
|
STUFF (blr_variable); STUFF_WORD (0);
|
|
|
|
|
STUFF (blr_end);
|
|
|
|
|
STUFF (blr_end);
|
|
|
|
|
STUFF (blr_eoc);
|
|
|
|
|
|
|
|
|
|
blr_length = blr - blr_buffer;
|
|
|
|
|
|
|
|
|
|
if (isc_compile_request (
|
|
|
|
|
status_vector,
|
|
|
|
|
(void**) GDS_REF (tdgbl->db_handle),
|
|
|
|
|
(void**) GDS_REF (gen_id_reqh),
|
|
|
|
|
blr_length,
|
|
|
|
|
(SCHAR*) GDS_VAL (blr_buffer)))
|
|
|
|
|
{
|
|
|
|
|
isc_print_blr ((SCHAR*) blr_buffer, (void (*)()) NULL_PTR, NULL_PTR, 0);
|
|
|
|
|
BURP_error_redirect (status_vector, 42, 0, 0);
|
|
|
|
|
/* msg 42 Failed in store_blr_gen_id */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isc_start_request (
|
|
|
|
|
status_vector,
|
|
|
|
|
(void**) GDS_REF (gen_id_reqh),
|
|
|
|
|
GDS_REF (gds_trans), /* use the same one generated by gpre */
|
|
|
|
|
0))
|
|
|
|
|
{
|
|
|
|
|
isc_print_blr ((SCHAR*) blr_buffer, (void (*)()) NULL_PTR, NULL_PTR, 0);
|
|
|
|
|
BURP_error_redirect (status_vector, 42, 0, 0);
|
|
|
|
|
/* msg 42 Failed in store_blr_gen_id */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BURP_verbose (185, gen_name, (void*) value, NULL_PTR, NULL_PTR, NULL_PTR);
|
|
|
|
|
/* msg 185 restoring generator %s value: %ld */
|
|
|
|
|
|
|
|
|
|
isc_release_request (status_vector,
|
|
|
|
|
(void**) GDS_REF (gen_id_reqh));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void stuff_string (
|
|
|
|
|
SCHAR **ptr,
|
|
|
|
|
TEXT *string)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* s t u f f _ s t r i n g
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Stuff a name input a BLR string -- byte count first.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
SCHAR *blr;
|
|
|
|
|
|
|
|
|
|
blr = *ptr;
|
|
|
|
|
STUFF (strlen (string));
|
|
|
|
|
|
|
|
|
|
while (*string)
|
|
|
|
|
STUFF (*string++);
|
|
|
|
|
|
|
|
|
|
*ptr = blr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void update_global_field (void)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* u p d a t e _ g l o b a l _ f i e l d
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Functional description
|
|
|
|
|
* Update the global field definition to add constraints.
|
|
|
|
|
* The blobs have been created already.
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
GFLD n_gfld, gfld;
|
|
|
|
|
USHORT length;
|
|
|
|
|
UCHAR *p, *q;
|
|
|
|
|
isc_req_handle req_handle1 = NULL;
|
2002-10-24 11:01:44 +02:00
|
|
|
|
STATUS req_status[ISC_STATUS_LENGTH];
|
|
|
|
|
TGBL tdgbl;
|
2001-07-12 08:32:05 +02:00
|
|
|
|
|
|
|
|
|
tdgbl = GET_THREAD_DATA;
|
|
|
|
|
|
|
|
|
|
for (gfld = tdgbl->gbl_global_fields; gfld; )
|
|
|
|
|
{
|
|
|
|
|
FOR (TRANSACTION_HANDLE tdgbl->global_trans REQUEST_HANDLE req_handle1)
|
|
|
|
|
X IN RDB$FIELDS WITH X.RDB$FIELD_NAME EQ gfld->gfld_name
|
|
|
|
|
MODIFY X
|
|
|
|
|
|
|
|
|
|
if (gfld->gfld_flags & GFLD_validation_blr)
|
|
|
|
|
{
|
|
|
|
|
X.RDB$VALIDATION_BLR.NULL = FALSE;
|
|
|
|
|
|
|
|
|
|
if (length = sizeof (ISC_QUAD))
|
|
|
|
|
{
|
|
|
|
|
p = (UCHAR *)&X.RDB$VALIDATION_BLR;
|
|
|
|
|
q = (UCHAR *)&gfld->gfld_vb;
|
|
|
|
|
|
|
|
|
|
do *p++ = *q++; while (--length);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gfld->gfld_flags & GFLD_validation_source)
|
|
|
|
|
{
|
|
|
|
|
X.RDB$VALIDATION_SOURCE.NULL = FALSE;
|
|
|
|
|
|
|
|
|
|
if (length = sizeof (ISC_QUAD))
|
|
|
|
|
{
|
|
|
|
|
p = (UCHAR *)&X.RDB$VALIDATION_SOURCE;
|
|
|
|
|
q = (UCHAR *)&gfld->gfld_vs;
|
|
|
|
|
|
|
|
|
|
do *p++ = *q++; while (--length);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gfld->gfld_flags & GFLD_validation_source2)
|
|
|
|
|
{
|
|
|
|
|
X.RDB$VALIDATION_SOURCE.NULL = FALSE;
|
|
|
|
|
|
|
|
|
|
if (length = sizeof (ISC_QUAD))
|
|
|
|
|
{
|
|
|
|
|
p = (UCHAR *)&X.RDB$VALIDATION_SOURCE;
|
|
|
|
|
q = (UCHAR *)&gfld->gfld_vs2;
|
|
|
|
|
|
|
|
|
|
do *p++ = *q++; while (--length);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
END_MODIFY;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
ON_ERROR
|
|
|
|
|
general_on_error ();
|
|
|
|
|
END_ERROR;
|
|
|
|
|
n_gfld = gfld->gfld_next;
|
|
|
|
|
BURP_FREE (gfld);
|
|
|
|
|
gfld = n_gfld;
|
|
|
|
|
}
|
|
|
|
|
if (req_handle1)
|
|
|
|
|
isc_release_request (req_status, &req_handle1);
|
|
|
|
|
|
|
|
|
|
tdgbl->gbl_global_fields = (GFLD)0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOLEAN bug_8183 (
|
|
|
|
|
TGBL tdgbl)
|
|
|
|
|
{
|
|
|
|
|
/**************************************
|
|
|
|
|
*
|
|
|
|
|
* b u g _ 8 1 8 3
|
|
|
|
|
*
|
|
|
|
|
**************************************
|
|
|
|
|
*
|
|
|
|
|
* Name: bug_8183
|
|
|
|
|
*
|
|
|
|
|
* Function: Bug fix for bug_no 8183: It is a migration bug between IB3.3
|
|
|
|
|
* and IB4.0. Gbak v4.0 can't restore database v3.3 if
|
|
|
|
|
* database has an index definition with comment field.
|
|
|
|
|
* It happens because of att_index_description2 attribute
|
|
|
|
|
* (which indicates that index contains a comment field
|
|
|
|
|
* and is equal 8 under IB3.3) accidently got new value 9
|
|
|
|
|
* under IB4.0.
|
|
|
|
|
* At the same time, new attribute att_index_foreign_key
|
|
|
|
|
* has been added with value 8. Thus, when gbak v4.0 faces
|
|
|
|
|
* index attribute with value 8 during restore procedure of
|
|
|
|
|
* database v3.3, it will recognize this attribute as
|
|
|
|
|
* att_index_foreign_key instead of att_index_description2.
|
|
|
|
|
*
|
|
|
|
|
* This function is trying to recognize the next
|
|
|
|
|
* data in tdgbl->io_ptr buffer as either name of foreign
|
|
|
|
|
* key or comment field. Function returns TRUE in case of
|
|
|
|
|
* comment field, otherwise FALSE.
|
|
|
|
|
*
|
|
|
|
|
* Usage: result = bug_8183(tdgbl);
|
|
|
|
|
*
|
|
|
|
|
* Parameters: tdgbl - pointer to the structure of global switches
|
|
|
|
|
* and data
|
|
|
|
|
*
|
|
|
|
|
* Returns: result [TRUE/FALSE]
|
|
|
|
|
*
|
|
|
|
|
* Pre: gbak got an index attribute with value "8" from
|
|
|
|
|
* backup database.
|
|
|
|
|
*
|
|
|
|
|
* Post: none
|
|
|
|
|
*
|
|
|
|
|
* Remarks: For more information see bug_no 8183
|
|
|
|
|
*
|
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
|
|
UCHAR tmp[sizeof(ULONG) + 1], *p;
|
|
|
|
|
USHORT io_cnt, i;
|
|
|
|
|
UCHAR *io_ptr;
|
|
|
|
|
ULONG len1, len2;
|
|
|
|
|
BOOLEAN result = FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
io_cnt = tdgbl->io_cnt;
|
|
|
|
|
io_ptr = tdgbl->io_ptr;
|
|
|
|
|
|
|
|
|
|
if ( io_cnt > 0 )
|
|
|
|
|
{
|
|
|
|
|
len1 = len2 = *io_ptr++;
|
|
|
|
|
--io_cnt;
|
|
|
|
|
/* len1 can be either length of att_index_foreign_key OR quantity of byte
|
|
|
|
|
where seats length of att_index_description2. In case of
|
|
|
|
|
att_index_description2, len1 should be as even and no bigger
|
|
|
|
|
than sizeof(ULONG). Let's check it out */
|
|
|
|
|
if ( (len1 % 2) == 0 && (len1 <= sizeof(ULONG)) )
|
|
|
|
|
{
|
|
|
|
|
/* it still can be a foreign key; so
|
|
|
|
|
try to read it. Note: if internal buffer is over, then
|
|
|
|
|
we wan't read next block */
|
|
|
|
|
|
|
|
|
|
memset(tmp, '\0', sizeof(tmp));
|
|
|
|
|
|
|
|
|
|
p = tmp;
|
|
|
|
|
while (len1-- && io_cnt-- )
|
|
|
|
|
*p++ = *io_ptr++;
|
|
|
|
|
|
|
|
|
|
/* if read array is a foreign key then it should contain following chars
|
|
|
|
|
only : ['A'..'Z', '0'..'9', '_', '$'] */
|
|
|
|
|
for ( p = tmp, i = 0;
|
|
|
|
|
*p && *p != ' ' && ((*p >= 'A' && *p <= 'Z') || (*p == '_') ||
|
|
|
|
|
(*p >= '0' && *p <= '9') || (*p == '$')) ;
|
|
|
|
|
p++ )
|
|
|
|
|
i++;
|
|
|
|
|
if ( (len2 - len1) != i )
|
|
|
|
|
result = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|