/* * PROGRAM: JRD Backup and Restore Program * MODULE: restore.epp * 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 * */ /* $Id: restore.epp,v 1.8 2002-10-22 08:05:57 dimitr Exp $ */ #include "firebird.h" #include "../jrd/ib_stdio.h" #include #include #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" #include "../jrd/thd_proto.h" #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 ***/ #define STUFF(byte) {*blr++ = (UCHAR) (byte);} #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 */ #define FOREIGN_KEY "FOREIGN KEY" #define DEFERRED_ACTIVE 3 /* RDB$INDEX_INACTIVE setting for Foreign Keys * 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) * -bsriram, 11-May-1999 BUG: 10016 */ #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 */ {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 */ {160, CS_LATIN2, 1}, /* CS_CZ */ {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 */ }; 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); static REL find_relation (TEXT *); static int get_acl (TEXT *, ISC_QUAD *, ISC_QUAD *); static void get_array (REL, UCHAR *); 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); static REC_TYPE get_data (REL); static BOOLEAN get_exception (void); static FLD get_field (REL); 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); static BOOLEAN get_index (REL); 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); static BOOLEAN get_trigger_old (REL); static BOOLEAN get_type (void); static BOOLEAN get_user_privilege (void); static BOOLEAN get_view (REL); static void ignore_array (REL); static void ignore_blob (void); static REC_TYPE ignore_data (REL); static void realign (UCHAR *, REL); static USHORT recompute_length (REL); 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()) #define GET_TEXT(text) get_text((text), sizeof(text)) /* 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. * **************************************/ int cumul_count_kb; REL relation; PRC procedure; isc_req_handle req_handle1 = NULL, req_handle2 = NULL, req_handle4 = NULL; long req_status [20]; TGBL tdgbl; long db_handle; UCHAR dpb[128], *d, *q; SSHORT l; isc_req_handle req_handle3 = NULL; BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name; long error_code; tdgbl = GET_THREAD_DATA; tdgbl->io_ptr = (UCHAR *) NULL; tdgbl->io_cnt = 0; tdgbl->relations = (REL) NULL; tdgbl->procedures = (PRC) 0; 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 */ MVOL_fini_read (&cumul_count_kb); /* 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; long req_status [20]; 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; long req_status [20]; 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; STATUS status_vector [ISC_STATUS_LENGTH]; 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; // sweep_interval = 0xFFFFFFFF; sweep_interval = MAX_ULONG; 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++; if (sweep_interval != MAX_ULONG) { *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); } static REL find_relation ( 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; REL relation; 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}; STATUS status_vector [ISC_STATUS_LENGTH]; 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 ** */ if (num_segments > 1) { assert (num_segments > 1); } 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 ( REL relation, 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; STATUS status_vector [ISC_STATUS_LENGTH]; 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; i1fld_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_dimfld_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_dimfld_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_dimfld_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_dimfld_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 || field->fld_type == blr_quad || field->fld_type == blr_int64) { 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_dimcount) { 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 || field->fld_type == blr_quad || field->fld_type == blr_int64) { 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; STATUS status_vector [ISC_STATUS_LENGTH]; 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. * **************************************/ STATUS status_vector [ISC_STATUS_LENGTH]; 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 */ if (!length || length + 1 <= (USHORT)(sizeof (static_buffer)) ) 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; GET_TEXT(X.RDB$CHARACTER_SET_NAME); 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; GET_TEXT(X.RDB$FORM_OF_USE); 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; GET_TEXT(X.RDB$DEFAULT_COLLATE_NAME); 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; GET_TEXT(X.RDB$FUNCTION_NAME); 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; GET_TEXT(X.RDB$CONSTRAINT_NAME); break; case att_chk_trigger_name: X.RDB$TRIGGER_NAME.NULL = FALSE; GET_TEXT(X.RDB$TRIGGER_NAME); 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; GET_TEXT(X.RDB$COLLATION_NAME); 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; GET_TEXT(X.RDB$FUNCTION_NAME); 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 ( REL relation) { /************************************** * * 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; STATUS status_vector [ISC_STATUS_LENGTH]; SLONG *blob_id; REC_TYPE record; TGBL tdgbl; isc_req_handle req_handle = NULL; BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name; 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 BURP_svc_error (26, isc_arg_number, (void*)field->fld_type, 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 BURP_svc_error(40, isc_arg_number, (void*)length, isc_arg_number, (void*)l, 0, NULL, 0, NULL, 0, NULL); #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; TEXT temp [GDS_NAME_LEN]; 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: l = GET_TEXT(X.RDB$EXCEPTION_NAME); 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: GET_TEXT(X.RDB$MESSAGE); 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 ( REL relation) { /************************************** * * 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 = GET_TEXT(field->fld_name); 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: GET_TEXT(X.RDB$FIELD_SOURCE); break; case att_field_security_class: GET_TEXT(X.RDB$SECURITY_CLASS); X.RDB$SECURITY_CLASS.NULL = FALSE; break; case att_field_query_name: GET_TEXT(X.RDB$QUERY_NAME); 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: GET_TEXT(X.RDB$EDIT_STRING); 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: GET_TEXT(X.RDB$BASE_FIELD); 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: GET_TEXT(X.RDB$COMPLEX_NAME); 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: GET_TEXT(X.RDB$FIELD_NAME); 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: GET_TEXT(X.RDB$FILE_NAME); 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: GET_TEXT(X.RDB$FUNCTION_NAME); 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: GET_TEXT(X.RDB$MODULE_NAME); break; case att_filter_entrypoint: GET_TEXT(X.RDB$ENTRYPOINT); 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; TEXT temp [GDS_NAME_LEN]; 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: l = GET_TEXT(X.RDB$FUNCTION_NAME); 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: GET_TEXT(X.RDB$MODULE_NAME); break; case att_function_entrypoint: GET_TEXT(X.RDB$ENTRYPOINT); break; case att_function_return_arg: X.RDB$RETURN_ARGUMENT = (USHORT) get_numeric(); break; case att_function_query_name: GET_TEXT(X.RDB$QUERY_NAME); 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; TEXT temp [GDS_NAME_LEN]; 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: l = GET_TEXT(X.RDB$FUNCTION_NAME); 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: l = GET_TEXT(X.RDB$FUNCTION_NAME); 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; BASED_ON RDB$GENERATORS.RDB$GENERATOR_NAME name; 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: GET_TEXT(name); 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; TEXT temp [GDS_NAME_LEN]; 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: l = GET_TEXT(X.RDB$FIELD_NAME); 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: GET_TEXT(X.RDB$QUERY_NAME); X.RDB$QUERY_NAME.NULL = FALSE; break; case att_field_edit_string: GET_TEXT(X.RDB$EDIT_STRING); 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: l = GET_TEXT(X.RDB$FIELD_NAME); 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: GET_TEXT(X.RDB$QUERY_NAME); X.RDB$QUERY_NAME.NULL = FALSE; break; case att_field_edit_string: GET_TEXT(X.RDB$EDIT_STRING); 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 ( REL relation) { /************************************** * * 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; BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name; 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: GET_TEXT(X.RDB$INDEX_NAME); 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 GET_TEXT(Y.RDB$FIELD_NAME); 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; GET_TEXT(X.RDB$FOREIGN_KEY); } 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. * **************************************/ STATUS status_vector [ISC_STATUS_LENGTH]; 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 */ if (!length || length <= (USHORT)(sizeof (static_buffer)) ) 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. * **************************************/ SLONG value[2]; // get_text needs additional space for the terminator, // because it treats everything as strings. assert(sizeof(value) > sizeof(SLONG)); SSHORT length = get_text((TEXT*) value, sizeof (value)); return isc_vax_integer ((SCHAR *) value, length); } 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. * **************************************/ SLONG value [4]; // get_text needs additional space for the terminator, // because it treats everything as strings. assert (sizeof(value) > sizeof(SINT64)); SSHORT length = get_text ((TEXT *) value, sizeof (value)); return isc_portable_integer ((UCHAR *) value, length); } 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; TEXT temp [GDS_NAME_LEN]; SSHORT l; PRC procedure; 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; procedure = (PRC) BURP_ALLOC_ZERO (sizeof (struct prc)); 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: l = GET_TEXT(X.RDB$PROCEDURE_NAME); 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: GET_TEXT(X.RDB$SECURITY_CLASS); X.RDB$SECURITY_CLASS.NULL = FALSE; break; case att_procedure_owner_name: GET_TEXT(procedure->prc_owner); 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; TEXT temp [GDS_NAME_LEN]; 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: l = GET_TEXT(X.RDB$PARAMETER_NAME); 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: GET_TEXT(X.RDB$FIELD_SOURCE); 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; GET_TEXT(X.RDB$CONSTRAINT_NAME); break; case att_ref_unique_const_name: X.RDB$CONST_NAME_UQ.NULL = FALSE; GET_TEXT(X.RDB$CONST_NAME_UQ); break; case att_ref_match_option: X.RDB$MATCH_OPTION.NULL = FALSE; GET_TEXT(X.RDB$MATCH_OPTION); break; case att_ref_update_rule: X.RDB$UPDATE_RULE.NULL = FALSE; GET_TEXT(X.RDB$UPDATE_RULE); break; case att_ref_delete_rule: X.RDB$DELETE_RULE.NULL = FALSE; GET_TEXT(X.RDB$DELETE_RULE); 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. * * **************************************/ REL relation; FLD field, *ptr; TEXT temp [GDS_NAME_LEN]; SSHORT l; ATT_TYPE attribute; REC_TYPE record; UCHAR scan_next_attr; TGBL tdgbl; 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; BASED_ON RDB$RELATIONS.RDB$SECURITY_CLASS sec_class; short sec_class_null = TRUE; BASED_ON RDB$RELATIONS.RDB$EXTERNAL_FILE ext_file_name; short ext_file_name_null = TRUE; isc_tr_handle local_trans; tdgbl = GET_THREAD_DATA; /* Pick up relation attributes */ relation = (REL) BURP_ALLOC_ZERO (sizeof (struct rel)); 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: l = GET_TEXT(relation->rel_name); 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; GET_TEXT(sec_class); 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: GET_TEXT(relation->rel_owner); break; case att_relation_ext_file_name: ext_file_name_null = FALSE; GET_TEXT(ext_file_name); 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 BURP_svc_error (43, isc_arg_number, (void*) record, 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; GET_TEXT(X.RDB$CONSTRAINT_NAME); break; case att_rel_constraint_type: X.RDB$CONSTRAINT_TYPE.NULL = FALSE; GET_TEXT(X.RDB$CONSTRAINT_TYPE); break; case att_rel_constraint_rel_name: X.RDB$RELATION_NAME.NULL = FALSE; GET_TEXT(X.RDB$RELATION_NAME); break; case att_rel_constraint_defer: X.RDB$DEFERRABLE.NULL = FALSE; GET_TEXT(X.RDB$DEFERRABLE); break; case att_rel_constraint_init: X.RDB$INITIALLY_DEFERRED.NULL = FALSE; GET_TEXT(X.RDB$INITIALLY_DEFERRED); break; case att_rel_constraint_index: X.RDB$INDEX_NAME.NULL = FALSE; GET_TEXT(X.RDB$INDEX_NAME); 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. * **************************************/ REL relation; BASED_ON RDB$RELATIONS.RDB$RELATION_NAME name; 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: GET_TEXT(name); 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; TEXT temp [GDS_NAME_LEN]; 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; l = GET_TEXT(X.RDB$ROLE_NAME); 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; GET_TEXT(X.RDB$OWNER_NAME); 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; TEXT temp [GDS_NAME_LEN]; 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: l = GET_TEXT(X.RDB$SECURITY_CLASS); /* 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. * **************************************/ STATUS status_vector [ISC_STATUS_LENGTH]; 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 */ if (!length || length <= (USHORT)(sizeof (static_buffer)) ) 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. * **************************************/ ULONG l; TGBL tdgbl; tdgbl = GET_THREAD_DATA; l = GET(); if (length <= l) BURP_error_redirect ((STATUS *) NULL_PTR, 46, 0, 0); /* msg 46 string truncated */ if (l) text = (TEXT*) GET_BLOCK ((UCHAR*) text, l); *text = 0; return (USHORT) l; } static BOOLEAN get_trigger_old ( REL relation) { /************************************** * * 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; TEXT *q, *p, *end, name [GDS_NAME_LEN]; 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; BASED_ON RDB$TRIGGERS.RDB$TRIGGER_NAME name; 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: GET_TEXT(X.RDB$TRIGGER_NAME); 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: GET_TEXT(X.RDB$RELATION_NAME); 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: GET_TEXT(name); 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: GET_TEXT(message); 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; TEXT temp [GDS_NAME_LEN]; 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: l = GET_TEXT(X.RDB$TYPE_NAME); break; case att_type_type: X.RDB$TYPE = (USHORT) get_numeric(); break; case att_type_field_name: GET_TEXT(X.RDB$FIELD_NAME); 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; GET_TEXT(user); 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; GET_TEXT(grantor); break; case att_priv_privilege: flags |= USER_PRIV_PRIVILEGE; GET_TEXT(privilege); 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 */ GET_TEXT(relation_name); break; case att_priv_field_name: flags |= USER_PRIV_FIELD_NAME; GET_TEXT(field_name); 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: { PRC proc; 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: { REL rel; 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 ( REL relation) { /************************************** * * 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: GET_TEXT(X.RDB$RELATION_NAME); break; case att_view_context_name: GET_TEXT(X.RDB$CONTEXT_NAME); 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 ( REL relation) { /************************************** * * 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 ( REL relation) { /************************************** * * 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, REL relation) { /************************************** * * 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 ( REL relation) { /************************************** * * 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; long req_status [20]; TGBL tdgbl; 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 BURP_svc_error (44, isc_arg_number, (void*)tdgbl->RESTORE_format, 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 BURP_svc_error (51, isc_arg_number, (void*)db_version, 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 */ GET_TEXT(tdgbl->database_security_class); 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 GET_TEXT(X.RDB$CHARACTER_SET_NAME); 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 BURP_svc_error (43, isc_arg_number, (void*) record, 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; long req_status [20]; 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; STATUS status_vector [ISC_STATUS_LENGTH]; 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; long req_status [20]; TGBL tdgbl; 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; }