8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 23:23:03 +01:00
firebird-mirror/src/burp/backup.epp
2008-04-13 14:38:39 +00:00

4310 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(attribute, message) put_message ((attribute), (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, UCHAR c)
{
if (--(tdgbl->io_cnt) >= 0)
*(tdgbl->io_ptr)++ = c;
else
MVOL_write(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 SCHAR, const TEXT*);
void put_blob(burp_fld*, ISC_QUAD&, ULONG);
bool put_blr_blob(SCHAR, ISC_QUAD&);
void put_data(burp_rel*);
void put_index(burp_rel*);
int put_message(SCHAR, const TEXT *, ULONG);
void put_numeric(SCHAR, SLONG);
void put_relation(burp_rel*);
bool put_source_blob(SCHAR, SCHAR, ISC_QUAD&);
int put_text(SCHAR, const TEXT *, SSHORT);
void set_capabilities(void);
void write_character_sets(void);
void write_check_constraints(void);
void write_collations(void);
void write_database(const TEXT*);
void write_exceptions(void);
void write_field_dimensions(void);
void write_filters(void);
void write_functions(void);
void write_function_args(GDS_NAME);
void write_generators(void);
void write_sql_roles(void);
void write_mapping(void);
void write_global_fields(void);
void write_procedures(void);
void write_procedure_prms(GDS_NAME);
void write_ref_constraints(void);
void write_rel_constraints(void);
void write_relations(void);
void write_shadow_files(void);
void write_triggers(void);
void write_trigger_messages(void);
void write_types(void);
void write_user_privileges(void);
void general_on_error(void);
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
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
};
// 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() == FALSE)
{
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, (UCHAR) (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 l = 127;
put(tdgbl, (UCHAR) (l));
p = put_block(tdgbl, p, l);
}
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(void)
{
/**************************************
*
* 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;
}
if (isc_start_request(status_vector, &gen_id_reqh,
&gds_trans, // use the same one generated by gpre
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;
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);
if (field->fld_type == blr_short ||
field->fld_type == blr_long ||
field->fld_type == blr_quad ||
field->fld_type == blr_int64)
{
add_byte(blr, field->fld_scale);
}
if (field->fld_type == blr_text || field->fld_type == blr_varying)
add_word(blr, field->fld_length);
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, (UCHAR) (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, (UCHAR) (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 SCHAR 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, (UCHAR) (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, (UCHAR) (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( SCHAR 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, (UCHAR) (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( SCHAR attribute, const TEXT* text, 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).
*
**************************************/
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
ULONG l = 0;
for (const TEXT* p = text; *p && l < length; p++)
l++;
l = length = MIN(l, length);
put(tdgbl, (UCHAR) (attribute));
put(tdgbl, (UCHAR) (l));
if (l)
put_block(tdgbl, reinterpret_cast<const UCHAR*>(text), l);
return length;
}
void put_numeric( SCHAR 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, (UCHAR) (attribute));
put(tdgbl, (UCHAR) sizeof(value));
put_block(tdgbl, (const UCHAR*) &vax_value, sizeof(vax_value));
}
void put_int64( SCHAR 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, (UCHAR) (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, (UCHAR) (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(SCHAR attribute,
SCHAR 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 = isc_vax_integer((const SCHAR*) p, 2);
p += 2;
const ULONG n = isc_vax_integer((const SCHAR*) 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) (NULL));
}
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( SCHAR 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.
*
**************************************/
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
const SSHORT l = (SSHORT) MISC_symbol_length(text, (ULONG) size_len);
put(tdgbl, (UCHAR) (attribute));
put(tdgbl, (UCHAR) (l));
if (l)
put_block(tdgbl, (const UCHAR*) text, l);
return l;
}
void set_capabilities(void)
{
/**************************************
*
* 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(void)
{
/**************************************
*
* 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(void)
{
/**************************************
*
* 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(void)
{
/**************************************
*
* 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 SCHAR 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, (UCHAR) (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, (UCHAR) (att_end));
}
void write_exceptions(void)
{
/**************************************
*
* 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, 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(void)
{
/**************************************
*
* 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(void)
{
/**************************************
*
* 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(void)
{
/**************************************
*
* 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(void)
{
/**************************************
*
* 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(void)
{
/**************************************
*
* 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(void)
{
/**************************************
*
* 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(void)
{
/**************************************
*
* 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_MESSAGE (att_ref_update_rule, X.RDB$UPDATE_RULE);
PUT_MESSAGE (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(void)
{
/**************************************
*
* 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_MESSAGE (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(void)
{
/**************************************
*
* 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(void)
{
/**************************************
*
* 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(void)
{
/**************************************
*
* 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(void)
{
/**************************************
*
* 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(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(void)
{
/**************************************
*
* 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(void)
{
/**************************************
*
* 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, 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(void)
{
/**************************************
*
* 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(void)
{
/**************************************
*
* 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