/* * PROGRAM: JRD Backup and Restore Program * MODULE: backup.epp * DESCRIPTION: Backup 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: Added verbose backup records as BACKUP_VERBOSE_INTERVAL * 2001.07.06 Sean Leyne - Code Cleanup, removed "#ifdef READONLY_DATABASE" * conditionals, as the engine now fully supports * readonly databases. * 2001.11.20 Claudio Valderrama: fix problem with embedded blanks in * generators and use symbol_length effective length calculation from put_text. * This minimizes code redundancy and fixes SF Bug #483276. * 2001.12.15 Claudio Valderrama: copy should run through symbol_length instead * of using just another length calculation algorithm. Callers of put_text, copy * and symbol_length (if used directly) should use sizeof. Changed all callers * and sizeof() works because the strings are local to the functions. This * eliminates the problem with harcoded limits in each call. * 2002.10.29 Mike Nordell: UINT64 backup message. * 2003.08.17 Claudio Valderrama: Fix SF Bug #750659. * 2005.04.29 Claudio Valderrama: Moved symbol_length to misc.cpp. */ #include "firebird.h" #include #include #include #include "../burp/burp.h" #include "../jrd/ods.h" #include "../jrd/align.h" #include "../jrd/gdsassert.h" #include "../jrd/constants.h" #include "../common/stuff.h" #include "../burp/backu_proto.h" #include "../burp/burp_proto.h" #include "../burp/canon_proto.h" #include "../burp/mvol_proto.h" #include "../remote/protocol.h" #ifdef DEBUG #include "../gpre/prett_proto.h" #endif #include "../common/classes/UserBlob.h" #include "../common/classes/MsgPrint.h" using MsgFormat::SafeArg; // For service APIs the follow DB handle is 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" RUNTIME * dbb_file; #define DB tdgbl->db_handle #define gds_trans tdgbl->tr_handle #define isc_status tdgbl->status namespace // unnamed, private { // VERBOSE INTERVAL WHEN BACKING RECORDS const ULONG BACKUP_VERBOSE_INTERVAL = 20000; #define PUT_MESSAGE(attrib, attrib2, message) put_message((attrib), (attrib2), (message), sizeof(message)) #define PUT_TEXT(attribute, text) put_text ((attribute), (text), sizeof(text)) #define COPY(source, target) copy ((source), (target), sizeof(target)) inline void put(BurpGlobals* tdgbl, const UCHAR c) { if (--(tdgbl->io_cnt) >= 0) *(tdgbl->io_ptr)++ = c; else MVOL_write(c, &tdgbl->io_cnt, &tdgbl->io_ptr); } inline void put(BurpGlobals* tdgbl, const att_type c) { if (--tdgbl->io_cnt >= 0) *(tdgbl->io_ptr)++ = UCHAR(c); else MVOL_write(UCHAR(c), &tdgbl->io_cnt, &tdgbl->io_ptr); } inline const UCHAR* put_block(BurpGlobals* tdgbl, const UCHAR* p, ULONG n) { return MVOL_write_block (tdgbl, p, n); } void compress(const UCHAR*, ULONG); int copy(const TEXT *, TEXT *, ULONG); burp_fld* get_fields(burp_rel*); SINT64 get_gen_id(const TEXT *, SSHORT); void get_ranges(burp_fld*); void put_array(burp_fld*, burp_rel*, ISC_QUAD*); void put_asciz(const att_type, const TEXT*); void put_blob(burp_fld*, ISC_QUAD&); bool put_blr_blob(att_type, ISC_QUAD&); void put_data(burp_rel*); void put_index(burp_rel*); int put_message(att_type, att_type, const TEXT*, const ULONG); void put_numeric(att_type, SLONG); void put_int64( att_type attribute, SINT64 value); void put_relation(burp_rel*); bool put_source_blob(att_type, att_type, ISC_QUAD&); int put_text(att_type, const TEXT *, SSHORT); void set_capabilities(); void write_character_sets(); void write_check_constraints(); void write_collations(); void write_database(const TEXT*); void write_exceptions(); void write_field_dimensions(); void write_filters(); void write_functions(); void write_function_args(const GDS_NAME, GDS_NAME); void write_generators(); void write_sql_roles(); void write_mapping(); void write_global_fields(); void write_packages(); void write_procedures(); void write_procedure_prms(const GDS_NAME, const GDS_NAME); void write_ref_constraints(); void write_rel_constraints(); void write_relations(); void write_shadow_files(); void write_triggers(); void write_trigger_messages(); void write_types(); void write_user_privileges(); void general_on_error(); enum backup_capabilities { BCK_security = 1, BCK_files = 2, BCK_external = 4, BCK_idx_inactive = 8, BCK_triggers = 16, // Obsolete - 1996-Aug-05 BCK_context_name = 32, BCK_db_description = 64, BCK_ffmptt = 128, // rdb$functions, rdb$filters, rdb$trigger_messages, // rdb$user_privileges, rdb$triggers, rdb$types BCK_attributes_v3 = 256, // attributes in various system relations new to v3 BCK_rfr_sys_flag = 512, // system flag is missing from Rdb/VMS V3 RFR relation BCK_ods6 = 1024, // rdb$field_dimensions and shadow files BCK_ods8 = 2048, // stored procedures & exceptions & constraints BCK_ods9 = 4096, // SQL roles BCK_ods10 = 8192, // FIELD_PRECISION BCK_ods11 = 16384,// rdb$description in rdb$roles and rdb$generators // rdb$base_collation_name and rdb$specific_attributes in rdb$collations // rdb$message enlarged to 1021. BCK_ods11_1 = 32768,// rdb$relation_type in rdb$relations // rdb$procedure_type in rdb$procedures // rdb$valid_blr in rdb$triggers // rdb$valid_blr in rdb$procedures // rdb$default_value, rdb$default_source, rdb$collation_id, // rdb$null_flag and rdb$parameter_mechanism in rdb$procedure_parameters BCK_ods11_2 = 65536,// rdb$field_name and rdb$relation_name in rdb$procedure_parameters // rdb$admin system role // rdb$message enlarged to 1023. BCK_ods12_0 =131072 // rdb$engine_name and rdb$entrypoint in rdb$triggers // rdb$package_name in rdb$dependencies // rdb$engine_name, rdb$package_name and rdb$private_flag // in rdb$functions // rdb$package_name in rdb$function_arguments // rdb$engine_name, rdb$entry_point, rdb$package_name // and rdb$private_flag in rdb$procedures // rdb$package_name in rdb$procedure_parameters // rdb$package_name in mon$call_stack // Table rdb$packages // Type of rdb$triggers.rdb$trigger_type changed from SMALLINT to BIGINT }; // ASF: Engine that works with ODS11.1 supports access to non-existent system fields. // Reads returns NULL and writes do nothing. #ifdef DEBUG UCHAR debug_on = 0; // able to turn this on in debug mode #endif // table used to determine capabilities, checking for specific // fields in system relations struct rfr_tab_t { const TEXT* relation; const TEXT* field; // Let's be compatible with BurpGlobals.BCK_capabilities, although we could follow // the enumeration backup_capabilities but the enum then should be defined // in burp.h instead so BCK_capabilities isn't anymore a simple SLONG. SLONG bit_mask; }; const rfr_tab_t rfr_table[] = { {"RDB$INDICES", "RDB$INDEX_INACTIVE", BCK_idx_inactive}, // Backup of V2 triggers no longer supported 1996-Aug-05 David Schnepper // {"RDB$RELATIONS", "RDB$STORE_TRIGGER", BCK_triggers}, {"RDB$RELATIONS", "RDB$EXTERNAL_FILE", BCK_external}, {"RDB$SECURITY_CLASSES", "RDB$SECURITY_CLASS", BCK_security}, {"RDB$FILES", "RDB$FILE_NAME", BCK_files}, {"RDB$VIEW_RELATIONS", "RDB$CONTEXT_NAME", BCK_context_name}, {"RDB$DATABASE", "RDB$DESCRIPTION", BCK_db_description}, {"RDB$FUNCTIONS", "RDB$FUNCTION_NAME", BCK_ffmptt}, {"RDB$FIELDS", "RDB$EXTERNAL_LENGTH", BCK_attributes_v3}, {"RDB$RELATION_FIELDS", "RDB$SYSTEM_FLAG", BCK_rfr_sys_flag}, {"RDB$FIELD_DIMENSIONS", "RDB$DIMENSION", BCK_ods6}, {"RDB$PROCEDURES", "RDB$PROCEDURE_NAME", BCK_ods8}, {"RDB$ROLES", "RDB$ROLE_NAME", BCK_ods9}, {"RDB$FIELDS", "RDB$FIELD_PRECISION", BCK_ods10}, {"RDB$ROLES", "RDB$DESCRIPTION", BCK_ods11}, //{"RDB$ROLES", "RDB$SYSTEM_FLAG", BCK_ods11}, //{"RDB$COLLATIONS", "RDB$BASE_COLLATION_NAME", BCK_ods11}, //{"RDB$COLLATIONS", "RDB$SPECIFIC_ATTRIBUTES", BCK_ods11}, {"RDB$RELATIONS", "RDB$RELATION_TYPE", BCK_ods11_1}, //{"RDB$PROCEDURES", "RDB$PROCEDURE_TYPE", BCK_ods11_1}, //{"RDB$TRIGGERS", "RDB$VALID_BLR", BCK_ods11_1}, //{"RDB$PROCEDURES", "RDB$VALID_BLR", BCK_ods11_1}, //{"RDB$PROCEDURE_PARAMETERS", "RDB$DEFAULT_VALUE", BCK_ods11_1}, //{"RDB$PROCEDURE_PARAMETERS", "RDB$DEFAULT_SOURCE", BCK_ods11_1}, //{"RDB$PROCEDURE_PARAMETERS", "RDB$COLLATION_ID", BCK_ods11_1}, //{"RDB$PROCEDURE_PARAMETERS", "RDB$NULL_FLAG", BCK_ods11_1}, //{"RDB$PROCEDURE_PARAMETERS", "RDB$PARAMETER_MECHANISM", BCK_ods11_1}, {"RDB$PROCEDURE_PARAMETERS", "RDB$FIELD_NAME", BCK_ods11_2}, //{"RDB$PROCEDURE_PARAMETERS", "RDB$RELATION_NAME", BCK_ods11_2}, {"RDB$PROCEDURES", "RDB$ENGINE_NAME", BCK_ods12_0}, {0, 0, 0} }; const UCHAR blob_items[] = { isc_info_blob_max_segment, isc_info_blob_num_segments, isc_info_blob_type, isc_info_blob_total_length }; const UCHAR blr_items[] = { isc_info_blob_max_segment, isc_info_blob_total_length }; const UCHAR source_items[] = { isc_info_blob_max_segment, isc_info_blob_total_length, isc_info_blob_num_segments }; const SCHAR db_info_items[] = { isc_info_db_sql_dialect, isc_info_page_size, isc_info_sweep_interval, isc_info_forced_writes, isc_info_no_reserve, isc_info_set_page_buffers, isc_info_db_read_only, isc_info_end }; const SCHAR limbo_tpb[] = { isc_tpb_version1, isc_tpb_ignore_limbo }; const SCHAR limbo_nau_tpb[] = { isc_tpb_version1, isc_tpb_ignore_limbo, isc_tpb_no_auto_undo }; } // namespace int BACKUP_backup(const TEXT* dbb_file, const TEXT* file_name) { /************************************** * * B A C K U P _ b a c k u p * ************************************** * * Functional description * Backup a database. * **************************************/ ISC_STATUS_ARRAY status_vector; TEXT temp[GDS_NAME_LEN]; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); tdgbl->gbl_database_file_name = dbb_file; tdgbl->io_ptr = NULL; tdgbl->io_cnt = 0; tdgbl->relations = NULL; tdgbl->BCK_capabilities = 0; gds_trans = 0; BURP_verbose(130); // msg 130 starting transaction if (tdgbl->gbl_sw_ignore_limbo) { if (isc_start_transaction(status_vector, &gds_trans, 1, &DB, sizeof(limbo_nau_tpb), limbo_nau_tpb)) { isc_start_transaction(status_vector, &gds_trans, 1, &DB, sizeof(limbo_tpb), limbo_tpb); } } else { EXEC SQL SET TRANSACTION NO_AUTO_UNDO; if (isc_status[1]) EXEC SQL SET TRANSACTION; } if (!gds_trans) { EXEC SQL SET TRANSACTION NAME gds_trans NO_AUTO_UNDO; if (isc_status[1]) EXEC SQL SET TRANSACTION NAME gds_trans; } // decide what type of database we've got set_capabilities(); // Write burp record first with other valuable information // In case of split operation, write a 'split' header first to all the files if (tdgbl->action->act_action == ACT_backup_split) { for (burp_fil* fil = tdgbl->gbl_sw_files; fil; fil = fil->fil_next) { tdgbl->action->act_file = fil; if (!MVOL_split_hdr_write()) { BURP_error(269, true, tdgbl->action->act_file->fil_name.c_str()); // msg 269 can't write a header record to file %s } } tdgbl->action->act_file = tdgbl->gbl_sw_files; } MVOL_init_write(file_name, &tdgbl->io_cnt, &tdgbl->io_ptr); // Write database record write_database(dbb_file); // Write global fields BURP_verbose(150); // msg 150 writing global fields write_global_fields(); if (tdgbl->BCK_capabilities & BCK_ods6) { write_field_dimensions(); BURP_verbose(162); // msg 162 writing shadow files write_shadow_files(); } if (tdgbl->BCK_capabilities & BCK_ods8) { // Write Character Sets BURP_verbose(msgVerbose_write_charsets); write_character_sets(); // Write Collations BURP_verbose(msgVerbose_write_collations); write_collations(); } if (tdgbl->BCK_capabilities & BCK_ods12_0) { // Write packages BURP_verbose(336); // msg 336 writing packages write_packages(); } if (tdgbl->BCK_capabilities & BCK_ffmptt) { // Write functions BURP_verbose(148); // msg 148 writing functions write_functions(); } // Write relations BURP_verbose(154); // msg 154 writing relations write_relations(); if (tdgbl->BCK_capabilities & BCK_ffmptt) { // Write types BURP_verbose(161); // msg 161 writing types write_types(); // Write filters BURP_verbose(146); // msg 146 writing filters write_filters(); // Write generators BURP_verbose(164); // msg 164 writing id generators write_generators(); } if (tdgbl->BCK_capabilities & BCK_ods8) { // Write procedures BURP_verbose(192); // msg 192 writing stored procedures write_procedures(); // Write exceptions BURP_verbose(197); // msg 197 writing exceptions write_exceptions(); } // Now go back and write all data for (burp_rel* relation = tdgbl->relations; relation; relation = relation->rel_next) { put(tdgbl, (UCHAR) rec_relation_data); PUT_TEXT(att_relation_name, relation->rel_name); put(tdgbl, att_end); if (!(relation->rel_flags & REL_view) && !(relation->rel_flags & REL_external)) { put_index(relation); if (!tdgbl->gbl_sw_meta) put_data(relation); } put(tdgbl, (UCHAR) rec_relation_end); } // now for the new triggers in rdb$triggers if (tdgbl->BCK_capabilities & BCK_ffmptt) { BURP_verbose(159); // msg 159 writing triggers write_triggers(); BURP_verbose(158); // msg 158 writing trigger messages write_trigger_messages(); write_user_privileges(); } // Last, but not least, go back and add any access control lists if (tdgbl->BCK_capabilities & BCK_security) { isc_req_handle req_handle1 = 0; FOR (REQUEST_HANDLE req_handle1) X IN RDB$SECURITY_CLASSES WITH X.RDB$SECURITY_CLASS NOT STARTING "SQL$" put(tdgbl, rec_security_class); const ULONG l = PUT_TEXT (att_class_security_class, X.RDB$SECURITY_CLASS); MISC_terminate (X.RDB$SECURITY_CLASS, temp, l, sizeof(temp)); BURP_verbose (155, temp); // msg 155 writing security class %s put_blr_blob (att_class_acl, X.RDB$ACL); put_source_blob (att_class_description2, att_class_description, X.RDB$DESCRIPTION); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; MISC_release_request_silent(req_handle1); } if (tdgbl->BCK_capabilities & BCK_ods8) { // Write relation constraints BURP_verbose(206); // msg 206 writing relation constraints write_rel_constraints(); // Write referential constraints BURP_verbose(209); // msg 209 writing referential constraints write_ref_constraints(); // Write check constraints BURP_verbose(210); // msg 210 writing check constraints write_check_constraints(); } if (tdgbl->BCK_capabilities & BCK_ods9) { // Write SQL roles BURP_verbose(248); // msg 248 writing SQL roles write_sql_roles(); } if (tdgbl->BCK_capabilities & BCK_ods11) { // Write names mapping BURP_verbose(296); // msg 296 writing mapping write_mapping(); } // Finish up put(tdgbl, (UCHAR) rec_end); FB_UINT64 cumul_count = MVOL_fini_write(&tdgbl->io_cnt, &tdgbl->io_ptr); BURP_verbose(176, SafeArg() << cumul_count); // msg 176 closing file, committing, and finishing. %ld bytes written COMMIT; ON_ERROR general_on_error(); END_ERROR; if (gds_trans) COMMIT gds_trans; ON_ERROR general_on_error(); END_ERROR; FINISH ON_ERROR general_on_error(); END_ERROR; return FINI_OK; } namespace // unnamed, private { void compress(const UCHAR* data, ULONG length) { /************************************** * * c o m p r e s s * ************************************** * * Functional description * Write out data in compressed form. * **************************************/ BurpGlobals* tdgbl = BurpGlobals::getSpecific(); const UCHAR* p = data; const UCHAR* end = p + length; const UCHAR* q = NULL; while (p < end) { for (q = p + 2; q < end && (q[-2] != q[-1] || q[-1] != q[0]); q++) ; USHORT run = (q < end) ? q - p - 2 : end - p; if (run) { for (; run > 127; run -= 127) { USHORT len = 127; put(tdgbl, (UCHAR) len); p = put_block(tdgbl, p, len); } if (run) { put(tdgbl, (UCHAR) run); p = put_block(tdgbl, p, run); } } for (q = p; q < end && *q == *p; q++) ; if ((run = q - p) != 0) { for (; run > 127; run -= 127) { put(tdgbl, (UCHAR) (-127)); put(tdgbl, (UCHAR) (*p)); } if (run) { put(tdgbl, (UCHAR) (-run)); put(tdgbl, (UCHAR) (*p)); } p = q; } } } int copy( const TEXT* from, TEXT* to, ULONG size_len) { /************************************** * * c o p y * ************************************** * * Functional description * Copy a blank or null terminated string into a null terminated * string. It assumes there's enough room in the target. * **************************************/ const ULONG len = (ULONG) MISC_symbol_length(from, size_len); memcpy(to, from, len); to[len] = '\0'; return (int) len; } void general_on_error() { /************************************** * * g e n e r a l _ o n _ e r r o r * ************************************** * * Functional description * Handle any general ON_ERROR clause during backup. * **************************************/ BurpGlobals* tdgbl = BurpGlobals::getSpecific(); BURP_print_status(isc_status, true); BURP_abort(); } burp_fld* get_fields( burp_rel* relation) { /************************************** * * g e t _ f i e l d s * ************************************** * * Functional description * Get fields for a relation. Test * capabilities and get system specific * **************************************/ burp_fld* field; ISC_QUAD* blob_id; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); USHORT count = 1; burp_fld* fields = NULL; // if we have all capabilities, use the first request to get the // most performance out of the latest engine; if we don't // have one of the capabilities we must use the second set of // requests--this requires more code but it is well worth it // for the performance benefits, especially remotely--deej if ((tdgbl->BCK_capabilities & BCK_attributes_v3) && (tdgbl->BCK_capabilities & BCK_ods8) && (tdgbl->BCK_capabilities & BCK_rfr_sys_flag) && (tdgbl->BCK_capabilities & BCK_security)) { FOR (REQUEST_HANDLE tdgbl->handles_get_fields_req_handle1) X IN RDB$RELATION_FIELDS CROSS Y IN RDB$FIELDS WITH X.RDB$FIELD_SOURCE = Y.RDB$FIELD_NAME AND X.RDB$RELATION_NAME EQ relation->rel_name field = (burp_fld*) BURP_alloc_zero(sizeof(burp_fld)); field->fld_number = count++; field->fld_type = Y.RDB$FIELD_TYPE; field->fld_sub_type = Y.RDB$FIELD_SUB_TYPE; field->fld_length = Y.RDB$FIELD_LENGTH; field->fld_scale = Y.RDB$FIELD_SCALE; field->fld_id = X.RDB$FIELD_ID; if (!X.RDB$DESCRIPTION.NULL) { blob_id = &X.RDB$DESCRIPTION; if (blob_id->gds_quad_low || blob_id->gds_quad_high) field->fld_description = X.RDB$DESCRIPTION; } if (!X.RDB$QUERY_HEADER.NULL) { blob_id = &X.RDB$QUERY_HEADER; if (blob_id->gds_quad_low || blob_id->gds_quad_high) field->fld_query_header = X.RDB$QUERY_HEADER; } if (X.RDB$FIELD_POSITION.NULL) field->fld_flags |= FLD_position_missing; else field->fld_position = X.RDB$FIELD_POSITION; field->fld_view_context = X.RDB$VIEW_CONTEXT; if (X.RDB$UPDATE_FLAG.NULL) field->fld_flags |= FLD_update_missing; else field->fld_update_flag = X.RDB$UPDATE_FLAG; COPY (X.RDB$FIELD_NAME, field->fld_name); COPY (X.RDB$FIELD_SOURCE, field->fld_source); COPY (X.RDB$BASE_FIELD, field->fld_base); COPY (X.RDB$QUERY_NAME, field->fld_query_name); COPY (X.RDB$EDIT_STRING, field->fld_edit_string); COPY (X.RDB$COMPLEX_NAME, field->fld_complex_name); blob_id = &Y.RDB$COMPUTED_BLR; if (blob_id->gds_quad_low || blob_id->gds_quad_high) { field->fld_flags |= FLD_computed; } field->fld_system_flag = X.RDB$SYSTEM_FLAG; COPY (X.RDB$SECURITY_CLASS, field->fld_security_class); // use the fld_flags to mark the field as an array and // to differentiate it from other blobs if (Y.RDB$DIMENSIONS) { field->fld_flags |= FLD_array; field->fld_dimensions = Y.RDB$DIMENSIONS; if (field->fld_dimensions < 0) { BURP_error_redirect (NULL, 52, SafeArg() << field->fld_name); } // msg 52 array dimension for field %s is invalid get_ranges (field); } if (!X.RDB$NULL_FLAG.NULL) { field->fld_null_flag = X.RDB$NULL_FLAG; field->fld_flags |= FLD_null_flag; } if (!X.RDB$DEFAULT_VALUE.NULL) { blob_id = &X.RDB$DEFAULT_VALUE; if (blob_id->gds_quad_low || blob_id->gds_quad_high) { field->fld_default_value = X.RDB$DEFAULT_VALUE; } } if (!X.RDB$DEFAULT_SOURCE.NULL) { blob_id = &X.RDB$DEFAULT_SOURCE; if (blob_id->gds_quad_low || blob_id->gds_quad_high) { field->fld_default_source = X.RDB$DEFAULT_SOURCE; } } if (!Y.RDB$CHARACTER_SET_ID.NULL) { field->fld_character_set_id = Y.RDB$CHARACTER_SET_ID; field->fld_flags |= FLD_charset_flag; } if (!X.RDB$COLLATION_ID.NULL) { field->fld_collation_id = X.RDB$COLLATION_ID; field->fld_flags |= FLD_collate_flag; } field->fld_next = fields; fields = field; END_FOR; ON_ERROR general_on_error(); END_ERROR; } else { FOR (REQUEST_HANDLE tdgbl->handles_get_fields_req_handle1) X IN RDB$RELATION_FIELDS CROSS Y IN RDB$FIELDS WITH X.RDB$FIELD_SOURCE = Y.RDB$FIELD_NAME AND X.RDB$RELATION_NAME EQ relation->rel_name field = (burp_fld*) BURP_alloc_zero (sizeof(burp_fld)); field->fld_number = count++; field->fld_type = Y.RDB$FIELD_TYPE; field->fld_sub_type = Y.RDB$FIELD_SUB_TYPE; field->fld_length = Y.RDB$FIELD_LENGTH; field->fld_scale = Y.RDB$FIELD_SCALE; field->fld_id = X.RDB$FIELD_ID; if (!X.RDB$DESCRIPTION.NULL) { blob_id = &X.RDB$DESCRIPTION; if (blob_id->gds_quad_low || blob_id->gds_quad_high) field->fld_description = X.RDB$DESCRIPTION; } if (!X.RDB$QUERY_HEADER.NULL) { blob_id = &X.RDB$QUERY_HEADER; if (blob_id->gds_quad_low || blob_id->gds_quad_high) field->fld_query_header = X.RDB$QUERY_HEADER; } if (X.RDB$FIELD_POSITION.NULL) field->fld_flags |= FLD_position_missing; else field->fld_position = X.RDB$FIELD_POSITION; field->fld_view_context = X.RDB$VIEW_CONTEXT; if (X.RDB$UPDATE_FLAG.NULL) field->fld_flags |= FLD_update_missing; else field->fld_update_flag = X.RDB$UPDATE_FLAG; COPY (X.RDB$FIELD_NAME, field->fld_name); COPY (X.RDB$FIELD_SOURCE, field->fld_source); COPY (X.RDB$BASE_FIELD, field->fld_base); COPY (X.RDB$QUERY_NAME, field->fld_query_name); COPY (X.RDB$EDIT_STRING, field->fld_edit_string); if (tdgbl->BCK_capabilities & BCK_attributes_v3) { FOR (REQUEST_HANDLE tdgbl->handles_get_fields_req_handle2) RFR IN RDB$RELATION_FIELDS WITH RFR.RDB$FIELD_NAME = X.RDB$FIELD_NAME AND RFR.RDB$RELATION_NAME = X.RDB$RELATION_NAME COPY (RFR.RDB$COMPLEX_NAME, field->fld_complex_name); END_FOR; ON_ERROR general_on_error(); END_ERROR; } blob_id = &Y.RDB$COMPUTED_BLR; if (blob_id->gds_quad_low || blob_id->gds_quad_high) field->fld_flags |= FLD_computed; if (tdgbl->BCK_capabilities & BCK_rfr_sys_flag) { FOR (REQUEST_HANDLE tdgbl->handles_get_fields_req_handle3) RFR IN RDB$RELATION_FIELDS WITH RFR.RDB$RELATION_NAME = relation->rel_name AND RFR.RDB$FIELD_NAME = X.RDB$FIELD_NAME field->fld_system_flag = RFR.RDB$SYSTEM_FLAG; END_FOR; ON_ERROR general_on_error(); END_ERROR; } if (tdgbl->BCK_capabilities & BCK_security) { FOR (REQUEST_HANDLE tdgbl->handles_get_fields_req_handle4) RFR IN RDB$RELATION_FIELDS WITH RFR.RDB$RELATION_NAME = relation->rel_name AND RFR.RDB$FIELD_NAME = X.RDB$FIELD_NAME COPY (RFR.RDB$SECURITY_CLASS, field->fld_security_class); END_FOR; ON_ERROR general_on_error(); END_ERROR; } if (tdgbl->BCK_capabilities & BCK_attributes_v3) { FOR (REQUEST_HANDLE tdgbl->handles_get_fields_req_handle5) RF IN RDB$FIELDS WITH RF.RDB$FIELD_NAME = X.RDB$FIELD_SOURCE // use the fld_flags to mark the field as an array and // to differentiate it from other blobs if (RF.RDB$DIMENSIONS) { field->fld_flags |= FLD_array; field->fld_dimensions = RF.RDB$DIMENSIONS; if (field->fld_dimensions < 0) { BURP_error_redirect (NULL, 52, SafeArg() << field->fld_name); // msg 52 array dimension for field %s is invalid } get_ranges (field); } END_FOR; ON_ERROR general_on_error(); END_ERROR; } if (tdgbl->BCK_capabilities & BCK_ods8) { FOR (REQUEST_HANDLE tdgbl->handles_get_fields_req_handle6) X2 IN RDB$RELATION_FIELDS CROSS F2 IN RDB$FIELDS WITH X2.RDB$FIELD_NAME = X.RDB$FIELD_NAME AND X2.RDB$RELATION_NAME EQ relation->rel_name AND X2.RDB$FIELD_SOURCE EQ F2.RDB$FIELD_NAME if (!X2.RDB$NULL_FLAG.NULL) { field->fld_null_flag = X2.RDB$NULL_FLAG; field->fld_flags |= FLD_null_flag; } if (!X2.RDB$DEFAULT_VALUE.NULL) { blob_id = &X2.RDB$DEFAULT_VALUE; if (blob_id->gds_quad_low || blob_id->gds_quad_high) field->fld_default_value = X2.RDB$DEFAULT_VALUE; } if (!X2.RDB$DEFAULT_SOURCE.NULL) { blob_id = &X2.RDB$DEFAULT_SOURCE; if (blob_id->gds_quad_low || blob_id->gds_quad_high) field->fld_default_source = X2.RDB$DEFAULT_SOURCE; } if (!F2.RDB$CHARACTER_SET_ID.NULL) { field->fld_character_set_id = F2.RDB$CHARACTER_SET_ID; field->fld_flags |= FLD_charset_flag; } if (!X2.RDB$COLLATION_ID.NULL) { field->fld_collation_id = X2.RDB$COLLATION_ID; field->fld_flags |= FLD_collate_flag; } END_FOR; ON_ERROR general_on_error(); END_ERROR; } field->fld_next = fields; fields = field; END_FOR; ON_ERROR general_on_error(); END_ERROR; } return fields; } SINT64 get_gen_id( const TEXT* name, SSHORT name_len) { /************************************** * * g e t _ g e n _ i d * ************************************** * * Functional description * Read id for a generator; * **************************************/ UCHAR blr_buffer[100]; // enough to fit blr BurpGlobals* tdgbl = BurpGlobals::getSpecific(); FB_API_HANDLE gen_id_reqh = 0; UCHAR* blr = blr_buffer; // If this is ODS 10 (IB version 6.0) or greater, build BLR to retrieve // the 64-bit value of the generator. If not, build BLR to retrieve the // 32-bit value, which we will cast to the expected INT64 format. if (tdgbl->BCK_capabilities & BCK_ods10) { // build the blr with the right relation name and 64-bit results. add_byte(blr, blr_version5); add_byte(blr, blr_begin); add_byte(blr, blr_message); add_byte(blr, 0); add_word(blr, 1); add_byte(blr, blr_int64); add_byte(blr, 0); add_byte(blr, blr_send); add_byte(blr, 0); add_byte(blr, blr_assignment); add_byte(blr, blr_gen_id); add_byte(blr, name_len); while (name_len--) { const UCHAR c = *name++; add_byte(blr, c); } add_byte(blr, blr_literal); add_byte(blr, blr_long); add_byte(blr, 0); add_word(blr, 0); add_word(blr, 0); add_byte(blr, blr_parameter); add_byte(blr, 0); add_word(blr, 0); add_byte(blr, blr_end); add_byte(blr, blr_eoc); } else { // build the blr with the right relation name and 32-bit results add_byte(blr, blr_version4); add_byte(blr, blr_begin); add_byte(blr, blr_message); add_byte(blr, 0); add_word(blr, 1); add_byte(blr, blr_long); add_byte(blr, 0); add_byte(blr, blr_send); add_byte(blr, 0); add_byte(blr, blr_assignment); add_byte(blr, blr_gen_id); add_byte(blr, name_len); while (name_len--) { const UCHAR c = *name++; add_byte(blr, c); } add_byte(blr, blr_literal); add_byte(blr, blr_long); add_byte(blr, 0); add_word(blr, 0); add_word(blr, 0); add_byte(blr, blr_parameter); add_byte(blr, 0); add_word(blr, 0); add_byte(blr, blr_end); add_byte(blr, blr_eoc); } const SSHORT blr_length = blr - blr_buffer; #ifdef DEBUG if (debug_on) fb_print_blr(blr_buffer, blr_length, NULL, NULL, 0); #endif ISC_STATUS_ARRAY status_vector; if (isc_compile_request(status_vector, &DB, &gen_id_reqh, blr_length, (const char*) blr_buffer)) { // if there's no gen_id, never mind ... return 0; } // use the same gds_trans generated by gpre if (isc_start_request(status_vector, &gen_id_reqh, &gds_trans, 0)) { BURP_error_redirect(status_vector, 25); // msg 25 Failed in put_blr_gen_id } SINT64 read_msg1; if (tdgbl->BCK_capabilities & BCK_ods10) { if (isc_receive(status_vector, &gen_id_reqh, 0, sizeof(read_msg1), &read_msg1, 0)) { BURP_error_redirect(status_vector, 25); // msg 25 Failed in put_blr_gen_id } } else { SLONG read_msg0; if (isc_receive(status_vector, &gen_id_reqh, 0, sizeof(read_msg0), &read_msg0, 0)) { BURP_error_redirect(status_vector, 25); // msg 25 Failed in put_blr_gen_id } read_msg1 = (SINT64) read_msg0; } isc_release_request(status_vector, &gen_id_reqh); return read_msg1; } void get_ranges( burp_fld* field) { /************************************** * * g e t _ r a n g e s * ************************************** * * Functional description * Fill in the range low and high bounds by reading * the ranges in rdb$field_dimensions. * **************************************/ BurpGlobals* tdgbl = BurpGlobals::getSpecific(); SLONG* rp = field->fld_ranges; USHORT count = 0; // Get the array dimensions in the rdb$field_dimensions FOR (REQUEST_HANDLE tdgbl->handles_get_ranges_req_handle1) X IN RDB$FIELD_DIMENSIONS WITH X.RDB$FIELD_NAME EQ field->fld_source SORTED BY X.RDB$DIMENSION if (count != X.RDB$DIMENSION) BURP_error_redirect (NULL, 52, SafeArg() << field->fld_name); // msg 52 array dimension for field %s is invalid *rp++ = X.RDB$LOWER_BOUND; *rp++ = X.RDB$UPPER_BOUND; count++; END_FOR; ON_ERROR general_on_error(); END_ERROR; if (count != field->fld_dimensions) BURP_error_redirect(NULL, 52, SafeArg() << field->fld_name); // msg 52 array dimension for field %s is invalid } void put_array( burp_fld* field, burp_rel* relation, ISC_QUAD* blob_id) { /************************************** * * p u t _ a r r a y * ************************************** * * Functional description * Write out an array. If, however, it's null, don't even bother. * **************************************/ SLONG range_buffer[16]; // enough for 16 dimensions UCHAR blr_buffer[200]; // enough for a sdl with 16 dimensions BurpGlobals* tdgbl = BurpGlobals::getSpecific(); // If the array is null, don't store it. It will be restored as null. if (!blob_id->gds_quad_low && !blob_id->gds_quad_high) return; lstring xdr_buffer; xdr_buffer.lstr_allocated = 0; xdr_buffer.lstr_address = NULL; UCHAR* blr = blr_buffer; const SLONG* const end_ranges = field->fld_ranges + 2 * field->fld_dimensions; USHORT field_length = field->fld_length; if (tdgbl->gbl_sw_transportable) xdr_buffer.lstr_length = field_length + 3; // build the sdl add_byte(blr, isc_sdl_version1); add_byte(blr, isc_sdl_struct); add_byte(blr, 1); add_byte(blr, field->fld_type); switch (field->fld_type) { case blr_short: case blr_long: case blr_quad: case blr_int64: add_byte(blr, field->fld_scale); break; case blr_text: case blr_varying: add_word(blr, field->fld_length); break; } if (field->fld_type == blr_varying) field_length += sizeof(USHORT); add_byte(blr, isc_sdl_rid); add_word(blr, relation->rel_id); add_byte(blr, isc_sdl_fid); add_word(blr, field->fld_id); USHORT count = 0; for (const SLONG* range = field->fld_ranges; range < end_ranges; range += 2, count++) { add_byte(blr, isc_sdl_do2); add_byte(blr, count); add_byte(blr, isc_sdl_long_integer); add_long(blr, range[0]); add_byte(blr, isc_sdl_long_integer); add_long(blr, range[1]); } add_byte(blr, isc_sdl_element); add_byte(blr, 1); add_byte(blr, isc_sdl_scalar); add_byte(blr, 0); add_byte(blr, field->fld_dimensions); for (count = 0; count < field->fld_dimensions; count++) { add_byte(blr, isc_sdl_variable); add_byte(blr, count); } add_byte(blr, isc_sdl_eoc); #ifdef DEBUG if (debug_on) PRETTY_print_sdl(blr_buffer, NULL, NULL, 0); #endif const USHORT blr_length = blr - blr_buffer; // compute the range size for each dimension = high_range - low_range ULONG slice_length = field_length; for (const SLONG* range = field->fld_ranges; range < end_ranges; range += 2) { slice_length *= (range[1] - range[0] + 1); if (tdgbl->gbl_sw_transportable) xdr_buffer.lstr_length *= (range[1] - range[0] + 1); } UCHAR* slice = BURP_alloc(slice_length); // allocate space for the XDR representation if (tdgbl->gbl_sw_transportable) { xdr_buffer.lstr_address = BURP_alloc(xdr_buffer.lstr_length); xdr_buffer.lstr_allocated = xdr_buffer.lstr_length; } ISC_STATUS_ARRAY status_vector; ULONG return_length = 0; if (isc_get_slice(status_vector, &DB, &gds_trans, blob_id, blr_length, (const char*) blr_buffer, 0, // param length for subset of an array handling NULL, // param for subset of an array handling slice_length, slice, (SLONG*) &return_length)) { BURP_print(81, field->fld_name); // msg 81 error accessing blob field %s -- continuing BURP_print_status(status_vector); #ifdef DEBUG PRETTY_print_sdl(blr_buffer, NULL, NULL, 0); #endif // CVC: At this point I would expected calls to deallocate memory // See the end of this function. BURP_free(slice); if (xdr_buffer.lstr_allocated) BURP_free(xdr_buffer.lstr_address); return; } if (return_length != slice_length) { // Ugh. The full array wasn't returned. We must recompute the top // element to backup. SLONG returned_elements = (return_length / field_length) - 1; SLONG* returned_range = range_buffer; const SLONG* range = end_ranges - 2; for (int i1 = 0, i3 = 0; range >= field->fld_ranges; range -= 2, returned_range++, i1++) { int divisor = 1; for (int i2 = (2 * (i1 + 1) + 1); i2 <= field->fld_dimensions * 2; i2 += 2) { divisor *= (field->fld_ranges[i2] - field->fld_ranges[i2 - 1] + 1); } *returned_range = (returned_elements - 1) / divisor + field->fld_ranges[i3]; returned_elements -= (*returned_range - field->fld_ranges[i3]) * divisor; i3 += 2; } } put(tdgbl, (UCHAR) rec_array); put_numeric(att_blob_field_number, field->fld_number); put_numeric(att_array_dimensions, field->fld_dimensions); SLONG* returned_range = range_buffer; for (const SLONG* range = field->fld_ranges; range < end_ranges; range += 2, returned_range++) { put_numeric(att_array_range_low, (int) range[0]); if (return_length == slice_length) put_numeric(att_array_range_high, (int) range[1]); else put_numeric(att_array_range_high, (int) *returned_range); } put(tdgbl, att_blob_data); put(tdgbl, (UCHAR) (return_length)); put(tdgbl, (UCHAR) (return_length >> 8)); put(tdgbl, (UCHAR) (return_length >> 16)); put(tdgbl, (UCHAR) (return_length >> 24)); if (return_length) { const UCHAR* p; if (tdgbl->gbl_sw_transportable) { lstring xdr_slice; xdr_slice.lstr_allocated = xdr_slice.lstr_length = return_length; xdr_slice.lstr_address = slice; return_length = CAN_slice(&xdr_buffer, &xdr_slice, TRUE, /*blr_length,*/ blr_buffer); put(tdgbl, att_xdr_array); put(tdgbl, (UCHAR) (return_length)); put(tdgbl, (UCHAR) (return_length >> 8)); put(tdgbl, (UCHAR) (return_length >> 16)); put(tdgbl, (UCHAR) (return_length >> 24)); p = xdr_buffer.lstr_address; } else p = slice; put_block(tdgbl, p, return_length); } BURP_free(slice); if (xdr_buffer.lstr_allocated) BURP_free(xdr_buffer.lstr_address); } void put_asciz( const att_type attribute, const TEXT* string) { /************************************** * * p u t _ a s c i z * ************************************** * * Functional description * Write an attribute starting with a null terminated string. * Currently it's only called by write_database with the db's name as param. * **************************************/ BurpGlobals* tdgbl = BurpGlobals::getSpecific(); ULONG l = strlen(string); // CVC: We'll have to ensure that length < MAX_FILE_NAME_SIZE. // For now, we'll truncate silently until we define a message. // We can't honor operating systems that allow longer file names. if (l >= MAX_FILE_NAME_SIZE) { //BURP_print(CREATE A MESSAGE, SafeArg() << string << (MAX_FILE_NAME_SIZE - 1)); // msg ZZZ: name %s too large, truncating to %d bytes. l = MAX_FILE_NAME_SIZE - 1; } put(tdgbl, attribute); put(tdgbl, (UCHAR) l); if (l) put_block(tdgbl, (const UCHAR*) string, l); } void put_blob( burp_fld* field, ISC_QUAD& blob_id) { /************************************** * * p u t _ b l o b * ************************************** * * Functional description * Write out a blob. If, however, it's null, don't even bother. * This is for user data blobs. * **************************************/ ISC_STATUS_ARRAY status_vector; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); // If the blob is null, don't store it. It will be restored as null. if (UserBlob::blobIsNull(blob_id)) return; // Open the blob and get it's vital statistics UserBlob blob(status_vector); if (!blob.open(DB, gds_trans, blob_id)) { BURP_print(81, field->fld_name); // msg 81 error accessing blob field %s -- continuing BURP_print_status(status_vector); return; } UCHAR blob_info[32]; if (!blob.getInfo(sizeof(blob_items), blob_items, sizeof(blob_info), blob_info)) { BURP_error_redirect(status_vector, 20); // msg 20 isc_blob_info failed } put(tdgbl, (UCHAR) rec_blob); put_numeric(att_blob_field_number, field->fld_number); ULONG segments = 0, total_length = 0; USHORT max_segment = 0; int blob_type = 0; // 0 - segmented, 1 - stream const UCHAR* p = blob_info; UCHAR item; while ((item = *p++) != isc_info_end) { const USHORT l = gds__vax_integer(p, 2); p += 2; const ULONG n = gds__vax_integer(p, l); p += l; switch (item) { case isc_info_blob_max_segment: max_segment = n; break; case isc_info_blob_type: blob_type = n; break; case isc_info_blob_num_segments: segments = n; break; case isc_info_blob_total_length: total_length = n; break; default: BURP_error_redirect(NULL, 21, SafeArg() << int(item)); // msg 21 don't understand blob info item %ld } } // NS: Compute number of chunks we are going to write for stream blob based // on total blob length and maximum segment size. This way we tend to // preserve maximum internal segment size over backup/restore. I'm not sure // this is beneficial, but let's do it for the moment instead of inventing // our own chunk size. Note, the number of segments returned by information // call for stream blob is always unreliable, even for zero-length blobs if (blob_type == 1) { if (total_length != 0) segments = (total_length + max_segment - 1) / max_segment; else segments = 0; } put_numeric(att_blob_max_segment, max_segment); put_numeric(att_blob_number_segments, segments); put_numeric(att_blob_type, blob_type); // Allocate a buffer large enough for the largest segment and start grinding. UCHAR static_buffer[1024]; UCHAR* buffer; if (!max_segment || max_segment <= sizeof(static_buffer)) buffer = static_buffer; else buffer = BURP_alloc(max_segment); put(tdgbl, att_blob_data); while (segments > 0) { size_t segment_length; blob.getSegment(max_segment, buffer, segment_length); const ISC_STATUS status = blob.getCode(); // Handle the errors. For stream blob isc_segment is not error here. if (status && (status != isc_segment || blob_type == 0)) { BURP_error_redirect(status_vector, 22); // msg 22 isc_get_segment failed } put(tdgbl, (UCHAR) (segment_length)); put(tdgbl, (UCHAR) (segment_length >> 8)); if (segment_length) { put_block(tdgbl, buffer, segment_length); } --segments; } if (!blob.close()) BURP_error_redirect(status_vector, 23); // msg 23 isc_close_blob failed if (buffer != static_buffer) BURP_free(buffer); } bool put_blr_blob( att_type attribute, ISC_QUAD& blob_id) { /************************************** * * p u t _ b l r _ b l o b * ************************************** * * Functional description * Write out a blr blob, if present. Otherwise do nothing. * Return true if the blob was present, false otherwise. * **************************************/ ISC_STATUS_ARRAY status_vector; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); // If the blob is null, don't store it. It will be restored as null. if (UserBlob::blobIsNull(blob_id)) return false; // Open the blob and get it's vital statistics UserBlob blob(status_vector); if (!blob.open(DB, gds_trans, blob_id)) { BURP_error_redirect(status_vector, 24); // msg 24 isc_open_blob failed } UCHAR blob_info[32]; if (!blob.getInfo(sizeof(blr_items), blr_items, sizeof(blob_info), blob_info)) { BURP_error_redirect(status_vector, 20); // msg 20 isc_blob_info failed } ULONG length = 0; USHORT max_segment = 0; const UCHAR* p = blob_info; UCHAR item; while ((item = *p++) != isc_info_end) { const USHORT l = isc_vax_integer((const char*) p, 2); p += 2; const ULONG n = isc_vax_integer((const char*) p, l); p += l; switch (item) { case isc_info_blob_max_segment: max_segment = n; break; case isc_info_blob_total_length: length = n; break; default: BURP_print(79, SafeArg() << int(item)); // msg 79 don't understand blob info item %ld if (!blob.close()) BURP_error_redirect(status_vector, 23); // msg 23 isc_close_blob failed return false; } } if (!length) { if (!blob.close()) BURP_error_redirect(status_vector, 23); // msg 23 isc_close_blob failed return false; } // Rdb sometimes gets the length messed up if (length < max_segment) length = max_segment; put_numeric(attribute, (int) length); // Allocate a buffer large enough for the largest segment and start grinding. UCHAR static_buffer[1024]; UCHAR* buffer; if (!max_segment || max_segment <= sizeof(static_buffer)) buffer = static_buffer; else buffer = BURP_alloc(max_segment); // The old code didn't accept isc_segment so we check it. size_t segment_length; while (blob.getSegment(max_segment, buffer, segment_length) && !blob.getCode()) { if (segment_length) { put_block(tdgbl, buffer, segment_length); } } if (!blob.close()) { BURP_error_redirect(status_vector, 23); // msg 23 isc_close_blob failed } if (buffer != static_buffer) BURP_free(buffer); return true; } void put_data(burp_rel* relation) { /************************************** * * p u t _ d a t a * ************************************** * * Functional description * Write relation meta-data and data. * **************************************/ burp_fld* field; ISC_STATUS_ARRAY status_vector; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); // CVC: A signed short isn't enough if the engine allows near 32K fields, // each being char(1) ASCII in the worst case. Looking at BLR generation // below, it's clear an extreme case won't compile => blr_length >= 32K. // However, SSHORT is the limit for request_length in isc_compile_request. SSHORT field_count = 1; for (field = relation->rel_fields; field; field = field->fld_next) { if (!(field->fld_flags & FLD_computed)) { field_count += 2; } } fb_assert(field_count > 0 && field_count * 9 > 0 && field_count * 9 + 200 > 0); // Time to generate blr to fetch data. Make sure we allocate a BLR buffer // large enough to handle the per field overhead UCHAR* const blr_buffer = BURP_alloc(200 + field_count * 9); UCHAR* blr = blr_buffer; add_byte(blr, blr_version4); add_byte(blr, blr_begin); add_byte(blr, blr_message); add_byte(blr, 0); // Message number add_word(blr, field_count); // Number of fields, counting eof RCRD_OFFSET offset = 0; SSHORT count = 0; // This is param count. for (field = relation->rel_fields; field; field = field->fld_next) { if (field->fld_flags & FLD_computed) continue; SSHORT alignment = 4; FLD_LENGTH length = field->fld_length; SSHORT dtype = field->fld_type; if (field->fld_flags & FLD_array) { dtype = blr_blob; length = 8; } switch (dtype) { case blr_text: alignment = type_alignments[dtype_text]; add_byte(blr, field->fld_type); add_word(blr, field->fld_length); break; case blr_varying: alignment = type_alignments[dtype_varying]; add_byte(blr, field->fld_type); add_word(blr, field->fld_length); length += sizeof(USHORT); break; case blr_short: alignment = type_alignments[dtype_short]; add_byte(blr, field->fld_type); add_byte(blr, field->fld_scale); break; case blr_long: alignment = type_alignments[dtype_long]; add_byte(blr, field->fld_type); add_byte(blr, field->fld_scale); break; case blr_quad: alignment = type_alignments[dtype_quad]; add_byte(blr, field->fld_type); add_byte(blr, field->fld_scale); break; case blr_int64: alignment = type_alignments[dtype_int64]; add_byte(blr, field->fld_type); add_byte(blr, field->fld_scale); break; case blr_double: alignment = type_alignments[dtype_double]; add_byte(blr, field->fld_type); break; case blr_timestamp: alignment = type_alignments[dtype_timestamp]; add_byte(blr, field->fld_type); break; case blr_sql_time: alignment = type_alignments[dtype_sql_time]; add_byte(blr, field->fld_type); break; case blr_sql_date: alignment = type_alignments[dtype_sql_date]; add_byte(blr, field->fld_type); break; case blr_float: alignment = type_alignments[dtype_real]; add_byte(blr, field->fld_type); break; case blr_blob: alignment = type_alignments[dtype_blob]; add_byte(blr, blr_quad); add_byte(blr, 0); break; default: BURP_error_redirect(NULL, 26, SafeArg() << field->fld_type); // msg 26 datatype %ld not understood break; } if (alignment) offset = FB_ALIGN(offset, alignment); field->fld_offset = offset; field->fld_parameter = count++; offset += length; } // Next, build fields for null flags for (field = relation->rel_fields; field; field = field->fld_next) { if (field->fld_flags & FLD_computed) continue; add_byte(blr, blr_short); add_byte(blr, 0); offset = FB_ALIGN(offset, sizeof(SSHORT)); field->fld_missing_parameter = count++; offset += sizeof(SSHORT); } // Finally, make up an EOF field add_byte(blr, blr_short); // eof field add_byte(blr, 0); // scale for eof field SSHORT eof_parameter = count++; RCRD_OFFSET record_length = offset; RCRD_OFFSET eof_offset = FB_ALIGN(offset, sizeof(SSHORT)); // To be used later for the buffer size to receive data const FLD_LENGTH length = (USHORT) (eof_offset + sizeof(SSHORT)); // Build FOR loop, body, and eof handler add_byte(blr, blr_for); add_byte(blr, blr_rse); add_byte(blr, 1); // count of relations add_byte(blr, blr_rid); add_word(blr, relation->rel_id); add_byte(blr, 0); // context variable add_byte(blr, blr_end); add_byte(blr, blr_send); add_byte(blr, 0); add_byte(blr, blr_begin); add_byte(blr, blr_assignment); add_byte(blr, blr_literal); add_byte(blr, blr_short); add_byte(blr, 0); add_word(blr, 1); add_byte(blr, blr_parameter); add_byte(blr, 0); add_word(blr, eof_parameter); for (field = relation->rel_fields; field; field = field->fld_next) { if (field->fld_flags & FLD_computed) continue; add_byte(blr, blr_assignment); add_byte(blr, blr_fid); add_byte(blr, 0); add_word(blr, field->fld_id); add_byte(blr, blr_parameter2); add_byte(blr, 0); add_word(blr, field->fld_parameter); add_word(blr, field->fld_missing_parameter); } add_byte(blr, blr_end); add_byte(blr, blr_send); add_byte(blr, 0); add_byte(blr, blr_assignment); add_byte(blr, blr_literal); add_byte(blr, blr_short); add_byte(blr, 0); add_word(blr, 0); add_byte(blr, blr_parameter); add_byte(blr, 0); add_word(blr, eof_parameter); add_byte(blr, blr_end); add_byte(blr, blr_eoc); SSHORT blr_length = blr - blr_buffer; #ifdef DEBUG if (debug_on) fb_print_blr(blr_buffer, blr_length, NULL, NULL, 0); #endif // Compile request FB_API_HANDLE request = 0; if (isc_compile_request(status_vector, &DB, &request, blr_length, (const SCHAR*) blr_buffer)) { BURP_error_redirect(status_vector, 27); // msg 27 isc_compile_request failed fb_print_blr(blr_buffer, blr_length, NULL, NULL, 0); } BURP_free(blr_buffer); BURP_verbose(142, relation->rel_name); // msg 142 writing data for relation %s if (isc_start_request(status_vector, &request, &gds_trans, 0)) { BURP_error_redirect(status_vector, 28); // msg 28 isc_start_request failed } // Here is the crux of the problem -- writing data. All this work // for the following small loop. UCHAR* buffer = BURP_alloc(length); SSHORT* eof = (SSHORT *) (buffer + eof_offset); // the XDR representation may be even fluffier lstring xdr_buffer; if (tdgbl->gbl_sw_transportable) { xdr_buffer.lstr_length = xdr_buffer.lstr_allocated = length + count * 3; xdr_buffer.lstr_address = BURP_alloc(xdr_buffer.lstr_length); } else xdr_buffer.lstr_address = NULL; ULONG records = 0; while (true) { if (isc_receive(status_vector, &request, 0, length, buffer, 0)) { BURP_error_redirect(status_vector, 29); // msg 29 isc_receive failed } if (!*eof) break; records++; // Verbose records if ((records % BACKUP_VERBOSE_INTERVAL) == 0) BURP_verbose(108, SafeArg() << records); put(tdgbl, (UCHAR) rec_data); put_numeric(att_data_length, record_length); const UCHAR* p; if (tdgbl->gbl_sw_transportable) { record_length = CAN_encode_decode(relation, &xdr_buffer, buffer, TRUE); put_numeric(att_xdr_length, record_length); p = xdr_buffer.lstr_address; } else p = buffer; put(tdgbl, att_data_data); if (tdgbl->gbl_sw_compress) compress(p, record_length); else if (record_length) put_block(tdgbl, p, record_length); // Look for any blobs to write for (field = relation->rel_fields; field; field = field->fld_next) { if (field->fld_type == blr_blob && !(field->fld_flags & FLD_computed) && !(field->fld_flags & FLD_array)) { put_blob(field, *(ISC_QUAD*) (buffer + field->fld_offset)); } } // Look for any array to write // we got back the blob_id for the array from isc_receive in the second param. for (field = relation->rel_fields; field; field = field->fld_next) { if (field->fld_flags & FLD_array) { put_array(field, relation, (ISC_QUAD*) (buffer + field->fld_offset)); } } } BURP_free(buffer); if (xdr_buffer.lstr_address) BURP_free(xdr_buffer.lstr_address); BURP_verbose(108, SafeArg() << records); // msg 108 %ld records written if (isc_release_request(status_vector, &request)) BURP_error_redirect(status_vector, 30); // msg 30 isc_release_request failed } void put_index( burp_rel* relation) { /************************************** * * p u t _ i n d e x * ************************************** * * Functional description * Write information about an index. First * check that all the segments of the * index exist. * **************************************/ ULONG count; TEXT temp[GDS_NAME_LEN]; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); // if we have all capabilities, use the first request to get the // most performance out of the latest engine; if we don't // have one of the capabilities we must use the second set of // requests--this requires more code but it is well worth it // for the performance benefits, especially remotely--deej if ((tdgbl->BCK_capabilities & BCK_idx_inactive) && (tdgbl->BCK_capabilities & BCK_attributes_v3) && (tdgbl->BCK_capabilities & BCK_ods8)) { FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle1) X IN RDB$INDICES WITH X.RDB$RELATION_NAME EQ relation->rel_name count = 0; FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle2) I_S IN RDB$INDEX_SEGMENTS CROSS RFR IN RDB$RELATION_FIELDS WITH I_S.RDB$FIELD_NAME = RFR.RDB$FIELD_NAME AND I_S.RDB$INDEX_NAME = X.RDB$INDEX_NAME AND RFR.RDB$RELATION_NAME = relation->rel_name count++; END_FOR; ON_ERROR general_on_error(); END_ERROR; if (count != (ULONG) X.RDB$SEGMENT_COUNT) { BURP_print(180, SafeArg() << X.RDB$INDEX_NAME << count << X.RDB$SEGMENT_COUNT); continue; } put(tdgbl, rec_index); const ULONG l = PUT_TEXT (att_index_name, X.RDB$INDEX_NAME); MISC_terminate (X.RDB$INDEX_NAME, temp, l, sizeof(temp)); BURP_verbose (151, temp); // msg 151 writing index %s put_numeric (att_segment_count, X.RDB$SEGMENT_COUNT); put_numeric (att_index_inactive, X.RDB$INDEX_INACTIVE); put_numeric (att_index_unique_flag, X.RDB$UNIQUE_FLAG); FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle5) Y IN RDB$INDEX_SEGMENTS WITH Y.RDB$INDEX_NAME EQ X.RDB$INDEX_NAME SORTED BY Y.RDB$FIELD_POSITION PUT_TEXT (att_index_field_name, Y.RDB$FIELD_NAME); END_FOR; ON_ERROR general_on_error(); END_ERROR; put_source_blob (att_index_description2, att_index_description, X.RDB$DESCRIPTION); put_numeric (att_index_type, X.RDB$INDEX_TYPE); if (!X.RDB$EXPRESSION_SOURCE.NULL) put_source_blob (att_index_expression_source, att_index_expression_source, X.RDB$EXPRESSION_SOURCE); if (!X.RDB$EXPRESSION_BLR.NULL) put_blr_blob (att_index_expression_blr, X.RDB$EXPRESSION_BLR); if (!X.RDB$FOREIGN_KEY.NULL) PUT_TEXT (att_index_foreign_key, X.RDB$FOREIGN_KEY); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } else { FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle1) X IN RDB$INDICES WITH X.RDB$RELATION_NAME EQ relation->rel_name count = 0; FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle2) I_S IN RDB$INDEX_SEGMENTS WITH I_S.RDB$INDEX_NAME = X.RDB$INDEX_NAME bool match = false; FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle3) RFR IN RDB$RELATION_FIELDS WITH I_S.RDB$FIELD_NAME = RFR.RDB$FIELD_NAME AND RFR.RDB$RELATION_NAME = relation->rel_name match = true; END_FOR; ON_ERROR general_on_error(); END_ERROR; if (!match) BURP_print (179, SafeArg() << I_S.RDB$FIELD_NAME << X.RDB$INDEX_NAME); else count++; END_FOR; ON_ERROR general_on_error(); END_ERROR; if (count != (ULONG) X.RDB$SEGMENT_COUNT) { BURP_print(180, SafeArg() << X.RDB$INDEX_NAME << count << X.RDB$SEGMENT_COUNT); continue; } put(tdgbl, rec_index); const ULONG l = PUT_TEXT (att_index_name, X.RDB$INDEX_NAME); MISC_terminate (X.RDB$INDEX_NAME, temp, l, sizeof(temp)); BURP_verbose (151, temp); // msg 151 writing index %s put_numeric (att_segment_count, X.RDB$SEGMENT_COUNT); if (tdgbl->BCK_capabilities & BCK_idx_inactive) FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle4) I IN RDB$INDICES WITH I.RDB$INDEX_NAME = X.RDB$INDEX_NAME put_numeric (att_index_inactive, I.RDB$INDEX_INACTIVE); END_FOR; ON_ERROR general_on_error(); END_ERROR; put_numeric (att_index_unique_flag, X.RDB$UNIQUE_FLAG); FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle5) Y IN RDB$INDEX_SEGMENTS WITH Y.RDB$INDEX_NAME EQ X.RDB$INDEX_NAME SORTED BY Y.RDB$FIELD_POSITION PUT_TEXT (att_index_field_name, Y.RDB$FIELD_NAME); END_FOR; ON_ERROR general_on_error(); END_ERROR; put_source_blob (att_index_description2, att_index_description, X.RDB$DESCRIPTION); if (tdgbl->BCK_capabilities & BCK_attributes_v3) FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle6) I IN RDB$INDICES WITH I.RDB$INDEX_NAME = X.RDB$INDEX_NAME put_numeric (att_index_type, I.RDB$INDEX_TYPE); END_FOR; ON_ERROR general_on_error(); END_ERROR; if (tdgbl->BCK_capabilities & BCK_ods8) FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle7) I IN RDB$INDICES WITH I.RDB$INDEX_NAME = X.RDB$INDEX_NAME if (!I.RDB$EXPRESSION_SOURCE.NULL) put_source_blob (att_index_expression_source, att_index_expression_source, I.RDB$EXPRESSION_SOURCE); if (!I.RDB$EXPRESSION_BLR.NULL) put_blr_blob (att_index_expression_blr, I.RDB$EXPRESSION_BLR); if (!I.RDB$FOREIGN_KEY.NULL) PUT_TEXT (att_index_foreign_key, I.RDB$FOREIGN_KEY); END_FOR; ON_ERROR general_on_error(); END_ERROR; put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } } int put_message( att_type attribute, att_type attribute2, const TEXT* text, const ULONG length) { /************************************** * * p u t _ m e s s a g e * ************************************** * * Functional description * Write a variable length text string, with embedded * blanks. Same as put_text but handles embedded blanks. * CVC: As v6 time, put_text handles embedded blanks, too! * The only difference is that put_text's length is SSHORT, so * in theory put_message can handle much longer input and it's * used for exception and trigger's messages (plus update/delete * rules for FKs and constraint types, where it's irrelevant * which function of the two you use). * CVC: Responsability for FKs and constraint types transferred to put_text. * This functions tries to maintain backwards compatibility where possible. * **************************************/ BurpGlobals* tdgbl = BurpGlobals::getSpecific(); ULONG l = 0; for (const TEXT* p = text; *p && l < length; p++) l++; const ULONG newlen = MIN(l, length); fb_assert(newlen <= MAX_USHORT); // If we can store the message using the old format, we do it. if (newlen <= MAX_UCHAR) { put(tdgbl, attribute); put(tdgbl, (UCHAR) newlen); } else if (newlen <= MAX_USHORT) { if (!attribute2) // In theory, this never happens, because the caller knows what it's doing. BURP_error(314, ""); put(tdgbl, attribute2); USHORT vax_value = (USHORT) newlen; vax_value = (USHORT) gds__vax_integer((const UCHAR*) &vax_value, sizeof(vax_value)); put_block(tdgbl, (const UCHAR*) &vax_value, sizeof(vax_value)); } else BURP_error(315, ""); if (newlen) put_block(tdgbl, reinterpret_cast(text), newlen); return newlen; } void put_numeric( att_type attribute, SLONG value) { /************************************** * * p u t _ n u m e r i c * ************************************** * * Functional description * Write a numeric value as an attribute. The number is represented * low byte first, high byte last, as in VAX. * **************************************/ BurpGlobals* tdgbl = BurpGlobals::getSpecific(); const SLONG vax_value = (SLONG) isc_vax_integer((const char*) &value, sizeof(value)); put(tdgbl, attribute); put(tdgbl, (UCHAR) sizeof(value)); put_block(tdgbl, (const UCHAR*) &vax_value, sizeof(vax_value)); } void put_int64( att_type attribute, SINT64 value) { /************************************** * * p u t _ i n t 6 4 * ************************************** * * Functional description * Write a 64-bit numeric value as an attribute. * The number is represented low byte first, high byte last, as in VAX. * This function is just like put_numeric, except that it handles an * INT64 value, while put_numeric handles a 32-bit value. * **************************************/ BurpGlobals* tdgbl = BurpGlobals::getSpecific(); const FB_UINT64 le_value = (FB_UINT64) isc_portable_integer((const UCHAR*) &value, sizeof(value)); put(tdgbl, attribute); put(tdgbl, (UCHAR) sizeof(value)); put_block(tdgbl, (const UCHAR*) &le_value, sizeof(le_value)); } void put_relation( burp_rel* relation) { /************************************** * * p u t _ r e l a t i o n * ************************************** * * Functional description * Write relation meta-data and data. * **************************************/ TEXT temp[GDS_NAME_LEN]; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); // Write local field information. This is made slightly more complicated // by the requirement that computational fields be aligned. burp_fld* aligned = NULL; burp_fld* unaligned = NULL; burp_fld* aligned4 = NULL; burp_fld* aligned8 = NULL; burp_fld* fields = get_fields(relation); // sort the list of fields into three lists, depending on alignment burp_fld* field; for (field = fields; field = fields;) { fields = field->fld_next; USHORT l = field->fld_length; if (field->fld_type == blr_varying) l += sizeof(USHORT); if (!(l & 7)) { field->fld_next = aligned8; aligned8 = field; } else if (!(l & 3)) { field->fld_next = aligned4; aligned4 = field; } else if (l & 1) { field->fld_next = unaligned; unaligned = field; } else { field->fld_next = aligned; aligned = field; } } // Next, merge the aligned and unaligned sub-lists. In the process, // re-create (approximately) the original order of the fields. This is // not strictly required, but it certainly is polite. while (field = unaligned) { unaligned = field->fld_next; field->fld_next = relation->rel_fields; relation->rel_fields = field; } while (field = aligned) { aligned = field->fld_next; field->fld_next = relation->rel_fields; relation->rel_fields = field; } while (field = aligned4) { aligned4 = field->fld_next; field->fld_next = relation->rel_fields; relation->rel_fields = field; } while (field = aligned8) { aligned8 = field->fld_next; field->fld_next = relation->rel_fields; relation->rel_fields = field; } // Now write the fields in what will become physical backup order for (field = relation->rel_fields; field; field = field->fld_next) { put(tdgbl, (UCHAR) rec_field); const USHORT l = PUT_TEXT(att_field_name, field->fld_name); MISC_terminate(field->fld_name, temp, l, sizeof(temp)); BURP_verbose(144, temp); // msg 144 writing field %s PUT_TEXT(att_field_source, field->fld_source); if (field->fld_query_name[0]) PUT_TEXT(att_field_query_name, field->fld_query_name); if (field->fld_complex_name[0]) PUT_TEXT(att_field_complex_name, field->fld_complex_name); if (field->fld_edit_string[0]) PUT_TEXT(att_field_edit_string, field->fld_edit_string); put_source_blob(att_field_description2, att_field_description, field->fld_description); put_source_blob(att_field_query_header, att_field_query_header, field->fld_query_header); if (field->fld_security_class[0]) PUT_TEXT(att_field_security_class, field->fld_security_class); if (!(field->fld_flags & FLD_position_missing)) put_numeric(att_field_position, field->fld_position); put_numeric(att_field_type, field->fld_type); put_numeric(att_field_length, field->fld_length); put_numeric(att_field_sub_type, field->fld_sub_type); put_numeric(att_field_scale, field->fld_scale); put_numeric(att_field_number, field->fld_number); put_numeric(att_field_system_flag, field->fld_system_flag); if (!(field->fld_flags & FLD_update_missing)) put_numeric(att_field_update_flag, field->fld_update_flag); if (field->fld_flags & FLD_null_flag) put_numeric(att_field_null_flag, field->fld_null_flag); if (field->fld_flags & FLD_charset_flag) put_numeric(att_field_character_set, field->fld_character_set_id); if (field->fld_flags & FLD_collate_flag) put_numeric(att_field_collation_id, field->fld_collation_id); put_blr_blob(att_field_default_value, field->fld_default_value); put_source_blob(att_field_default_source, att_field_default_source, field->fld_default_source); if (relation->rel_flags & REL_view) { put_numeric(att_view_context, field->fld_view_context); if (field->fld_base[0]) PUT_TEXT(att_base_field, field->fld_base); } if (field->fld_flags & FLD_computed) put_numeric(att_field_computed_flag, TRUE); if (field->fld_flags & FLD_array) { put_numeric(att_field_dimensions, field->fld_dimensions); const SLONG* rp = field->fld_ranges; for (USHORT n = field->fld_dimensions; n; rp += 2, n--) { put_numeric(att_field_range_low, *rp); put_numeric(att_field_range_high, *(rp + 1)); } } put(tdgbl, att_end); } // Write out view relations (if a view, of course) if (relation->rel_flags & REL_view) { if (tdgbl->BCK_capabilities & BCK_context_name) { FOR (REQUEST_HANDLE tdgbl->handles_put_relation_req_handle1) X IN RDB$VIEW_RELATIONS WITH X.RDB$VIEW_NAME EQ relation->rel_name put(tdgbl, rec_view); PUT_TEXT (att_view_relation_name, X.RDB$RELATION_NAME); put_numeric (att_view_context_id, X.RDB$VIEW_CONTEXT); PUT_TEXT (att_view_context_name, X.RDB$CONTEXT_NAME); put(tdgbl, att_end); END_FOR ON_ERROR general_on_error(); END_ERROR; } else { FOR (REQUEST_HANDLE tdgbl->handles_put_relation_req_handle2) X IN RDB$VIEW_RELATIONS WITH X.RDB$VIEW_NAME EQ relation->rel_name put(tdgbl, rec_view); PUT_TEXT (att_view_relation_name, X.RDB$RELATION_NAME); put_numeric (att_view_context_id, X.RDB$VIEW_CONTEXT); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } } put(tdgbl, (UCHAR) rec_relation_end); } bool put_source_blob(att_type attribute, att_type old_attribute, ISC_QUAD& blob_id) { /************************************** * * p u t _ s o u r c e _ b l o b * ************************************** * * Functional description * Write out a source blob or query header if present. * Return true is there was the blob was present, false otherwise. * Include the NULL character to separate each segment. * **************************************/ ISC_STATUS_ARRAY status_vector; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); // If the blob is null, don't store it. It will be restored as null. if (UserBlob::blobIsNull(blob_id)) return false; if (tdgbl->gbl_sw_old_descriptions && attribute != att_field_query_header) return put_blr_blob(old_attribute, blob_id); // Open the blob and get it's vital statistics UserBlob blob(status_vector); if (!blob.open(DB, gds_trans, blob_id)) { BURP_error_redirect(status_vector, 24); // msg 24 isc_open_blob failed } UCHAR blob_info[48]; if (!blob.getInfo(sizeof(source_items), source_items, sizeof(blob_info), blob_info)) { BURP_error_redirect(status_vector, 20); // msg 20 isc_blob_info failed } ULONG length = 0; ULONG num_seg = 0; USHORT max_segment = 0; const UCHAR* p = blob_info; UCHAR item; while ((item = *p++) != isc_info_end) { const USHORT l = gds__vax_integer(p, 2); p += 2; const ULONG n = gds__vax_integer(p, l); p += l; switch (item) { case isc_info_blob_max_segment: max_segment = n; break; case isc_info_blob_total_length: length = n; break; case isc_info_blob_num_segments: num_seg = n; break; default: BURP_print(79, SafeArg() << int(item)); // msg 79 don't understand blob info item %ld if (!blob.close()) { BURP_error_redirect(status_vector, 23); // msg 23 isc_close_blob failed } return false; } } if (!length) { if (!blob.close()) { BURP_error_redirect(status_vector, 23); // msg 23 isc_close_blob failed } return false; } // Rdb sometimes gets the length messed up if (length < max_segment) length = max_segment; fb_assert(FB_UINT64(length) + num_seg <= FB_UINT64(MAX_ULONG)); put_numeric(attribute, length + num_seg); // Allocate a buffer large enough for the largest segment and start grinding. UCHAR static_buffer[1024]; UCHAR* buffer; if (!max_segment || max_segment <= sizeof(static_buffer)) buffer = static_buffer; else buffer = BURP_alloc(max_segment); // The old code didn't accept isc_segment so we check it. size_t segment_length; while (blob.getSegment(max_segment, buffer, segment_length) && !blob.getCode()) { if (segment_length) { put_block(tdgbl, buffer, segment_length); } put(tdgbl, (UCHAR) 0); } if (!blob.close()) BURP_error_redirect(status_vector, 23); // msg 23 isc_close_blob failed if (buffer != static_buffer) BURP_free(buffer); return true; } int put_text( att_type attribute, const TEXT* text, SSHORT size_len) { /************************************** * * p u t _ t e x t * ************************************** * * Functional description * Write a variable length text string, with embedded spaces. * Truncate trailing spaces. * Now this routine does not truncate trailing spaces, 3-2002 MOD * transfering changes from fb1, I believe this is to do with problems * with quoted names and embedded spaces. * CVC: This routine does trailing spaces truncation, but correctly. * **************************************/ BurpGlobals* tdgbl = BurpGlobals::getSpecific(); const SSHORT l = (SSHORT) MISC_symbol_length(text, (ULONG) size_len); fb_assert(l <= MAX_UCHAR); put(tdgbl, attribute); put(tdgbl, (UCHAR) l); if (l) put_block(tdgbl, (const UCHAR*) text, l); return l; } void set_capabilities() { /************************************** * * s e t _ c a p a b i l i t i e s * ************************************** * * Functional description * * set the capabilities bits for the * database being extracted to avoid * unpleasantness later. * **************************************/ BurpGlobals* tdgbl = BurpGlobals::getSpecific(); FB_API_HANDLE req = 0; // Look for desireable fields in system relations for (const rfr_tab_t* rel_field_table = rfr_table; rel_field_table->relation; rel_field_table++) { const TEXT* field = rel_field_table->field; const TEXT* relation = rel_field_table->relation; FOR (REQUEST_HANDLE req) x IN RDB$RELATION_FIELDS WITH x.RDB$RELATION_NAME = relation AND x.RDB$FIELD_NAME = field tdgbl->BCK_capabilities |= rel_field_table->bit_mask; END_FOR; ON_ERROR general_on_error(); END_ERROR; } isc_release_request(isc_status, &req); } void write_character_sets() { /************************************** * * w r i t e _ c h a r a c t e r _ s e t s * ************************************** * * Functional description * write a record in the burp file for * each user defined character set. * **************************************/ isc_req_handle req_handle1 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); FOR (REQUEST_HANDLE req_handle1) X IN RDB$CHARACTER_SETS WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$DEFAULT_COLLATE_NAME NE X.RDB$CHARACTER_SET_NAME put(tdgbl, rec_charset); PUT_TEXT (att_charset_name, X.RDB$CHARACTER_SET_NAME); if (X.RDB$SYSTEM_FLAG.NULL || X.RDB$SYSTEM_FLAG != 1) { if (!X.RDB$FORM_OF_USE.NULL) PUT_TEXT (att_charset_form, X.RDB$FORM_OF_USE); if (!X.RDB$NUMBER_OF_CHARACTERS.NULL) put_numeric (att_charset_numchar, X.RDB$NUMBER_OF_CHARACTERS); put_numeric (att_charset_id, X.RDB$CHARACTER_SET_ID); if (X.RDB$SYSTEM_FLAG) put_numeric (att_charset_sysflag, X.RDB$SYSTEM_FLAG); if (!X.RDB$DESCRIPTION.NULL) { put_source_blob (att_charset_description, att_charset_description, X.RDB$DESCRIPTION); } if (!X.RDB$FUNCTION_NAME.NULL) PUT_TEXT (att_charset_funct, X.RDB$FUNCTION_NAME); put_numeric (att_charset_bytes_char, X.RDB$BYTES_PER_CHARACTER); } PUT_TEXT (att_charset_coll, X.RDB$DEFAULT_COLLATE_NAME); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; MISC_release_request_silent(req_handle1); } void write_check_constraints() { /************************************** * * w r i t e _ c h e c k _ c o n s t r a i n t s * ************************************** * * Functional description * write a record in the burp file for * each check constraint. * **************************************/ isc_req_handle req_handle1 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); FOR (REQUEST_HANDLE req_handle1) X IN RDB$CHECK_CONSTRAINTS put(tdgbl, rec_chk_constraint); PUT_TEXT (att_chk_constraint_name, X.RDB$CONSTRAINT_NAME); if (!X.RDB$TRIGGER_NAME.NULL) PUT_TEXT (att_chk_trigger_name, X.RDB$TRIGGER_NAME); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; MISC_release_request_silent(req_handle1); } void write_collations() { /************************************** * * w r i t e _ c o l l a t i o n s * ************************************** * * Functional description * write a record in the burp file for * each user defined collation * **************************************/ isc_req_handle req_handle1 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); if (tdgbl->BCK_capabilities & BCK_ods11) { FOR (REQUEST_HANDLE req_handle1) X IN RDB$COLLATIONS WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 put(tdgbl, rec_collation); PUT_TEXT (att_coll_name, X.RDB$COLLATION_NAME); put_numeric (att_coll_id, X.RDB$COLLATION_ID); put_numeric (att_coll_cs_id, X.RDB$CHARACTER_SET_ID); put_numeric (att_coll_attr, X.RDB$COLLATION_ATTRIBUTES); if (X.RDB$SYSTEM_FLAG) put_numeric (att_coll_sysflag, X.RDB$SYSTEM_FLAG); if (!X.RDB$DESCRIPTION.NULL) put_source_blob (att_coll_description, att_coll_description, X.RDB$DESCRIPTION); if (!X.RDB$FUNCTION_NAME.NULL) PUT_TEXT (att_coll_funct, X.RDB$FUNCTION_NAME); if (!X.RDB$BASE_COLLATION_NAME.NULL) PUT_TEXT(att_coll_base_collation_name, X.RDB$BASE_COLLATION_NAME); if (!X.RDB$SPECIFIC_ATTRIBUTES.NULL) put_source_blob (att_coll_specific_attr, att_coll_specific_attr, X.RDB$SPECIFIC_ATTRIBUTES); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } else { FOR (REQUEST_HANDLE req_handle1) X IN RDB$COLLATIONS WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 put(tdgbl, rec_collation); PUT_TEXT (att_coll_name, X.RDB$COLLATION_NAME); put_numeric (att_coll_id, X.RDB$COLLATION_ID); put_numeric (att_coll_cs_id, X.RDB$CHARACTER_SET_ID); put_numeric (att_coll_attr, X.RDB$COLLATION_ATTRIBUTES); if (X.RDB$SYSTEM_FLAG) put_numeric (att_coll_sysflag, X.RDB$SYSTEM_FLAG); if (!X.RDB$DESCRIPTION.NULL) put_source_blob (att_coll_description, att_coll_description, X.RDB$DESCRIPTION); if (!X.RDB$FUNCTION_NAME.NULL) PUT_TEXT (att_coll_funct, X.RDB$FUNCTION_NAME); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } MISC_release_request_silent(req_handle1); } void write_database( const TEXT* dbb_file) { /************************************** * * w r i t e _ d a t a b a s e * ************************************** * * Functional description * write a physical database record and a * logical database record in the burp file for * the database itself. * **************************************/ ISC_STATUS_ARRAY status_vector; SCHAR buffer[256]; isc_req_handle req_handle1 = 0, req_handle2 = 0, req_handle3 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); put(tdgbl, (UCHAR) rec_physical_db); if (isc_database_info(status_vector, &DB, sizeof(db_info_items), db_info_items, sizeof(buffer), buffer)) { BURP_error_redirect(status_vector, 31); // msg 31 isc_database_info failed } USHORT page_size = 0, forced_writes, no_reserve, SQL_dialect, db_read_only; ULONG sweep_interval, page_buffers; USHORT length = 0; for (const SCHAR* d = buffer; *d != isc_info_end; d += length) { const UCHAR item = *d++; length = (USHORT) isc_vax_integer(d, 2); d += 2; switch (item) { case isc_info_end: break; case isc_info_page_size: page_size = (USHORT) isc_vax_integer(d, length); put_numeric(att_page_size, page_size); break; case isc_info_sweep_interval: sweep_interval = isc_vax_integer(d, length); put_numeric(att_sweep_interval, sweep_interval); break; case isc_info_forced_writes: forced_writes = (USHORT) isc_vax_integer(d, length); put_numeric(att_forced_writes, forced_writes); break; case isc_info_no_reserve: if (no_reserve = (USHORT) isc_vax_integer(d, length)) put_numeric(att_no_reserve, no_reserve); break; case isc_info_set_page_buffers: if (page_buffers = isc_vax_integer(d, length)) put_numeric(att_page_buffers, page_buffers); break; case isc_info_error: // old server does not understand new isc_info break; // parameter and returns isc_info_error. skip it case isc_info_db_sql_dialect: SQL_dialect = (USHORT) isc_vax_integer(d, length); put_numeric(att_SQL_dialect, SQL_dialect); break; case isc_info_db_read_only: if (db_read_only = (USHORT) isc_vax_integer(d, length)) put_numeric(att_db_read_only, db_read_only); break; default: BURP_error_redirect(status_vector, 31); // msg 31 isc_database_info failed break; } } put_asciz(att_file_name, dbb_file); BURP_verbose(77, SafeArg() << dbb_file << page_size); // msg 77 database %s has a page size of %ld bytes. put(tdgbl, att_end); put(tdgbl, (UCHAR) rec_database); // if we have all capabilities, use the first request to get the // most performance out of the latest engine; if we don't // have one of the capabilities we must use the second set of // requests--this requires more code but it is well worth it // for the performance benefits, especially remotely--deej if ((tdgbl->BCK_capabilities & BCK_security) && (tdgbl->BCK_capabilities & BCK_db_description) && (tdgbl->BCK_capabilities & BCK_ods8)) { FOR (REQUEST_HANDLE req_handle1) D IN RDB$DATABASE if (!D.RDB$SECURITY_CLASS.NULL) PUT_TEXT (att_database_security_class, D.RDB$SECURITY_CLASS); put_source_blob (att_database_description2, att_database_description, D.RDB$DESCRIPTION); if (!D.RDB$CHARACTER_SET_NAME.NULL) PUT_TEXT (att_database_dfl_charset, D.RDB$CHARACTER_SET_NAME); END_FOR; ON_ERROR general_on_error(); END_ERROR; } else { if (tdgbl->BCK_capabilities & BCK_security) { FOR (REQUEST_HANDLE req_handle1) D IN RDB$DATABASE if (!D.RDB$SECURITY_CLASS.NULL) PUT_TEXT (att_database_security_class, D.RDB$SECURITY_CLASS); END_FOR; ON_ERROR general_on_error(); END_ERROR; } if (tdgbl->BCK_capabilities & BCK_db_description) { FOR (REQUEST_HANDLE req_handle2) D IN RDB$DATABASE put_source_blob (att_database_description2, att_database_description, D.RDB$DESCRIPTION); END_FOR; ON_ERROR general_on_error(); END_ERROR; } if (tdgbl->BCK_capabilities & BCK_ods8) { FOR (REQUEST_HANDLE req_handle3) D IN RDB$DATABASE if (!D.RDB$CHARACTER_SET_NAME.NULL) PUT_TEXT (att_database_dfl_charset, D.RDB$CHARACTER_SET_NAME); END_FOR; ON_ERROR general_on_error(); END_ERROR; } } MISC_release_request_silent(req_handle1); MISC_release_request_silent(req_handle2); MISC_release_request_silent(req_handle3); put(tdgbl, att_end); } void write_exceptions() { /************************************** * * w r i t e _ e x c e p t i o n s * ************************************** * * Functional description * write a record in the burp file for * each exception. * **************************************/ TEXT temp[GDS_NAME_LEN]; isc_req_handle req_handle1 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); FOR (REQUEST_HANDLE req_handle1) X IN RDB$EXCEPTIONS WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 put(tdgbl, rec_exception); const SSHORT l = PUT_TEXT (att_exception_name, X.RDB$EXCEPTION_NAME); MISC_terminate (X.RDB$EXCEPTION_NAME, temp, l, sizeof(temp)); BURP_verbose (198, temp); // msg 198 writing exception %s PUT_MESSAGE(att_exception_msg, att_exception_msg2, X.RDB$MESSAGE); put_source_blob (att_exception_description2, att_procedure_description, X.RDB$DESCRIPTION); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; MISC_release_request_silent(req_handle1); } void write_field_dimensions() { /************************************** * * w r i t e _ f i e l d _ d i m e n s i o n s * ************************************** * * Functional description * write a record in the burp file for * each array field dimension. * **************************************/ isc_req_handle req_handle1 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); FOR (REQUEST_HANDLE req_handle1) X IN RDB$FIELD_DIMENSIONS put(tdgbl, rec_field_dimensions); PUT_TEXT (att_field_name, X.RDB$FIELD_NAME); put_numeric (att_field_dimensions, X.RDB$DIMENSION); put_numeric (att_field_range_low, X.RDB$LOWER_BOUND); put_numeric (att_field_range_high, X.RDB$UPPER_BOUND); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; MISC_release_request_silent(req_handle1); } void write_filters() { /************************************** * * w r i t e _ f i l t e r s * ************************************** * * Functional description * write a record in the burp file for * each filter. * **************************************/ TEXT temp[GDS_NAME_LEN]; isc_req_handle req_handle1 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); FOR (REQUEST_HANDLE req_handle1) X IN RDB$FILTERS WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 put(tdgbl, rec_filter); const SSHORT l = PUT_TEXT (att_filter_name, X.RDB$FUNCTION_NAME); MISC_terminate (X.RDB$FUNCTION_NAME, temp, l, sizeof(temp)); BURP_verbose (145, temp); // msg 145 writing filter %s put_source_blob (att_filter_description2, att_filter_description, X.RDB$DESCRIPTION); PUT_TEXT (att_filter_module_name, X.RDB$MODULE_NAME); PUT_TEXT (att_filter_entrypoint, X.RDB$ENTRYPOINT); put_numeric (att_filter_input_sub_type, X.RDB$INPUT_SUB_TYPE); put_numeric (att_filter_output_sub_type, X.RDB$OUTPUT_SUB_TYPE); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; MISC_release_request_silent(req_handle1); } void write_functions() { /************************************** * * w r i t e _ f u n c t i o n s * ************************************** * * Functional description * write a record in the burp file for * each function. * **************************************/ GDS_NAME func; TEXT temp[GDS_NAME_LEN * 2]; isc_req_handle req_handle1 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); if (tdgbl->BCK_capabilities & BCK_ods12_0) { FOR (REQUEST_HANDLE req_handle1) X IN RDB$FUNCTIONS WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 put(tdgbl, rec_function); SSHORT prefixLen = 0; if (!X.RDB$PACKAGE_NAME.NULL) { prefixLen = PUT_TEXT(att_function_package_name, X.RDB$PACKAGE_NAME); MISC_terminate(X.RDB$PACKAGE_NAME, temp, prefixLen, sizeof(temp)); temp[prefixLen++] = '.'; } const SSHORT l = PUT_TEXT (att_function_name, X.RDB$FUNCTION_NAME); MISC_terminate (X.RDB$FUNCTION_NAME, temp + prefixLen, l, sizeof(temp) - prefixLen); BURP_verbose (147, temp); // msg 147 writing function %.*s put_source_blob (att_function_description2, att_function_description, X.RDB$DESCRIPTION); PUT_TEXT (att_function_module_name, X.RDB$MODULE_NAME); PUT_TEXT (att_function_entrypoint, X.RDB$ENTRYPOINT); put_numeric (att_function_return_arg, X.RDB$RETURN_ARGUMENT); put_numeric (att_function_type, X.RDB$FUNCTION_TYPE); PUT_TEXT (att_function_query_name, X.RDB$QUERY_NAME); if (!X.RDB$ENGINE_NAME.NULL) PUT_TEXT(att_function_engine_name, X.RDB$ENGINE_NAME); if (!X.RDB$PRIVATE_FLAG.NULL) put_numeric(att_function_private_flag, X.RDB$PRIVATE_FLAG); put(tdgbl, att_end); COPY (X.RDB$FUNCTION_NAME, func); write_function_args ((X.RDB$PACKAGE_NAME.NULL ? "" : X.RDB$PACKAGE_NAME), func); put(tdgbl, rec_function_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } else { FOR (REQUEST_HANDLE req_handle1) X IN RDB$FUNCTIONS WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 put(tdgbl, rec_function); const SSHORT l = PUT_TEXT (att_function_name, X.RDB$FUNCTION_NAME); MISC_terminate (X.RDB$FUNCTION_NAME, temp, l, sizeof(temp)); BURP_verbose (147, temp); // msg 147 writing function %.*s put_source_blob (att_function_description2, att_function_description, X.RDB$DESCRIPTION); PUT_TEXT (att_function_module_name, X.RDB$MODULE_NAME); PUT_TEXT (att_function_entrypoint, X.RDB$ENTRYPOINT); put_numeric (att_function_return_arg, X.RDB$RETURN_ARGUMENT); put_numeric (att_function_type, X.RDB$FUNCTION_TYPE); PUT_TEXT (att_function_query_name, X.RDB$QUERY_NAME); put(tdgbl, att_end); COPY (X.RDB$FUNCTION_NAME, func); write_function_args ("", func); put(tdgbl, rec_function_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } MISC_release_request_silent(req_handle1); } void write_function_args(const GDS_NAME package, GDS_NAME funcptr) { /************************************** * * w r i t e _ f u n c t i o n _ a r g s * ************************************** * * Functional description * write all arguments for a function. * **************************************/ TEXT temp[GDS_NAME_LEN * 2]; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); // if we have all capabilities, use the first request to get the // most performance out of the latest engine; if we don't // have one of the capabilities we must use the second set of // requests--this requires more code but it is well worth it // for the performance benefits, especially remotely--deej if (tdgbl->BCK_capabilities & BCK_ods12_0) { FOR (REQUEST_HANDLE tdgbl->handles_write_function_args_req_handle1) X IN RDB$FUNCTION_ARGUMENTS WITH X.RDB$FUNCTION_NAME EQ funcptr AND X.RDB$PACKAGE_NAME EQUIV NULLIF(package, '') put(tdgbl, rec_function_arg); SSHORT prefixLen = 0; if (!X.RDB$PACKAGE_NAME.NULL) { prefixLen = PUT_TEXT(att_functionarg_package_name, X.RDB$PACKAGE_NAME); MISC_terminate(X.RDB$PACKAGE_NAME, temp, prefixLen, sizeof(temp)); temp[prefixLen++] = '.'; } const SSHORT l = PUT_TEXT (att_functionarg_name, X.RDB$FUNCTION_NAME); MISC_terminate (X.RDB$FUNCTION_NAME, temp + prefixLen, l, sizeof(temp) - prefixLen); BURP_verbose (141, temp); // msg 141 writing argument for function %s put_numeric (att_functionarg_position, X.RDB$ARGUMENT_POSITION); put_numeric (att_functionarg_mechanism, X.RDB$MECHANISM); put_numeric (att_functionarg_field_type, X.RDB$FIELD_TYPE); put_numeric (att_functionarg_field_scale, X.RDB$FIELD_SCALE); put_numeric (att_functionarg_field_length, X.RDB$FIELD_LENGTH); put_numeric (att_functionarg_field_sub_type, X.RDB$FIELD_SUB_TYPE); if (!X.RDB$CHARACTER_SET_ID.NULL) put_numeric (att_functionarg_character_set, X.RDB$CHARACTER_SET_ID); if (!X.RDB$FIELD_PRECISION.NULL) put_numeric (att_functionarg_field_precision, X.RDB$FIELD_PRECISION); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } else if (tdgbl->BCK_capabilities & BCK_ods10) { FOR (REQUEST_HANDLE tdgbl->handles_write_function_args_req_handle1) X IN RDB$FUNCTION_ARGUMENTS WITH X.RDB$FUNCTION_NAME EQ funcptr put(tdgbl, rec_function_arg); const SSHORT l = PUT_TEXT (att_functionarg_name, X.RDB$FUNCTION_NAME); MISC_terminate (X.RDB$FUNCTION_NAME, temp, l, sizeof(temp)); BURP_verbose (141, temp); // msg 141 writing argument for function %s put_numeric (att_functionarg_position, X.RDB$ARGUMENT_POSITION); put_numeric (att_functionarg_mechanism, X.RDB$MECHANISM); put_numeric (att_functionarg_field_type, X.RDB$FIELD_TYPE); put_numeric (att_functionarg_field_scale, X.RDB$FIELD_SCALE); put_numeric (att_functionarg_field_length, X.RDB$FIELD_LENGTH); put_numeric (att_functionarg_field_sub_type, X.RDB$FIELD_SUB_TYPE); if (!X.RDB$CHARACTER_SET_ID.NULL) put_numeric (att_functionarg_character_set, X.RDB$CHARACTER_SET_ID); if (!X.RDB$FIELD_PRECISION.NULL) put_numeric (att_functionarg_field_precision, X.RDB$FIELD_PRECISION); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } else { FOR (REQUEST_HANDLE tdgbl->handles_write_function_args_req_handle1) X IN RDB$FUNCTION_ARGUMENTS WITH X.RDB$FUNCTION_NAME EQ funcptr put(tdgbl, rec_function_arg); const SSHORT l = PUT_TEXT (att_functionarg_name, X.RDB$FUNCTION_NAME); MISC_terminate (X.RDB$FUNCTION_NAME, temp, l, sizeof(temp)); BURP_verbose (141, temp); // msg 141 writing argument for function %s put_numeric (att_functionarg_position, X.RDB$ARGUMENT_POSITION); put_numeric (att_functionarg_mechanism, X.RDB$MECHANISM); put_numeric (att_functionarg_field_type, X.RDB$FIELD_TYPE); put_numeric (att_functionarg_field_scale, X.RDB$FIELD_SCALE); put_numeric (att_functionarg_field_length, X.RDB$FIELD_LENGTH); put_numeric (att_functionarg_field_sub_type, X.RDB$FIELD_SUB_TYPE); if (tdgbl->BCK_capabilities & BCK_ods8) { FOR (REQUEST_HANDLE tdgbl->handles_write_function_args_req_handle2) X2 IN RDB$FUNCTION_ARGUMENTS WITH X2.RDB$FUNCTION_NAME EQ funcptr AND X2.RDB$ARGUMENT_POSITION = X.RDB$ARGUMENT_POSITION; if (!X2.RDB$CHARACTER_SET_ID.NULL) put_numeric (att_functionarg_character_set, X2.RDB$CHARACTER_SET_ID); // Note that BCK_ods10 canNOT be set if we're in this // "else" branch. Hence there is no need to test that // bit and store the RDB$FIELD_PRECISION. END_FOR; ON_ERROR general_on_error(); END_ERROR; } put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } } void write_generators() { /************************************** * * w r i t e _ g e n e r a t o r s * ************************************** * * Functional description * Write any defined generators. * **************************************/ isc_req_handle req_handle1 = 0; TEXT temp[GDS_NAME_LEN]; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); if (tdgbl->BCK_capabilities & BCK_ods11) { FOR (REQUEST_HANDLE req_handle1) X IN RDB$GENERATORS WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 put(tdgbl, rec_generator); const SSHORT l = PUT_TEXT (att_gen_generator, X.RDB$GENERATOR_NAME); SINT64 value = 0; if (!tdgbl->gbl_sw_meta) { value = get_gen_id (X.RDB$GENERATOR_NAME, l); put_int64 (att_gen_value_int64, value); } if (!X.RDB$DESCRIPTION.NULL) { put_source_blob (att_gen_description, att_gen_description, X.RDB$DESCRIPTION); } put(tdgbl, att_end); MISC_terminate (X.RDB$GENERATOR_NAME, temp, l, sizeof(temp)); BURP_verbose (165, SafeArg() << temp << value); // msg 165 writing generator %s value %ld END_FOR; ON_ERROR general_on_error(); END_ERROR; } else { FOR (REQUEST_HANDLE req_handle1) X IN RDB$GENERATORS WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 put(tdgbl, rec_generator); const SSHORT l = PUT_TEXT (att_gen_generator, X.RDB$GENERATOR_NAME); SINT64 value = 0; if (!tdgbl->gbl_sw_meta) { value = get_gen_id (X.RDB$GENERATOR_NAME, l); put_int64 (att_gen_value_int64, value); } put(tdgbl, att_end); MISC_terminate (X.RDB$GENERATOR_NAME, temp, l, sizeof(temp)); BURP_verbose (165, SafeArg() << temp << value); // msg 165 writing generator %s value %ld END_FOR; ON_ERROR general_on_error(); END_ERROR; } MISC_release_request_silent(req_handle1); } void write_global_fields() { /************************************** * * w r i t e _ g l o b a l _ f i e l d s * ************************************** * * Functional description * write a record in the burp file for * each global field. * **************************************/ TEXT temp[GDS_NAME_LEN]; isc_req_handle req_handle1 = 0, req_handle2 = 0, req_handle3 = 0, req_handle4 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); // if we have all capabilities, use the first request to get the // most performance out of the latest engine; if we don't // have one of the capabilities we must use the second set of // requests--this requires more code but it is well worth it // for the performance benefits, especially remotely--deej if ((tdgbl->BCK_capabilities & BCK_attributes_v3) && (tdgbl->BCK_capabilities & BCK_ods8) && (tdgbl->BCK_capabilities & BCK_ods10)) { FOR (REQUEST_HANDLE req_handle1) X IN RDB$FIELDS WITH X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$SYSTEM_FLAG MISSING put(tdgbl, rec_global_field); const SSHORT l = PUT_TEXT (att_field_name, X.RDB$FIELD_NAME); MISC_terminate (X.RDB$FIELD_NAME, temp, l, sizeof(temp)); BURP_verbose (149, temp); // msg 149 writing global field %.*s if (X.RDB$QUERY_NAME [0] != ' ') PUT_TEXT (att_field_query_name, X.RDB$QUERY_NAME); if (X.RDB$EDIT_STRING [0] != ' ') PUT_TEXT (att_field_edit_string, X.RDB$EDIT_STRING); put_source_blob (att_field_query_header, att_field_query_header, X.RDB$QUERY_HEADER); put_numeric (att_field_type, X.RDB$FIELD_TYPE); put_numeric (att_field_length, X.RDB$FIELD_LENGTH); put_numeric (att_field_sub_type, X.RDB$FIELD_SUB_TYPE); put_numeric (att_field_scale, X.RDB$FIELD_SCALE); put_blr_blob (att_field_missing_value, X.RDB$MISSING_VALUE); put_blr_blob (att_field_default_value, X.RDB$DEFAULT_VALUE); put_blr_blob (att_field_validation_blr, X.RDB$VALIDATION_BLR); put_source_blob(att_field_validation_source2, att_field_validation_source, X.RDB$VALIDATION_SOURCE); put_blr_blob (att_field_computed_blr, X.RDB$COMPUTED_BLR); put_source_blob(att_field_computed_source2, att_field_computed_source, X.RDB$COMPUTED_SOURCE); if (X.RDB$SEGMENT_LENGTH) put_numeric (att_field_segment_length, X.RDB$SEGMENT_LENGTH); if (X.RDB$SYSTEM_FLAG) put_numeric (att_field_system_flag, X.RDB$SYSTEM_FLAG); put_source_blob (att_field_description2, att_field_description, X.RDB$DESCRIPTION); if (X.RDB$EXTERNAL_LENGTH) put_numeric (att_field_external_length, X.RDB$EXTERNAL_LENGTH); if (X.RDB$EXTERNAL_TYPE) put_numeric (att_field_external_type, X.RDB$EXTERNAL_TYPE); if (X.RDB$EXTERNAL_SCALE) put_numeric (att_field_external_scale, X.RDB$EXTERNAL_SCALE); if (X.RDB$DIMENSIONS) put_numeric (att_field_dimensions, X.RDB$DIMENSIONS); if (!X.RDB$NULL_FLAG.NULL) put_numeric (att_field_null_flag, X.RDB$NULL_FLAG); if (!X.RDB$CHARACTER_LENGTH.NULL) put_numeric (att_field_character_length, X.RDB$CHARACTER_LENGTH); if (!X.RDB$DEFAULT_SOURCE.NULL) put_source_blob(att_field_default_source, att_field_default_source, X.RDB$DEFAULT_SOURCE); if (!X.RDB$MISSING_SOURCE.NULL) put_source_blob(att_field_missing_source, att_field_missing_source, X.RDB$MISSING_SOURCE); if (!X.RDB$CHARACTER_SET_ID.NULL) put_numeric (att_field_character_set, X.RDB$CHARACTER_SET_ID); if (!X.RDB$COLLATION_ID.NULL) put_numeric (att_field_collation_id, X.RDB$COLLATION_ID); if (!X.RDB$FIELD_PRECISION.NULL) put_numeric (att_field_precision, X.RDB$FIELD_PRECISION); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } else { FOR (REQUEST_HANDLE req_handle1) X IN RDB$FIELDS WITH X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$SYSTEM_FLAG MISSING put(tdgbl, rec_global_field); const SSHORT l = PUT_TEXT (att_field_name, X.RDB$FIELD_NAME); MISC_terminate (X.RDB$FIELD_NAME, temp, l, sizeof(temp)); BURP_verbose (149, temp); // msg 149 writing global field %.*s if (X.RDB$QUERY_NAME [0] != ' ') PUT_TEXT (att_field_query_name, X.RDB$QUERY_NAME); if (X.RDB$EDIT_STRING [0] != ' ') PUT_TEXT (att_field_edit_string, X.RDB$EDIT_STRING); put_source_blob (att_field_query_header, att_field_query_header, X.RDB$QUERY_HEADER); put_numeric (att_field_type, X.RDB$FIELD_TYPE); put_numeric (att_field_length, X.RDB$FIELD_LENGTH); put_numeric (att_field_sub_type, X.RDB$FIELD_SUB_TYPE); put_numeric (att_field_scale, X.RDB$FIELD_SCALE); put_blr_blob (att_field_missing_value, X.RDB$MISSING_VALUE); put_blr_blob (att_field_default_value, X.RDB$DEFAULT_VALUE); put_blr_blob (att_field_validation_blr, X.RDB$VALIDATION_BLR); put_source_blob(att_field_validation_source2, att_field_validation_source, X.RDB$VALIDATION_SOURCE); put_blr_blob (att_field_computed_blr, X.RDB$COMPUTED_BLR); put_source_blob (att_field_computed_source2, att_field_computed_source, X.RDB$COMPUTED_SOURCE); if (X.RDB$SEGMENT_LENGTH) put_numeric (att_field_segment_length, X.RDB$SEGMENT_LENGTH); if (X.RDB$SYSTEM_FLAG) put_numeric (att_field_system_flag, X.RDB$SYSTEM_FLAG); put_source_blob (att_field_description2, att_field_description, X.RDB$DESCRIPTION); if (tdgbl->BCK_capabilities & BCK_attributes_v3) { FOR (REQUEST_HANDLE req_handle2) F IN RDB$FIELDS WITH F.RDB$FIELD_NAME = X.RDB$FIELD_NAME if (F.RDB$EXTERNAL_LENGTH) put_numeric (att_field_external_length, F.RDB$EXTERNAL_LENGTH); if (F.RDB$EXTERNAL_TYPE) put_numeric (att_field_external_type, F.RDB$EXTERNAL_TYPE); if (F.RDB$EXTERNAL_SCALE) put_numeric (att_field_external_scale, F.RDB$EXTERNAL_SCALE); if (F.RDB$DIMENSIONS) put_numeric (att_field_dimensions, F.RDB$DIMENSIONS); END_FOR; ON_ERROR general_on_error(); END_ERROR; } if (tdgbl->BCK_capabilities & BCK_ods8) { FOR (REQUEST_HANDLE req_handle3) F IN RDB$FIELDS WITH F.RDB$FIELD_NAME = X.RDB$FIELD_NAME if (!F.RDB$NULL_FLAG.NULL) put_numeric (att_field_null_flag, F.RDB$NULL_FLAG); if (!F.RDB$CHARACTER_LENGTH.NULL) put_numeric (att_field_character_length, F.RDB$CHARACTER_LENGTH); if (!F.RDB$DEFAULT_SOURCE.NULL) put_source_blob(att_field_default_source, att_field_default_source, F.RDB$DEFAULT_SOURCE); if (!F.RDB$MISSING_SOURCE.NULL) put_source_blob(att_field_missing_source, att_field_missing_source, F.RDB$MISSING_SOURCE); if (!F.RDB$CHARACTER_SET_ID.NULL) put_numeric (att_field_character_set, F.RDB$CHARACTER_SET_ID); if (!F.RDB$COLLATION_ID.NULL) put_numeric (att_field_collation_id, F.RDB$COLLATION_ID); if (tdgbl->BCK_capabilities & BCK_ods10) { FOR (REQUEST_HANDLE req_handle4) K IN RDB$FIELDS WITH K.RDB$FIELD_NAME = X.RDB$FIELD_NAME if (!K.RDB$FIELD_PRECISION.NULL) put_numeric (att_field_precision, K.RDB$FIELD_PRECISION); END_FOR; ON_ERROR general_on_error(); END_ERROR; } END_FOR; ON_ERROR general_on_error(); END_ERROR; } put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } MISC_release_request_silent(req_handle1); MISC_release_request_silent(req_handle2); MISC_release_request_silent(req_handle3); MISC_release_request_silent(req_handle4); } void write_packages() { /************************************** * * w r i t e _ p a c k a g e s * ************************************** * * Functional description * write a record in the burp file for * each package. * **************************************/ TEXT temp[GDS_NAME_LEN]; isc_req_handle req_handle1 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); FOR (REQUEST_HANDLE req_handle1) X IN RDB$PACKAGES WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 { put(tdgbl, rec_package); const SSHORT l = PUT_TEXT(att_package_name, X.RDB$PACKAGE_NAME); MISC_terminate(X.RDB$PACKAGE_NAME, temp, l, sizeof(temp)); BURP_verbose(335, temp); // msg 335 writing package @1 if (!X.RDB$PACKAGE_HEADER_SOURCE.NULL) { put_source_blob(att_package_header_source, att_package_header_source, X.RDB$PACKAGE_HEADER_SOURCE); } if (!X.RDB$PACKAGE_BODY_SOURCE.NULL) { put_source_blob(att_package_body_source, att_package_body_source, X.RDB$PACKAGE_BODY_SOURCE); } if (!X.RDB$SECURITY_CLASS.NULL) PUT_TEXT(att_package_security_class, X.RDB$SECURITY_CLASS); if (!X.RDB$OWNER_NAME.NULL) PUT_TEXT(att_package_owner_name, X.RDB$OWNER_NAME); if (!X.RDB$DESCRIPTION.NULL) put_source_blob(att_package_description, att_package_description, X.RDB$DESCRIPTION); put(tdgbl, att_end); } END_FOR ON_ERROR general_on_error(); END_ERROR MISC_release_request_silent(req_handle1); } void write_procedures() { /************************************** * * w r i t e _ p r o c e d u r e s * ************************************** * * Functional description * write a record in the burp file for * each stored procedure. * **************************************/ GDS_NAME proc; TEXT temp[GDS_NAME_LEN]; isc_req_handle req_handle1 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); if (tdgbl->BCK_capabilities & BCK_ods11_1) { FOR (REQUEST_HANDLE req_handle1) X IN RDB$PROCEDURES WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 put(tdgbl, rec_procedure); SSHORT prefixLen = 0; if (!X.RDB$PACKAGE_NAME.NULL) { prefixLen = PUT_TEXT(att_procedure_package_name, X.RDB$PACKAGE_NAME); MISC_terminate (X.RDB$PACKAGE_NAME, temp, prefixLen, sizeof(temp)); temp[prefixLen++] = '.'; } const SSHORT len = PUT_TEXT (att_procedure_name, X.RDB$PROCEDURE_NAME); MISC_terminate (X.RDB$PROCEDURE_NAME, temp + prefixLen, len, sizeof(temp) - prefixLen); BURP_verbose (193, temp); // msg 193 writing stored procedure %.*s put_numeric (att_procedure_inputs, X.RDB$PROCEDURE_INPUTS); put_numeric (att_procedure_outputs, X.RDB$PROCEDURE_OUTPUTS); put_source_blob(att_procedure_description2, att_procedure_description, X.RDB$DESCRIPTION); put_source_blob (att_procedure_source2, att_procedure_source, X.RDB$PROCEDURE_SOURCE); if (!X.RDB$PROCEDURE_BLR.NULL) put_blr_blob (att_procedure_blr, X.RDB$PROCEDURE_BLR); if (!X.RDB$SECURITY_CLASS.NULL) PUT_TEXT (att_procedure_security_class, X.RDB$SECURITY_CLASS); if (!X.RDB$OWNER_NAME.NULL) PUT_TEXT (att_procedure_owner_name, X.RDB$OWNER_NAME); if (!X.RDB$PROCEDURE_TYPE.NULL) put_numeric (att_procedure_type, X.RDB$PROCEDURE_TYPE); if (!X.RDB$VALID_BLR.NULL) put_numeric (att_procedure_valid_blr, X.RDB$VALID_BLR); if (!X.RDB$DEBUG_INFO.NULL) put_blr_blob (att_procedure_debug_info, X.RDB$DEBUG_INFO); if (!X.RDB$ENGINE_NAME.NULL) PUT_TEXT(att_procedure_engine_name, X.RDB$ENGINE_NAME); if (!X.RDB$ENTRYPOINT.NULL) PUT_TEXT(att_procedure_entrypoint, X.RDB$ENTRYPOINT); if (!X.RDB$PRIVATE_FLAG.NULL) put_numeric(att_procedure_private_flag, X.RDB$PRIVATE_FLAG); put(tdgbl, att_end); COPY(X.RDB$PROCEDURE_NAME, proc); write_procedure_prms ((X.RDB$PACKAGE_NAME.NULL ? "" : X.RDB$PACKAGE_NAME), proc); put(tdgbl, rec_procedure_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } else { FOR (REQUEST_HANDLE req_handle1) X IN RDB$PROCEDURES WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 put(tdgbl, rec_procedure); const SSHORT l = PUT_TEXT (att_procedure_name, X.RDB$PROCEDURE_NAME); MISC_terminate (X.RDB$PROCEDURE_NAME, temp, l, sizeof(temp)); BURP_verbose (193, temp); // msg 193 writing stored procedure %.*s put_numeric (att_procedure_inputs, X.RDB$PROCEDURE_INPUTS); put_numeric (att_procedure_outputs, X.RDB$PROCEDURE_OUTPUTS); put_source_blob (att_procedure_description2, att_procedure_description, X.RDB$DESCRIPTION); put_source_blob (att_procedure_source2, att_procedure_source, X.RDB$PROCEDURE_SOURCE); put_blr_blob (att_procedure_blr, X.RDB$PROCEDURE_BLR); if (!X.RDB$SECURITY_CLASS.NULL) PUT_TEXT (att_procedure_security_class, X.RDB$SECURITY_CLASS); if (!X.RDB$SECURITY_CLASS.NULL) PUT_TEXT (att_procedure_owner_name, X.RDB$OWNER_NAME); put(tdgbl, att_end); COPY(X.RDB$PROCEDURE_NAME, proc); write_procedure_prms ("", proc); put(tdgbl, rec_procedure_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } MISC_release_request_silent(req_handle1); } void write_procedure_prms(const GDS_NAME package, const GDS_NAME procptr) { /************************************** * * w r i t e _ p r o c e d u r e _ p r m s * ************************************** * * Functional description * write all parameters of a stored procedure. * **************************************/ TEXT temp[GDS_NAME_LEN]; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); if (tdgbl->BCK_capabilities & BCK_ods11_1) { FOR (REQUEST_HANDLE tdgbl->handles_write_procedure_prms_req_handle1) X IN RDB$PROCEDURE_PARAMETERS WITH X.RDB$PROCEDURE_NAME EQ procptr AND X.RDB$PACKAGE_NAME EQUIV NULLIF(package, '') { put(tdgbl, rec_procedure_prm); const SSHORT l = PUT_TEXT (att_procedureprm_name, X.RDB$PARAMETER_NAME); MISC_terminate (X.RDB$PARAMETER_NAME, temp, l, sizeof(temp)); BURP_verbose (194, temp); // msg 194 writing parameter %s for stored procedure put_numeric (att_procedureprm_number, X.RDB$PARAMETER_NUMBER); put_numeric (att_procedureprm_type, X.RDB$PARAMETER_type); PUT_TEXT (att_procedureprm_field_source, X.RDB$FIELD_SOURCE); put_source_blob(att_procedureprm_description2, att_procedureprm_description, X.RDB$DESCRIPTION); put_blr_blob (att_procedureprm_default_value, X.RDB$DEFAULT_VALUE); put_source_blob(att_procedureprm_default_source, att_procedureprm_default_source, X.RDB$DEFAULT_SOURCE); if (!X.RDB$COLLATION_ID.NULL) put_numeric (att_procedureprm_collation_id, X.RDB$COLLATION_ID); if (!X.RDB$NULL_FLAG.NULL) put_numeric (att_procedureprm_null_flag, X.RDB$NULL_FLAG); if (!X.RDB$PARAMETER_MECHANISM.NULL) put_numeric (att_procedureprm_mechanism, X.RDB$PARAMETER_MECHANISM); // BCK_ods11_2 if (!X.RDB$FIELD_NAME.NULL) PUT_TEXT(att_procedureprm_field_name, X.RDB$FIELD_NAME); if (!X.RDB$RELATION_NAME.NULL) PUT_TEXT(att_procedureprm_relation_name, X.RDB$RELATION_NAME); put(tdgbl, att_end); } END_FOR; ON_ERROR general_on_error(); END_ERROR; } else { FOR (REQUEST_HANDLE tdgbl->handles_write_procedure_prms_req_handle1) X IN RDB$PROCEDURE_PARAMETERS WITH X.RDB$PROCEDURE_NAME EQ procptr put(tdgbl, rec_procedure_prm); const SSHORT l = PUT_TEXT (att_procedureprm_name, X.RDB$PARAMETER_NAME); MISC_terminate (X.RDB$PARAMETER_NAME, temp, l, sizeof(temp)); BURP_verbose (194, temp); // msg 194 writing parameter %s for stored procedure put_numeric (att_procedureprm_number, X.RDB$PARAMETER_NUMBER); put_numeric (att_procedureprm_type, X.RDB$PARAMETER_type); PUT_TEXT (att_procedureprm_field_source, X.RDB$FIELD_SOURCE); put_source_blob(att_procedureprm_description2, att_procedureprm_description, X.RDB$DESCRIPTION); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } } void write_ref_constraints() { /************************************** * * w r i t e _ r e f _ c o n s t r a i n t s * ************************************** * * Functional description * write a record in the burp file for * each referential constraint. * **************************************/ isc_req_handle req_handle1 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); FOR (REQUEST_HANDLE req_handle1) X IN RDB$REF_CONSTRAINTS put(tdgbl, rec_ref_constraint); PUT_TEXT (att_ref_constraint_name, X.RDB$CONSTRAINT_NAME); PUT_TEXT (att_ref_unique_const_name, X.RDB$CONST_NAME_UQ); PUT_TEXT (att_ref_match_option, X.RDB$MATCH_OPTION); PUT_TEXT (att_ref_update_rule, X.RDB$UPDATE_RULE); PUT_TEXT (att_ref_delete_rule, X.RDB$DELETE_RULE); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; MISC_release_request_silent(req_handle1); } void write_rel_constraints() { /************************************** * * w r i t e _ r e l _ c o n s t r a i n t s * ************************************** * * Functional description * write a record in the burp file for * each relation constraint. * **************************************/ TEXT temp[GDS_NAME_LEN]; isc_req_handle req_handle1 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); FOR (REQUEST_HANDLE req_handle1) X IN RDB$RELATION_CONSTRAINTS put(tdgbl, rec_rel_constraint); const SSHORT l = PUT_TEXT (att_rel_constraint_name, X.RDB$CONSTRAINT_NAME); MISC_terminate (X.RDB$CONSTRAINT_NAME, temp, l, sizeof(temp)); BURP_verbose (207, temp); // msg 207 writing constraint %s PUT_TEXT (att_rel_constraint_type, X.RDB$CONSTRAINT_TYPE); PUT_TEXT (att_rel_constraint_rel_name, X.RDB$RELATION_NAME); PUT_TEXT (att_rel_constraint_defer, X.RDB$DEFERRABLE); PUT_TEXT (att_rel_constraint_init, X.RDB$INITIALLY_DEFERRED); if (!X.RDB$INDEX_NAME.NULL) PUT_TEXT (att_rel_constraint_index, X.RDB$INDEX_NAME); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; MISC_release_request_silent(req_handle1); } void write_relations() { /************************************** * * w r i t e _ r e l a t i o n s * ************************************** * * Functional description * write a record in the burp file for * each relation. * **************************************/ TEXT temp[GDS_NAME_LEN]; isc_req_handle req_handle1 = 0, req_handle2 = 0, req_handle3 = 0, req_handle4 = 0, req_handle5 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); // if we have all capabilities, use the first request to get the // most performance out of the latest engine; if we don't // have one of the capabilities we must use the second set of // requests--this requires more code but it is well worth it // for the performance benefits, especially remotely--deej if ((tdgbl->BCK_capabilities & BCK_ods8) && (tdgbl->BCK_capabilities & BCK_security) && (tdgbl->BCK_capabilities & BCK_attributes_v3) && (tdgbl->BCK_capabilities & BCK_ods11_1)) { FOR (REQUEST_HANDLE req_handle1) X IN RDB$RELATIONS WITH X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$SYSTEM_FLAG MISSING SSHORT flags = 0; put(tdgbl, rec_relation); const SSHORT l = PUT_TEXT (att_relation_name, X.RDB$RELATION_NAME); MISC_terminate (X.RDB$RELATION_NAME, temp, l, sizeof(temp)); BURP_verbose (153, temp); // msg 153 writing relation %.*s // RDB$VIEW_BLR must be the first blob field in the backup file. // RESTORE.EPP makes this assumption in get_relation(). if (put_blr_blob (att_relation_view_blr, X.RDB$VIEW_BLR)) flags |= REL_view; if (X.RDB$SYSTEM_FLAG) put_numeric (att_relation_system_flag, X.RDB$SYSTEM_FLAG); if (!X.RDB$FLAGS.NULL) put_numeric (att_relation_flags, X.RDB$FLAGS); if (!X.RDB$SECURITY_CLASS.NULL) PUT_TEXT (att_relation_security_class, X.RDB$SECURITY_CLASS); put_source_blob (att_relation_description2, att_relation_description, X.RDB$DESCRIPTION); put_source_blob (att_relation_view_source2, att_relation_view_source, X.RDB$VIEW_SOURCE); put_source_blob(att_relation_ext_description2, att_relation_ext_description, X.RDB$EXTERNAL_DESCRIPTION); PUT_TEXT (att_relation_owner_name, X.RDB$OWNER_NAME); if (!X.RDB$EXTERNAL_FILE.NULL) { if (!tdgbl->gbl_sw_convert_ext_tables) { PUT_TEXT(att_relation_ext_file_name, X.RDB$EXTERNAL_FILE); flags |= REL_external; } } if (!X.RDB$RELATION_TYPE.NULL) put_numeric (att_relation_type, X.RDB$RELATION_TYPE); put(tdgbl, att_end); burp_rel* relation = (burp_rel*) BURP_alloc_zero (sizeof(burp_rel)); relation->rel_next = tdgbl->relations; tdgbl->relations = relation; relation->rel_id = X.RDB$RELATION_ID; relation->rel_name_length = COPY(X.RDB$RELATION_NAME, relation->rel_name); relation->rel_flags |= flags; put_relation (relation); END_FOR; ON_ERROR general_on_error(); END_ERROR; } else { FOR (REQUEST_HANDLE req_handle1) X IN RDB$RELATIONS WITH X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$SYSTEM_FLAG MISSING SSHORT flags = 0; put(tdgbl, rec_relation); const SSHORT l = PUT_TEXT(att_relation_name, X.RDB$RELATION_NAME); MISC_terminate (X.RDB$RELATION_NAME, temp, l, sizeof(temp)); BURP_verbose (153, temp); // msg 153 writing relation %.*s // RDB$VIEW_BLR must be the first blob field in the backup file. // RESTORE.EPP makes this assumption in get_relation(). if (put_blr_blob (att_relation_view_blr, X.RDB$VIEW_BLR)) flags |= REL_view; if (X.RDB$SYSTEM_FLAG) put_numeric (att_relation_system_flag, X.RDB$SYSTEM_FLAG); if (tdgbl->BCK_capabilities & BCK_ods8) { FOR (REQUEST_HANDLE req_handle2) R IN RDB$RELATIONS WITH R.RDB$RELATION_NAME = X.RDB$RELATION_NAME if (!R.RDB$FLAGS.NULL) put_numeric (att_relation_flags, R.RDB$FLAGS); END_FOR; ON_ERROR general_on_error(); END_ERROR; } if (tdgbl->BCK_capabilities & BCK_security) { FOR (REQUEST_HANDLE req_handle3) R IN RDB$RELATIONS WITH R.RDB$RELATION_NAME = X.RDB$RELATION_NAME if (!R.RDB$SECURITY_CLASS.NULL) PUT_TEXT(att_relation_security_class, R.RDB$SECURITY_CLASS); END_FOR; ON_ERROR general_on_error(); END_ERROR; } put_source_blob (att_relation_description2, att_relation_description, X.RDB$DESCRIPTION); put_source_blob (att_relation_view_source2, att_relation_view_source, X.RDB$VIEW_SOURCE); if (tdgbl->BCK_capabilities & BCK_attributes_v3) { FOR (REQUEST_HANDLE req_handle4) R IN RDB$RELATIONS WITH R.RDB$RELATION_NAME = X.RDB$RELATION_NAME put_source_blob(att_relation_ext_description2, att_relation_ext_description, R.RDB$EXTERNAL_DESCRIPTION); PUT_TEXT(att_relation_owner_name, R.RDB$OWNER_NAME); if (!R.RDB$EXTERNAL_FILE.NULL) { if (!tdgbl->gbl_sw_convert_ext_tables) { PUT_TEXT(att_relation_ext_file_name, R.RDB$EXTERNAL_FILE); flags |= REL_external; } } END_FOR; ON_ERROR general_on_error(); END_ERROR; } if (tdgbl->BCK_capabilities & BCK_ods11_1) { FOR (REQUEST_HANDLE req_handle5) R IN RDB$RELATIONS WITH R.RDB$RELATION_NAME = X.RDB$RELATION_NAME if (!R.RDB$RELATION_TYPE.NULL) put_numeric (att_relation_type, R.RDB$RELATION_TYPE); END_FOR; ON_ERROR general_on_error(); END_ERROR; } put(tdgbl, att_end); burp_rel* relation = (burp_rel*) BURP_alloc_zero (sizeof(burp_rel)); relation->rel_next = tdgbl->relations; tdgbl->relations = relation; relation->rel_id = X.RDB$RELATION_ID; relation->rel_name_length = COPY(X.RDB$RELATION_NAME, relation->rel_name); relation->rel_flags |= flags; put_relation (relation); END_FOR; ON_ERROR general_on_error(); END_ERROR; } MISC_release_request_silent(req_handle1); MISC_release_request_silent(req_handle2); MISC_release_request_silent(req_handle3); MISC_release_request_silent(req_handle4); MISC_release_request_silent(req_handle5); } void write_shadow_files() { /************************************** * * w r i t e _ s h a d o w _ f i l e s * ************************************** * * Functional description * Write out files to use as shadows. * **************************************/ TEXT temp[GDS_NAME_LEN]; isc_req_handle req_handle1 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); FOR (REQUEST_HANDLE req_handle1) X IN RDB$FILES WITH X.RDB$SHADOW_NUMBER NOT MISSING AND X.RDB$SHADOW_NUMBER NE 0 put(tdgbl, rec_files); const SSHORT l = PUT_TEXT (att_file_filename, X.RDB$FILE_NAME); MISC_terminate (X.RDB$FILE_NAME, temp, l, sizeof(temp)); BURP_verbose (163, temp); // msg 163 writing shadow file %s put_numeric (att_file_sequence, X.RDB$FILE_SEQUENCE); put_numeric (att_file_start, X.RDB$FILE_START); put_numeric (att_file_length, X.RDB$FILE_LENGTH); put_numeric (att_file_flags, X.RDB$FILE_FLAGS); put_numeric (att_shadow_number, X.RDB$SHADOW_NUMBER); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; MISC_release_request_silent(req_handle1); } void write_sql_roles() { /************************************** * * w r i t e _ s q l _ r o l e s * ************************************** * * Functional description * write a record in the burp file for * each SQL roles. * **************************************/ isc_req_handle req_handle1 = 0; TEXT temp[GDS_NAME_LEN]; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); if (tdgbl->BCK_capabilities & BCK_ods11) { FOR (REQUEST_HANDLE req_handle1) X IN RDB$ROLES WITH X.RDB$SYSTEM_FLAG EQ 0 OR X.RDB$SYSTEM_FLAG MISSING put(tdgbl, rec_sql_roles); const SSHORT l = PUT_TEXT(att_role_name, X.RDB$ROLE_NAME); PUT_TEXT (att_role_owner_name, X.RDB$OWNER_NAME); if (!X.RDB$DESCRIPTION.NULL) { put_source_blob (att_role_description, att_role_description, X.RDB$DESCRIPTION); } put(tdgbl, att_end); MISC_terminate (X.RDB$ROLE_NAME, temp, l, sizeof(temp)); BURP_verbose (249, temp); // msg 249 writing SQL role: %s END_FOR; ON_ERROR general_on_error(); END_ERROR; } else { FOR (REQUEST_HANDLE req_handle1) X IN RDB$ROLES put(tdgbl, rec_sql_roles); const SSHORT l = PUT_TEXT(att_role_name, X.RDB$ROLE_NAME); PUT_TEXT (att_role_owner_name, X.RDB$OWNER_NAME); put(tdgbl, att_end); MISC_terminate (X.RDB$ROLE_NAME, temp, l, sizeof(temp)); BURP_verbose (249, temp); // msg 249 writing SQL role: %s END_FOR; ON_ERROR general_on_error(); END_ERROR; } MISC_release_request_silent(req_handle1); } void write_mapping() { /************************************** * * w r i t e _ m a p p i n g * ************************************** * * Functional description * write a record in the burp file for * each names mapping. * **************************************/ isc_req_handle req_handle = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); if (tdgbl->BCK_capabilities & BCK_ods11_2) { FOR (REQUEST_HANDLE req_handle) X IN RDB$ROLES WITH X.RDB$ROLE_NAME EQ ADMIN_ROLE if (X.RDB$SYSTEM_FLAG == (ROLE_FLAG_MAY_TRUST | ROLE_FLAG_DBO)) { put(tdgbl, rec_mapping); //put_text(att_map_os, DOMAIN-ADMINS, strlen(DOMAIN-ADMINS) + 1); //put_text(att_map_role, ADMIN-ROLE, strlen(ADMIN-ROLE) + 1); put_text(att_auto_map_role, ADMIN_ROLE, strlen(ADMIN_ROLE) + 1); put(tdgbl, att_end); BURP_verbose (297, ADMIN_ROLE); // msg 297 writing mapping for @1 } END_FOR; ON_ERROR general_on_error(); END_ERROR; } MISC_release_request_silent(req_handle); } void write_triggers() { /************************************** * * w r i t e _ t r i g g e r s * ************************************** * * Functional description * write the triggers in rdb$triggers * **************************************/ TEXT temp[GDS_NAME_LEN]; isc_req_handle req_handle1 = 0, req_handle2 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); // if we have all capabilities, use the first request to get the // most performance out of the latest engine; if we don't // have one of the capabilities we must use the second set of // requests--this requires more code but it is well worth it // for the performance benefits, especially remotely--deej if (tdgbl->BCK_capabilities & BCK_ods11_1) { FOR (REQUEST_HANDLE req_handle1) X IN RDB$TRIGGERS WITH X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$SYSTEM_FLAG MISSING put(tdgbl, rec_trigger); const SSHORT l = PUT_TEXT (att_trig_name, X.RDB$TRIGGER_NAME); MISC_terminate (X.RDB$TRIGGER_NAME, temp, l, sizeof(temp)); BURP_verbose (156, temp); // msg 156 writing trigger %s if (!X.RDB$RELATION_NAME.NULL) PUT_TEXT (att_trig_relation_name, X.RDB$RELATION_NAME); put_numeric (att_trig_sequence, X.RDB$TRIGGER_SEQUENCE); if (X.RDB$TRIGGER_TYPE >= SLONG_MIN && X.RDB$TRIGGER_TYPE <= SLONG_MAX) put_numeric (att_trig_type, (SLONG) X.RDB$TRIGGER_TYPE); else put_int64 (att_trig_type2, X.RDB$TRIGGER_TYPE); put_blr_blob (att_trig_blr, X.RDB$TRIGGER_BLR); put_source_blob (att_trig_source2, att_trig_source, X.RDB$TRIGGER_SOURCE); put_source_blob (att_trig_description2, att_trig_description, X.RDB$DESCRIPTION); put_numeric (att_trig_system_flag, X.RDB$SYSTEM_FLAG); put_numeric (att_trig_inactive, X.RDB$TRIGGER_INACTIVE); if (!X.RDB$FLAGS.NULL) put_numeric (att_trig_flags, X.RDB$FLAGS); if (!X.RDB$VALID_BLR.NULL) put_numeric (att_trig_valid_blr, X.RDB$VALID_BLR); if (!X.RDB$DEBUG_INFO.NULL) put_blr_blob (att_trig_debug_info, X.RDB$DEBUG_INFO); if (!X.RDB$ENGINE_NAME.NULL) PUT_TEXT(att_trig_engine_name, X.RDB$ENGINE_NAME); if (!X.RDB$ENTRYPOINT.NULL) PUT_TEXT(att_trig_entrypoint, X.RDB$ENTRYPOINT); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } else if (tdgbl->BCK_capabilities & BCK_ods8) { FOR (REQUEST_HANDLE req_handle1) X IN RDB$TRIGGERS WITH X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$SYSTEM_FLAG MISSING put(tdgbl, rec_trigger); const SSHORT l = PUT_TEXT (att_trig_name, X.RDB$TRIGGER_NAME); MISC_terminate (X.RDB$TRIGGER_NAME, temp, l, sizeof(temp)); BURP_verbose (156, temp); // msg 156 writing trigger %s if (!X.RDB$RELATION_NAME.NULL) PUT_TEXT (att_trig_relation_name, X.RDB$RELATION_NAME); put_numeric (att_trig_sequence, X.RDB$TRIGGER_SEQUENCE); put_numeric (att_trig_type, X.RDB$TRIGGER_TYPE); put_blr_blob (att_trig_blr, X.RDB$TRIGGER_BLR); put_source_blob (att_trig_source2, att_trig_source, X.RDB$TRIGGER_SOURCE); put_source_blob (att_trig_description2, att_trig_description, X.RDB$DESCRIPTION); put_numeric (att_trig_system_flag, X.RDB$SYSTEM_FLAG); put_numeric (att_trig_inactive, X.RDB$TRIGGER_INACTIVE); if (!X.RDB$FLAGS.NULL) put_numeric (att_trig_flags, X.RDB$FLAGS); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } else { FOR (REQUEST_HANDLE req_handle1) X IN RDB$TRIGGERS WITH X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$SYSTEM_FLAG MISSING put(tdgbl, rec_trigger); const SSHORT l = PUT_TEXT (att_trig_name, X.RDB$TRIGGER_NAME); MISC_terminate (X.RDB$TRIGGER_NAME, temp, l, sizeof(temp)); BURP_verbose (156, temp); // msg 156 writing trigger %s if (!X.RDB$RELATION_NAME.NULL) PUT_TEXT (att_trig_relation_name, X.RDB$RELATION_NAME); put_numeric (att_trig_sequence, X.RDB$TRIGGER_SEQUENCE); put_numeric (att_trig_type, X.RDB$TRIGGER_TYPE); put_blr_blob (att_trig_blr, X.RDB$TRIGGER_BLR); put_source_blob (att_trig_source2, att_trig_source, X.RDB$TRIGGER_SOURCE); put_source_blob (att_trig_description2, att_trig_description, X.RDB$DESCRIPTION); put_numeric (att_trig_system_flag, X.RDB$SYSTEM_FLAG); put_numeric (att_trig_inactive, X.RDB$TRIGGER_INACTIVE); if (tdgbl->BCK_capabilities & BCK_ods8) { FOR (REQUEST_HANDLE req_handle2) Y IN RDB$TRIGGERS WITH X.RDB$TRIGGER_NAME = Y.RDB$TRIGGER_NAME if (!Y.RDB$FLAGS.NULL) put_numeric (att_trig_flags, Y.RDB$FLAGS); END_FOR; ON_ERROR general_on_error(); END_ERROR; } put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } MISC_release_request_silent(req_handle1); MISC_release_request_silent(req_handle2); } void write_trigger_messages() { /************************************** * * w r i t e _ t r i g g e r _ m e s s a g e s * ************************************** * * Functional description * write a record in the burp file for * each trigger message. * **************************************/ TEXT temp[GDS_NAME_LEN]; isc_req_handle req_handle1 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); FOR (REQUEST_HANDLE req_handle1) T IN RDB$TRIGGERS CROSS X IN RDB$TRIGGER_MESSAGES OVER RDB$TRIGGER_NAME WITH T.RDB$SYSTEM_FLAG NE 1 OR T.RDB$SYSTEM_FLAG MISSING; put(tdgbl, rec_trigger_message); const SSHORT l = PUT_TEXT (att_trigmsg_name, X.RDB$TRIGGER_NAME); MISC_terminate (X.RDB$TRIGGER_NAME, temp, l, sizeof(temp)); BURP_verbose (157, temp); // msg 157 writing trigger message for *s put_numeric (att_trigmsg_number, X.RDB$MESSAGE_NUMBER); PUT_MESSAGE (att_trigmsg_text, att_end, X.RDB$MESSAGE); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; MISC_release_request_silent(req_handle1); } void write_types() { /************************************** * * w r i t e _ t y p e s * ************************************** * * Functional description * write a record in the burp file for * each type. * **************************************/ isc_req_handle req_handle1 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); FOR (REQUEST_HANDLE req_handle1) X IN RDB$TYPES WITH X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$SYSTEM_FLAG MISSING put(tdgbl, rec_system_type); PUT_TEXT (att_type_name, X.RDB$TYPE_NAME); PUT_TEXT (att_type_field_name, X.RDB$FIELD_NAME); BURP_verbose (160, SafeArg() << X.RDB$TYPE_NAME << X.RDB$FIELD_NAME); // msg 160 writing type %s for field %s put_numeric (att_type_type, X.RDB$TYPE); put_source_blob (att_type_description2, att_type_description, X.RDB$DESCRIPTION); if (X.RDB$SYSTEM_FLAG) put_numeric (att_type_system_flag, X.RDB$SYSTEM_FLAG); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; MISC_release_request_silent(req_handle1); } void write_user_privileges() { /************************************** * * w r i t e _ u s e r _ p r i v i l e g e s * ************************************** * * Functional description * write a record in the burp file for * each user privilege. * **************************************/ TEXT temp[GDS_NAME_LEN]; isc_req_handle req_handle1 = 0; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); if (tdgbl->BCK_capabilities & BCK_ods8) { FOR (REQUEST_HANDLE req_handle1) X IN RDB$USER_PRIVILEGES put(tdgbl, rec_user_privilege); const SSHORT l = PUT_TEXT (att_priv_user, X.RDB$USER); MISC_terminate (X.RDB$USER, temp, l, sizeof(temp)); BURP_verbose (152, temp); // msg 152 writing privilege for user %s PUT_TEXT (att_priv_grantor, X.RDB$GRANTOR); PUT_TEXT (att_priv_privilege, X.RDB$PRIVILEGE); put_numeric (att_priv_grant_option, X.RDB$GRANT_OPTION); PUT_TEXT (att_priv_object_name, X.RDB$RELATION_NAME); if (!X.RDB$FIELD_NAME.NULL) PUT_TEXT (att_priv_field_name, X.RDB$FIELD_NAME); put_numeric (att_priv_user_type, X.RDB$USER_TYPE); put_numeric (att_priv_obj_type, X.RDB$OBJECT_TYPE); put(tdgbl, att_end); END_FOR ON_ERROR general_on_error(); END_ERROR; } else { FOR (REQUEST_HANDLE req_handle1) X IN RDB$USER_PRIVILEGES put(tdgbl, rec_user_privilege); const SSHORT l = PUT_TEXT (att_priv_user, X.RDB$USER); MISC_terminate (X.RDB$USER, temp, l, sizeof(temp)); BURP_verbose (152, temp); // msg 152 writing privilege for user %s PUT_TEXT (att_priv_grantor, X.RDB$GRANTOR); PUT_TEXT (att_priv_privilege, X.RDB$PRIVILEGE); put_numeric (att_priv_grant_option, X.RDB$GRANT_OPTION); PUT_TEXT (att_priv_object_name, X.RDB$RELATION_NAME); if (!X.RDB$FIELD_NAME.NULL) PUT_TEXT (att_priv_field_name, X.RDB$FIELD_NAME); put(tdgbl, att_end); END_FOR; ON_ERROR general_on_error(); END_ERROR; } MISC_release_request_silent(req_handle1); } } // namespace