8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 12:03:02 +01:00
firebird-mirror/src/burp/backup.epp
2004-05-02 23:06:37 +00:00

3999 lines
109 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.
*/
/*
$Id: backup.epp,v 1.56 2004-05-02 23:03:42 skidder Exp $
*/
#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/thd_proto.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
// 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(tgbl* 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(tgbl* 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);
int symbol_length(const TEXT *, ULONG);
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_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
};
#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 tgbl.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},
{0, 0, 0}
};
const SCHAR blob_items[] =
{
isc_info_blob_max_segment,
isc_info_blob_num_segments,
isc_info_blob_type
};
const SCHAR blr_items[] =
{
isc_info_blob_max_segment,
isc_info_blob_total_length
};
const SCHAR 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];
TGBL tdgbl = GET_THREAD_DATA;
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, NULL, NULL, NULL, NULL, NULL);
// 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, 0, 0, 0, 0);
// msg 269 can't write a header record to file %s
}
}
tdgbl->action->act_file = tdgbl->gbl_sw_files;
}
MVOL_init_write(reinterpret_cast<const UCHAR*>(dbb_file),
reinterpret_cast<const UCHAR*>(file_name),
&tdgbl->io_cnt, &tdgbl->io_ptr);
// Write database record
write_database(dbb_file);
// Write global fields
BURP_verbose(150, NULL, NULL, NULL, NULL, NULL);
// msg 150 writing global fields
write_global_fields();
if (tdgbl->BCK_capabilities & BCK_ods6)
{
write_field_dimensions();
BURP_verbose(162, NULL, NULL, NULL, NULL, NULL);
// msg 162 writing shadow files
write_shadow_files();
}
// Write relations
BURP_verbose(154, NULL, NULL, NULL, NULL, NULL);
// msg 154 writing relations
write_relations();
if (tdgbl->BCK_capabilities & BCK_ffmptt)
{
// Write functions
BURP_verbose(148, NULL, NULL, NULL, NULL, NULL);
// msg 148 writing functions
write_functions();
// Write types
BURP_verbose(161, NULL, NULL, NULL, NULL, NULL);
// msg 161 writing types
write_types();
// Write filters
BURP_verbose(146, NULL, NULL, NULL, NULL, NULL);
// msg 146 writing filters
write_filters();
// Write generators
BURP_verbose(164, NULL, NULL, NULL, NULL, NULL);
// msg 164 writing id generators
write_generators();
}
if (tdgbl->BCK_capabilities & BCK_ods8)
{
// Write procedures
BURP_verbose(192, NULL, NULL, NULL, NULL, NULL);
// msg 192 writing stored procedures
write_procedures();
// Write exceptions
BURP_verbose(197, NULL, NULL, NULL, NULL, NULL);
// msg 197 writing exceptions
write_exceptions();
// Write Character Sets
BURP_verbose(msgVerbose_write_charsets, NULL, NULL, NULL, NULL, NULL);
write_character_sets();
// Write Collations
BURP_verbose(msgVerbose_write_collations, NULL, NULL, NULL, NULL,
NULL);
write_collations();
}
// 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, NULL, NULL, NULL, NULL, NULL);
// msg 159 writing triggers
write_triggers();
BURP_verbose(158, NULL, NULL, NULL, NULL, NULL);
// 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, NULL, NULL, NULL, NULL);
// 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, NULL, NULL, NULL, NULL, NULL);
// msg 206 writing relation constraints
write_rel_constraints();
// Write referential constraints
BURP_verbose(209, NULL, NULL, NULL, NULL, NULL);
// msg 209 writing referential constraints
write_ref_constraints();
// Write check constraints
BURP_verbose(210, NULL, NULL, NULL, NULL, NULL);
// msg 210 writing check constraints
write_check_constraints();
}
if (tdgbl->BCK_capabilities & BCK_ods9)
{
// Write SQL roles
BURP_verbose(248, NULL, NULL, NULL, NULL, NULL);
// msg 248 writing SQL roles
write_sql_roles();
}
// Finish up
put(tdgbl, (UCHAR) (rec_end));
UINT64 cumul_count = MVOL_fini_write(&tdgbl->io_cnt, &tdgbl->io_ptr);
if (cumul_count <= MAX_SLONG) {
SLONG tempcount = cumul_count;
BURP_verbose(176, (void*) (IPTR)tempcount, NULL, NULL, NULL, NULL);
// msg 176 closing file, committing, and finishing. %ld bytes written
}
else {
char psz[64];
sprintf(psz, "%" QUADFORMAT "d", cumul_count);
BURP_verbose(283, psz, NULL, NULL, NULL, NULL);
// msg 283 closing file, committing, and finishing. %s 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.
*
**************************************/
TGBL tdgbl = GET_THREAD_DATA;
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.
*
**************************************/
const ULONG l = (ULONG) symbol_length (from, size_len);
MOVE_FAST(from, to, 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.
*
**************************************/
TGBL tdgbl = GET_THREAD_DATA;
BURP_print_status(isc_status);
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;
TGBL tdgbl = GET_THREAD_DATA;
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, field->fld_name, NULL);
}
// 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, field->fld_name, NULL);
}
// 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
TGBL tdgbl = GET_THREAD_DATA;
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.
stuff(&blr, blr_version5);
stuff(&blr, blr_begin);
stuff(&blr, blr_message);
stuff(&blr, 0);
stuff_word(&blr, 1);
stuff(&blr, blr_int64);
stuff(&blr, 0);
stuff(&blr, blr_send);
stuff(&blr, 0);
stuff(&blr, blr_assignment);
stuff(&blr, blr_gen_id);
stuff(&blr, name_len);
while (name_len--)
{
const UCHAR c = *name++;
stuff(&blr, c);
}
stuff(&blr, blr_literal);
stuff(&blr, blr_long);
stuff(&blr, 0);
stuff_word(&blr, 0);
stuff_word(&blr, 0);
stuff(&blr, blr_parameter);
stuff(&blr, 0);
stuff_word(&blr, 0);
stuff(&blr, blr_end);
stuff(&blr, blr_eoc);
}
else
{
// build the blr with the right relation name and 32-bit results
stuff(&blr, blr_version4);
stuff(&blr, blr_begin);
stuff(&blr, blr_message);
stuff(&blr, 0);
stuff_word(&blr, 1);
stuff(&blr, blr_long);
stuff(&blr, 0);
stuff(&blr, blr_send);
stuff(&blr, 0);
stuff(&blr, blr_assignment);
stuff(&blr, blr_gen_id);
stuff(&blr, name_len);
while (name_len--)
{
const UCHAR c = *name++;
stuff(&blr, c);
}
stuff(&blr, blr_literal);
stuff(&blr, blr_long);
stuff(&blr, 0);
stuff_word(&blr, 0);
stuff_word(&blr, 0);
stuff(&blr, blr_parameter);
stuff(&blr, 0);
stuff_word(&blr, 0);
stuff(&blr, blr_end);
stuff(&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, NULL, NULL);
// 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, NULL, NULL);
// 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, NULL, NULL);
// 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.
*
**************************************/
TGBL tdgbl = GET_THREAD_DATA;
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, field->fld_name, NULL);
// 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, field->fld_name, NULL);
// 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
TGBL tdgbl = GET_THREAD_DATA;
// 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
stuff(&blr, isc_sdl_version1);
stuff(&blr, isc_sdl_struct);
stuff(&blr, 1);
stuff(&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)
{
stuff(&blr, field->fld_scale);
}
if (field->fld_type == blr_text || field->fld_type == blr_varying)
stuff_word(&blr, field->fld_length);
if (field->fld_type == blr_varying)
field_length += sizeof(USHORT);
stuff(&blr, isc_sdl_rid);
stuff_word(&blr, relation->rel_id);
stuff(&blr, isc_sdl_fid);
stuff_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++)
{
stuff(&blr, isc_sdl_do2);
stuff(&blr, count);
stuff(&blr, isc_sdl_long_integer);
stuff_long(&blr, range[0]);
stuff(&blr, isc_sdl_long_integer);
stuff_long(&blr, range[1]);
}
stuff(&blr, isc_sdl_element);
stuff(&blr, 1);
stuff(&blr, isc_sdl_scalar);
stuff(&blr, 0);
stuff(&blr, field->fld_dimensions);
for (count = 0; count < field->fld_dimensions; count++)
{
stuff(&blr, isc_sdl_variable);
stuff(&blr, count);
}
stuff(&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, NULL, NULL, NULL, NULL);
// 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)
{
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.
*
**************************************/
TGBL tdgbl = GET_THREAD_DATA;
ULONG l = strlen(string);
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.
*
**************************************/
ISC_STATUS_ARRAY status_vector;
UCHAR blob_info[32], static_buffer[1024];
TGBL tdgbl = GET_THREAD_DATA;
// If the blob is null, don't store it. It will be restored as null.
if (!blob_id->gds_quad_high && !blob_id->gds_quad_low)
return;
// Open the blob and get it's vital statistics
FB_API_HANDLE blob = 0;
if (isc_open_blob(status_vector, &DB, &gds_trans, &blob, blob_id))
{
BURP_print(81, field->fld_name, NULL, NULL, NULL, NULL);
// msg 81 error accessing blob field %s -- continuing
BURP_print_status(status_vector);
return;
}
if (isc_blob_info(status_vector, &blob, sizeof(blob_items),
blob_items, sizeof(blob_info),
(char*) blob_info))
{
BURP_error_redirect(status_vector, 20, NULL, NULL);
// msg 20 isc_blob_info failed
}
put(tdgbl, (UCHAR) (rec_blob));
put_numeric(att_blob_field_number, field->fld_number);
ULONG segments = 0;
USHORT max_segment = 0;
const UCHAR* p = blob_info;
UCHAR item;
while ((item = *p++) != isc_info_end)
{
const USHORT l = (USHORT) isc_vax_integer((const char*) p, 2);
p += 2;
const USHORT n = (USHORT) isc_vax_integer((const char*) p, l);
p += l;
switch (item)
{
case isc_info_blob_max_segment:
put_numeric(att_blob_max_segment, (int) n);
max_segment = n;
break;
case isc_info_blob_type:
put_numeric(att_blob_type, (int) n);
break;
case isc_info_blob_num_segments:
put_numeric(att_blob_number_segments, (int) n);
segments = n;
break;
default:
BURP_error_redirect(NULL, 21, (void*) (IPTR) item, NULL);
// msg 21 don't understand blob info item %ld
}
}
// 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)
{
USHORT segment_length;
if (isc_get_segment(status_vector, &blob, &segment_length, max_segment,
(char*) buffer))
{
BURP_error_redirect(status_vector, 22, NULL, NULL);
}
// 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 (isc_close_blob(status_vector, &blob))
BURP_error_redirect(status_vector, 23, NULL, NULL);
// 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 is there was the blob was present, false otherwise.
*
**************************************/
ISC_STATUS_ARRAY status_vector;
UCHAR blob_info[32], static_buffer[1024];
TGBL tdgbl = GET_THREAD_DATA;
// If the blob is null, don't store it. It will be restored as null.
if (!blob_id->gds_quad_high && !blob_id->gds_quad_low)
return false;
// Open the blob and get it's vital statistics
FB_API_HANDLE blob = 0;
if (isc_open_blob(status_vector, &DB, &gds_trans, &blob, blob_id))
{
BURP_error_redirect(status_vector, 24, NULL, NULL);
// msg 24 isc_open_blob failed
}
if (isc_blob_info(status_vector, &blob, sizeof(blr_items),
(SCHAR *) blr_items, sizeof(blob_info),
(char*) blob_info))
{
BURP_error_redirect(status_vector, 20, NULL, NULL);
// 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 = (USHORT) isc_vax_integer((const char*) p, 2);
p += 2;
const USHORT n = (USHORT) 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, (void *) (IPTR) item, NULL, NULL, NULL, NULL);
// msg 79 don't understand blob info item %ld
return false;
}
}
if (!length)
{
if (isc_close_blob(status_vector, &blob))
BURP_error_redirect(status_vector, 23, NULL, NULL);
// 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);
USHORT segment_length;
while (!isc_get_segment(status_vector, &blob, &segment_length,
(USHORT) max_segment, (char*) buffer))
{
if (segment_length)
{
put_block(tdgbl, buffer, segment_length);
}
}
if (isc_close_blob(status_vector, &blob))
{
BURP_error_redirect(status_vector, 23, NULL, NULL);
}
// 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;
TGBL tdgbl = GET_THREAD_DATA;
// 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;
}
}
/* 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;
stuff(&blr, blr_version4);
stuff(&blr, blr_begin);
stuff(&blr, blr_message);
stuff(&blr, 0); // Message number
stuff_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];
stuff(&blr, field->fld_type);
stuff_word(&blr, field->fld_length);
break;
case blr_varying:
alignment = type_alignments[dtype_varying];
stuff(&blr, field->fld_type);
stuff_word(&blr, field->fld_length);
length += sizeof(USHORT);
break;
case blr_short:
alignment = type_alignments[dtype_short];
stuff(&blr, field->fld_type);
stuff(&blr, field->fld_scale);
break;
case blr_long:
alignment = type_alignments[dtype_long];
stuff(&blr, field->fld_type);
stuff(&blr, field->fld_scale);
break;
case blr_quad:
alignment = type_alignments[dtype_quad];
stuff(&blr, field->fld_type);
stuff(&blr, field->fld_scale);
break;
case blr_int64:
alignment = type_alignments[dtype_int64];
stuff(&blr, field->fld_type);
stuff(&blr, field->fld_scale);
break;
case blr_double:
alignment = type_alignments[dtype_double];
stuff(&blr, field->fld_type);
break;
case blr_timestamp:
alignment = type_alignments[dtype_timestamp];
stuff(&blr, field->fld_type);
break;
case blr_sql_time:
alignment = type_alignments[dtype_sql_time];
stuff(&blr, field->fld_type);
break;
case blr_sql_date:
alignment = type_alignments[dtype_sql_date];
stuff(&blr, field->fld_type);
break;
case blr_float:
alignment = type_alignments[dtype_real];
stuff(&blr, field->fld_type);
break;
case blr_blob:
alignment = type_alignments[dtype_blob];
stuff(&blr, blr_quad);
stuff(&blr, 0);
break;
default:
BURP_error_redirect(NULL, 26, (void *) (IPTR) field->fld_type, NULL);
// 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;
stuff(&blr, blr_short);
stuff(&blr, 0);
offset = FB_ALIGN(offset, sizeof(SSHORT));
field->fld_missing_parameter = count++;
offset += sizeof(SSHORT);
}
// Finally, make up an EOF field
stuff(&blr, blr_short); // eof field
stuff(&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
stuff(&blr, blr_for);
stuff(&blr, blr_rse);
stuff(&blr, 1); // count of relations
stuff(&blr, blr_rid);
stuff_word(&blr, relation->rel_id);
stuff(&blr, 0); // context variable
stuff(&blr, blr_end);
stuff(&blr, blr_send);
stuff(&blr, 0);
stuff(&blr, blr_begin);
stuff(&blr, blr_assignment);
stuff(&blr, blr_literal);
stuff(&blr, blr_short);
stuff(&blr, 0);
stuff_word(&blr, 1);
stuff(&blr, blr_parameter);
stuff(&blr, 0);
stuff_word(&blr, eof_parameter);
for (field = relation->rel_fields; field; field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
continue;
stuff(&blr, blr_assignment);
stuff(&blr, blr_fid);
stuff(&blr, 0);
stuff_word(&blr, field->fld_id);
stuff(&blr, blr_parameter2);
stuff(&blr, 0);
stuff_word(&blr, field->fld_parameter);
stuff_word(&blr, field->fld_missing_parameter);
}
stuff(&blr, blr_end);
stuff(&blr, blr_send);
stuff(&blr, 0);
stuff(&blr, blr_assignment);
stuff(&blr, blr_literal);
stuff(&blr, blr_short);
stuff(&blr, 0);
stuff_word(&blr, 0);
stuff(&blr, blr_parameter);
stuff(&blr, 0);
stuff_word(&blr, eof_parameter);
stuff(&blr, blr_end);
stuff(&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, NULL, NULL);
// 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, NULL, NULL, NULL, NULL);
// msg 142 writing data for relation %s
if (isc_start_request(status_vector, &request, &gds_trans, 0))
{
BURP_error_redirect(status_vector, 28, NULL, NULL);
// 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, NULL, NULL);
// msg 29 isc_receive failed
}
if (!*eof)
break;
records++;
// Verbose records
if ((records % BACKUP_VERBOSE_INTERVAL) == 0)
BURP_verbose(108, (void *) (IPTR) records, NULL, NULL, NULL, NULL);
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, (void *) (IPTR) records, NULL, NULL, NULL, NULL);
// msg 108 %ld records written
if (isc_release_request(status_vector, &request))
BURP_error_redirect(status_vector, 30, NULL, NULL);
// 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];
TGBL tdgbl = GET_THREAD_DATA;
/* 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, X.RDB$INDEX_NAME, (void*)(IPTR)count,
(void*)(IPTR)X.RDB$SEGMENT_COUNT, NULL, NULL);
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, NULL, NULL, NULL, NULL);
// 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, (ISC_QUAD *)&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, I_S.RDB$FIELD_NAME, X.RDB$INDEX_NAME, NULL, NULL, NULL);
else
count++;
END_FOR;
ON_ERROR
general_on_error();
END_ERROR;
if (count != (ULONG) X.RDB$SEGMENT_COUNT)
{
BURP_print(180, X.RDB$INDEX_NAME, (void*)(IPTR) count,
(void*)(IPTR) X.RDB$SEGMENT_COUNT, NULL, NULL);
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, NULL, NULL, NULL, NULL);
// 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).
*
**************************************/
TGBL tdgbl = GET_THREAD_DATA;
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.
*
**************************************/
TGBL tdgbl = GET_THREAD_DATA;
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.
*
**************************************/
TGBL tdgbl = GET_THREAD_DATA;
const UINT64 le_value =
(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];
TGBL tdgbl = GET_THREAD_DATA;
/* 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, NULL, NULL, NULL, NULL);
// 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,
(ISC_QUAD *) & 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);
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.
*
**************************************/
ISC_STATUS_ARRAY status_vector;
UCHAR blob_info[48], static_buffer[1024];
TGBL tdgbl = GET_THREAD_DATA;
// If the blob is null, don't store it. It will be restored as null.
if (!blob_id->gds_quad_high && !blob_id->gds_quad_low)
return false;
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
FB_API_HANDLE blob = 0;
if (isc_open_blob(status_vector, &DB, &gds_trans, &blob, blob_id))
{
BURP_error_redirect(status_vector, 24, NULL, NULL);
// msg 24 isc_open_blob failed
}
if (isc_blob_info(status_vector, &blob, sizeof(source_items),
(SCHAR *) source_items, sizeof(blob_info),
(SCHAR*) blob_info))
{
BURP_error_redirect(status_vector, 20, NULL, NULL);
// 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 = (USHORT) isc_vax_integer((const SCHAR*) p, 2);
p += 2;
const USHORT n = (USHORT) 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, (void *)(IPTR) item, NULL, NULL, NULL, NULL);
// msg 79 don't understand blob info item %ld
return false;
}
}
if (!length)
{
if (isc_close_blob(status_vector, &blob))
{
BURP_error_redirect(status_vector, 23, NULL, NULL);
// 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);
USHORT segment_length;
while (!isc_get_segment(status_vector, &blob, &segment_length,
max_segment, (SCHAR*) buffer))
{
if (segment_length)
{
put_block(tdgbl, buffer, segment_length);
}
put(tdgbl, (UCHAR) (NULL));
}
if (isc_close_blob(status_vector, &blob))
BURP_error_redirect(status_vector, 23, NULL, NULL);
// 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.
*
**************************************/
TGBL tdgbl = GET_THREAD_DATA;
const SSHORT l = (SSHORT) 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.
*
**************************************/
TGBL tdgbl = GET_THREAD_DATA;
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);
}
int symbol_length( const TEXT * symbol, ULONG size_len)
{
/**************************************
*
* s y m b o l _ l e n g t h
*
**************************************
*
* Functional description
* Compute length of null terminated symbol.
* CVC: This function should acknowledge embedded blanks.
*
**************************************/
if (size_len < 2) {
return 0;
}
--size_len;
const TEXT* p = symbol;
const TEXT* const q = p + size_len;
while (*p && p < q) { // find end of string (null or end).
p++;
}
--p;
while (p >= symbol && *p == ' ') { // skip trailing blanks
--p;
}
return p + 1 - symbol;
}
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;
TGBL tdgbl = GET_THREAD_DATA;
FOR (REQUEST_HANDLE req_handle1)
X IN RDB$CHARACTER_SETS WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1
put(tdgbl, rec_charset);
PUT_TEXT (att_charset_name, X.RDB$CHARACTER_SET_NAME);
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_TEXT (att_charset_coll, X.RDB$DEFAULT_COLLATE_NAME);
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(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;
TGBL tdgbl = GET_THREAD_DATA;
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;
TGBL tdgbl = GET_THREAD_DATA;
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;
TGBL tdgbl = GET_THREAD_DATA;
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, NULL, NULL);
// 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, NULL, NULL);
// msg 31 isc_database_info failed
break;
}
}
put_asciz(att_file_name, dbb_file);
BURP_verbose(77, dbb_file, (void *) (IPTR) page_size, NULL, NULL, NULL);
// 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;
TGBL tdgbl = GET_THREAD_DATA;
FOR (REQUEST_HANDLE req_handle1)
X IN RDB$EXCEPTIONS
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, NULL, NULL, NULL, NULL);
// 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;
TGBL tdgbl = GET_THREAD_DATA;
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;
TGBL tdgbl = GET_THREAD_DATA;
FOR (REQUEST_HANDLE req_handle1)
X IN RDB$FILTERS
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, NULL, NULL, NULL, NULL);
// 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;
TGBL tdgbl = GET_THREAD_DATA;
FOR (REQUEST_HANDLE req_handle1)
X IN RDB$FUNCTIONS
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, NULL, NULL, NULL, NULL);
/* 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];
TGBL tdgbl = GET_THREAD_DATA;
/* 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, NULL, NULL, NULL, NULL);
// 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, NULL, NULL, NULL, NULL);
// 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];
TGBL tdgbl = GET_THREAD_DATA;
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));
#pragma FB_COMPILER_MESSAGE("BRS: casting SINT64 to SLONG")
BURP_verbose (165, temp, (void*) (IPTR) value, NULL, NULL, NULL);
// 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;
TGBL tdgbl = GET_THREAD_DATA;
/* 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, NULL, NULL, NULL, NULL);
/* 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, NULL, NULL, NULL, NULL);
/* 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;
TGBL tdgbl = GET_THREAD_DATA;
FOR (REQUEST_HANDLE req_handle1)
X IN RDB$PROCEDURES
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, NULL, NULL, NULL, NULL);
/* 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];
TGBL tdgbl = GET_THREAD_DATA;
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, NULL, NULL, NULL, NULL);
// 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;
TGBL tdgbl = GET_THREAD_DATA;
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;
TGBL tdgbl = GET_THREAD_DATA;
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, NULL, NULL, NULL, NULL);
// 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 = 0L, req_handle2 = 0, req_handle3 = 0, req_handle4 = 0;
TGBL tdgbl = GET_THREAD_DATA;
/* 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))
{
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, NULL, NULL, NULL, NULL);
/* 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;
}
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, NULL, NULL, NULL, NULL);
/* 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;
}
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);
}
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;
TGBL tdgbl = GET_THREAD_DATA;
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, NULL, NULL, NULL, NULL);
// 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];
TGBL tdgbl = GET_THREAD_DATA;
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, NULL, NULL, NULL, NULL);
// msg 249 writing SQL role: %s
END_FOR;
ON_ERROR
general_on_error();
END_ERROR;
MISC_release_request_silent(req_handle1);
}
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;
TGBL tdgbl = GET_THREAD_DATA;
/* 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)
{
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, NULL, NULL, NULL, NULL);
// msg 156 writing trigger %s
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, NULL, NULL, NULL, NULL);
// msg 156 writing trigger %s
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;
TGBL tdgbl = GET_THREAD_DATA;
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, NULL, NULL, NULL, NULL);
/* 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;
TGBL tdgbl = GET_THREAD_DATA;
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, X.RDB$TYPE_NAME, X.RDB$FIELD_NAME, NULL, NULL, NULL);
// 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;
TGBL tdgbl = GET_THREAD_DATA;
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, NULL, NULL, NULL, NULL);
// 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, NULL, NULL, NULL, NULL);
// 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