mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 14:03:02 +01:00
4297 lines
119 KiB
Plaintext
4297 lines
119 KiB
Plaintext
/*
|
|
* 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 <stdio.h>
|
|
#include <memory.h>
|
|
#include <string.h>
|
|
#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&, ULONG);
|
|
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(GDS_NAME);
|
|
void write_generators();
|
|
void write_sql_roles();
|
|
void write_mapping();
|
|
void write_global_fields();
|
|
void write_procedures();
|
|
void write_procedure_prms(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.
|
|
};
|
|
// 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},
|
|
{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(dbb_file, 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_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 l = (ULONG) MISC_symbol_length(from, size_len);
|
|
|
|
memcpy(to, from, l);
|
|
to[l] = '\0';
|
|
|
|
return (int) l;
|
|
}
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (debug_on)
|
|
isc_print_blr((const char*)blr_buffer, NULL, NULL, 0);
|
|
#endif
|
|
|
|
ISC_STATUS_ARRAY status_vector;
|
|
const SSHORT blr_length = blr - blr_buffer;
|
|
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;
|
|
const SLONG* range; // used in multiple loops.
|
|
for (range = field->fld_ranges, count = 0; 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 (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)
|
|
{
|
|
int i1, i3;
|
|
/* 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;
|
|
for (i1 = 0, i3 = 0, range = end_ranges - 2;
|
|
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 (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, ULONG count)
|
|
{
|
|
/**************************************
|
|
*
|
|
* 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;
|
|
UCHAR blob_info[32], static_buffer[1024];
|
|
|
|
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;
|
|
}
|
|
|
|
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 = 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_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* 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;
|
|
UCHAR blob_info[32], static_buffer[1024];
|
|
|
|
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
|
|
}
|
|
|
|
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* 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);
|
|
|
|
#ifdef DEBUG
|
|
if (debug_on)
|
|
isc_print_blr((const char*)blr_buffer, NULL, NULL, 0);
|
|
#endif
|
|
|
|
|
|
// Compile request
|
|
|
|
FB_API_HANDLE request = 0;
|
|
SSHORT blr_length = blr - blr_buffer;
|
|
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
|
|
isc_print_blr((const char*) blr_buffer, 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), records);
|
|
}
|
|
}
|
|
|
|
// 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 & 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<const UCHAR*>(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;
|
|
UCHAR blob_info[48], static_buffer[1024];
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
SLONG length = 0;
|
|
USHORT max_segment = 0, num_seg = 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;
|
|
|
|
put_numeric(attribute, length + num_seg);
|
|
|
|
// Allocate a buffer large enough for the largest segment and start grinding.
|
|
|
|
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];
|
|
isc_req_handle req_handle1 = 0;
|
|
|
|
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
|
|
|
|
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( 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];
|
|
|
|
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_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_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);
|
|
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);
|
|
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);
|
|
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;
|
|
}
|
|
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( 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
|
|
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.E 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);
|
|
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);
|
|
|
|
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);
|
|
|
|
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
|
|
|