mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 20:03:02 +01:00
3975 lines
109 KiB
Plaintext
3975 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.46 2003-12-03 08:19:00 robocop Exp $
|
|
*/
|
|
|
|
#include "firebird.h"
|
|
#include "../jrd/ib_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
|
|
};
|
|
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;
|
|
ULONG l;
|
|
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 = NULL;
|
|
|
|
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 (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 = NULL;
|
|
FOR (REQUEST_HANDLE req_handle1)
|
|
X IN RDB$SECURITY_CLASSES WITH X.RDB$SECURITY_CLASS NOT STARTING "SQL$"
|
|
put(tdgbl, rec_security_class);
|
|
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, (ISC_QUAD *)&X.RDB$ACL);
|
|
put_source_blob (att_class_description2, att_class_description,
|
|
(ISC_QUAD *)&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*) tempcount, NULL, NULL, NULL, NULL);
|
|
// msg 176 closing file, committing, and finishing. %ld bytes written
|
|
} else {
|
|
char psz[64];
|
|
ib_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.
|
|
*
|
|
**************************************/
|
|
|
|
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
|
|
SLONG read_msg0;
|
|
SINT64 read_msg1;
|
|
ISC_STATUS_ARRAY status_vector;
|
|
|
|
TGBL tdgbl = GET_THREAD_DATA;
|
|
|
|
FRBRD *gen_id_reqh = NULL;
|
|
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--)
|
|
{
|
|
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--)
|
|
{
|
|
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((char*)blr_buffer, NULL, NULL, 0);
|
|
#endif
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
{
|
|
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.
|
|
*
|
|
**************************************/
|
|
ISC_STATUS_ARRAY status_vector;
|
|
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;
|
|
SLONG *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;
|
|
SLONG *range;
|
|
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
|
|
|
|
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;
|
|
}
|
|
|
|
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 divisor, i1, i2, 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++)
|
|
{
|
|
divisor = 1;
|
|
for (i2 = (2 * (i1 + 1) + 1); i2 <= field->fld_dimensions * 2;
|
|
i2 += 2)
|
|
divisor *=
|
|
(field->fld_ranges[i2] - field->fld_ranges[i2 - 1] + 1);
|
|
*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, (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
|
|
|
|
FRBRD *blob = NULL;
|
|
|
|
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;
|
|
UCHAR *p = blob_info;
|
|
|
|
UCHAR item;
|
|
while ((item = *p++) != isc_info_end)
|
|
{
|
|
USHORT l = (USHORT) isc_vax_integer((char*) p, 2);
|
|
p += 2;
|
|
USHORT n = (USHORT) isc_vax_integer((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*) (ULONG) 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
|
|
|
|
FRBRD *blob = NULL;
|
|
|
|
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;
|
|
UCHAR *p = blob_info;
|
|
UCHAR item;
|
|
|
|
while ((item = *p++) != isc_info_end)
|
|
{
|
|
USHORT l = (USHORT) isc_vax_integer((char*) p, 2);
|
|
p += 2;
|
|
USHORT n = (USHORT) isc_vax_integer((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 *) (ULONG) 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;
|
|
UCHAR *p, *blr, *blr_buffer;
|
|
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 */
|
|
|
|
blr = blr_buffer = BURP_alloc(200 + field_count * 9);
|
|
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 *) (SLONG) 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((char*)blr_buffer, NULL, NULL, 0);
|
|
#endif
|
|
|
|
|
|
// Compile request
|
|
|
|
FRBRD *request = NULL;
|
|
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((char*) blr_buffer, (isc_callback)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 *) (SLONG) records, NULL, NULL, NULL, NULL);
|
|
|
|
put(tdgbl, (UCHAR) (rec_data));
|
|
put_numeric(att_data_length, record_length);
|
|
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 *) (SLONG) 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 l, 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*) count,
|
|
(void*)(ULONG) X.RDB$SEGMENT_COUNT, NULL, NULL);
|
|
continue;
|
|
}
|
|
|
|
put(tdgbl, rec_index);
|
|
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,
|
|
(ISC_QUAD *)&X.RDB$EXPRESSION_SOURCE);
|
|
if (!X.RDB$EXPRESSION_BLR.NULL)
|
|
put_blr_blob (att_index_expression_blr,
|
|
(ISC_QUAD *)&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*) count,
|
|
(void*)(ULONG) X.RDB$SEGMENT_COUNT, NULL, NULL);
|
|
continue;
|
|
}
|
|
|
|
put(tdgbl, rec_index);
|
|
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,
|
|
(ISC_QUAD *)&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,
|
|
(ISC_QUAD *)&I.RDB$EXPRESSION_SOURCE);
|
|
if (!I.RDB$EXPRESSION_BLR.NULL)
|
|
put_blr_blob (att_index_expression_blr,
|
|
(ISC_QUAD *)&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;
|
|
|
|
SLONG vax_value = (SLONG) isc_vax_integer((char*) &value, sizeof(value));
|
|
|
|
put(tdgbl, (UCHAR) (attribute));
|
|
put(tdgbl, (UCHAR) sizeof(value));
|
|
put_block(tdgbl, (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;
|
|
|
|
UINT64 le_value =
|
|
(UINT64) isc_portable_integer((UCHAR*) &value, sizeof(value));
|
|
|
|
put(tdgbl, (UCHAR) (attribute));
|
|
put(tdgbl, (UCHAR) (sizeof(value)));
|
|
put_block(tdgbl, (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];
|
|
USHORT l;
|
|
|
|
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 field, aligned, unaligned, aligned4, aligned8;
|
|
aligned = unaligned = aligned4 = aligned8 = NULL;
|
|
|
|
BURP_FLD fields = get_fields(relation);
|
|
|
|
// sort the list of fields into three lists, depending on alignment
|
|
|
|
for (field = fields; field = fields;)
|
|
{
|
|
fields = field->fld_next;
|
|
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));
|
|
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,
|
|
(ISC_QUAD *) & 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,
|
|
(ISC_QUAD *) & field->fld_default_value);
|
|
put_source_blob(att_field_default_source, att_field_default_source,
|
|
(ISC_QUAD *) & 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);
|
|
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, (ISC_QUAD *) blob_id);
|
|
|
|
// Open the blob and get it's vital statistics
|
|
|
|
FRBRD *blob = NULL;
|
|
|
|
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;
|
|
UCHAR *p = blob_info;
|
|
UCHAR item;
|
|
|
|
while ((item = *p++) != isc_info_end)
|
|
{
|
|
USHORT l = (USHORT) isc_vax_integer((SCHAR*) p, 2);
|
|
p += 2;
|
|
USHORT n = (USHORT) isc_vax_integer((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 *) (ULONG) 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;
|
|
|
|
SSHORT l = (SSHORT) symbol_length (text, (ULONG) size_len);
|
|
|
|
put(tdgbl, (UCHAR) (attribute));
|
|
put(tdgbl, (UCHAR) (l));
|
|
if (l)
|
|
put_block(tdgbl, (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;
|
|
|
|
FRBRD *req = NULL;
|
|
|
|
// 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* 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 = NULL;
|
|
|
|
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, (ISC_QUAD *)&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 = NULL;
|
|
|
|
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 = NULL;
|
|
|
|
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, (ISC_QUAD *)&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 = NULL, req_handle2 = NULL, req_handle3 = NULL;
|
|
|
|
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,
|
|
length, SQL_dialect, db_read_only;
|
|
ULONG sweep_interval, page_buffers;
|
|
for (SCHAR *d = buffer; *d != isc_info_end; d += length)
|
|
{
|
|
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; // parametere 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 *) (ULONG) 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, (ISC_QUAD *)&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,
|
|
(ISC_QUAD *)&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 = NULL;
|
|
|
|
TGBL tdgbl = GET_THREAD_DATA;
|
|
|
|
FOR (REQUEST_HANDLE req_handle1)
|
|
X IN RDB$EXCEPTIONS
|
|
put(tdgbl, rec_exception);
|
|
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, (ISC_QUAD *)&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 = NULL;
|
|
|
|
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 = NULL;
|
|
|
|
TGBL tdgbl = GET_THREAD_DATA;
|
|
|
|
FOR (REQUEST_HANDLE req_handle1)
|
|
X IN RDB$FILTERS
|
|
put(tdgbl, rec_filter);
|
|
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, (ISC_QUAD *)&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 = NULL;
|
|
|
|
TGBL tdgbl = GET_THREAD_DATA;
|
|
|
|
FOR (REQUEST_HANDLE req_handle1)
|
|
X IN RDB$FUNCTIONS
|
|
put(tdgbl, rec_function);
|
|
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, (ISC_QUAD *)&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);
|
|
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);
|
|
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 = NULL;
|
|
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);
|
|
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*) (SLONG) 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 = NULL, req_handle2 = NULL,
|
|
req_handle3 = NULL, req_handle4 = NULL;
|
|
|
|
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);
|
|
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, (ISC_QUAD *)&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, (ISC_QUAD *)&X.RDB$MISSING_VALUE);
|
|
put_blr_blob (att_field_default_value, (ISC_QUAD *)&X.RDB$DEFAULT_VALUE);
|
|
put_blr_blob (att_field_validation_blr, (ISC_QUAD *)&X.RDB$VALIDATION_BLR);
|
|
put_source_blob (att_field_validation_source2, att_field_validation_source, (ISC_QUAD *)&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, (ISC_QUAD *)&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, (ISC_QUAD *)&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, (ISC_QUAD *)&X.RDB$DEFAULT_SOURCE);
|
|
if (!(X.RDB$MISSING_SOURCE.NULL))
|
|
put_source_blob (att_field_missing_source, att_field_missing_source, (ISC_QUAD *)&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);
|
|
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, (ISC_QUAD *)&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, (ISC_QUAD *)&X.RDB$MISSING_VALUE);
|
|
put_blr_blob (att_field_default_value, (ISC_QUAD *)&X.RDB$DEFAULT_VALUE);
|
|
put_blr_blob (att_field_validation_blr, (ISC_QUAD *)&X.RDB$VALIDATION_BLR);
|
|
put_source_blob (att_field_validation_source2, att_field_validation_source, (ISC_QUAD *)&X.RDB$VALIDATION_SOURCE);
|
|
put_blr_blob (att_field_computed_blr, (ISC_QUAD *)&X.RDB$COMPUTED_BLR);
|
|
put_source_blob (att_field_computed_source2, att_field_computed_source, (ISC_QUAD *)&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, (ISC_QUAD *)&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, (ISC_QUAD *)&F.RDB$DEFAULT_SOURCE);
|
|
if (!(F.RDB$MISSING_SOURCE.NULL))
|
|
put_source_blob (att_field_missing_source, att_field_missing_source, (ISC_QUAD *)&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 = NULL;
|
|
|
|
TGBL tdgbl = GET_THREAD_DATA;
|
|
|
|
FOR (REQUEST_HANDLE req_handle1)
|
|
X IN RDB$PROCEDURES
|
|
put(tdgbl, rec_procedure);
|
|
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, (ISC_QUAD *)&X.RDB$DESCRIPTION);
|
|
put_source_blob (att_procedure_source2, att_procedure_source, (ISC_QUAD *)&X.RDB$PROCEDURE_SOURCE);
|
|
put_blr_blob (att_procedure_blr, (ISC_QUAD *)&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);
|
|
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, (ISC_QUAD *)&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 = NULL;
|
|
|
|
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 = NULL;
|
|
|
|
TGBL tdgbl = GET_THREAD_DATA;
|
|
|
|
FOR (REQUEST_HANDLE req_handle1)
|
|
X IN RDB$RELATION_CONSTRAINTS
|
|
put(tdgbl, rec_rel_constraint);
|
|
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 = NULL, req_handle2 = NULL, req_handle3 =
|
|
NULL, req_handle4 = NULL;
|
|
|
|
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);
|
|
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, (ISC_QUAD *)&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, (ISC_QUAD *)&X.RDB$DESCRIPTION);
|
|
put_source_blob (att_relation_view_source2, att_relation_view_source, (ISC_QUAD *)&X.RDB$VIEW_SOURCE);
|
|
|
|
put_source_blob (att_relation_ext_description2, att_relation_ext_description, (ISC_QUAD *)&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);
|
|
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, (ISC_QUAD *)&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, (ISC_QUAD *)&X.RDB$DESCRIPTION);
|
|
put_source_blob (att_relation_view_source2, att_relation_view_source, (ISC_QUAD *)&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, (ISC_QUAD *)&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 = NULL;
|
|
|
|
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);
|
|
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 = NULL;
|
|
TEXT temp[GDS_NAME_LEN];
|
|
|
|
TGBL tdgbl = GET_THREAD_DATA;
|
|
|
|
FOR (REQUEST_HANDLE req_handle1)
|
|
X IN RDB$ROLES
|
|
|
|
put(tdgbl, rec_sql_roles);
|
|
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 = NULL, req_handle2 = NULL;
|
|
|
|
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);
|
|
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, (ISC_QUAD *)&X.RDB$TRIGGER_BLR);
|
|
put_source_blob (att_trig_source2, att_trig_source, (ISC_QUAD *)&X.RDB$TRIGGER_SOURCE);
|
|
put_source_blob (att_trig_description2, att_trig_description, (ISC_QUAD *)&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);
|
|
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, (ISC_QUAD *)&X.RDB$TRIGGER_BLR);
|
|
put_source_blob (att_trig_source2, att_trig_source, (ISC_QUAD *)&X.RDB$TRIGGER_SOURCE);
|
|
put_source_blob (att_trig_description2, att_trig_description, (ISC_QUAD *)&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 = NULL;
|
|
|
|
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);
|
|
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 = NULL;
|
|
|
|
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, (ISC_QUAD *)&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 = NULL;
|
|
|
|
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);
|
|
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);
|
|
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
|
|
|