8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 06:03:02 +01:00
firebird-mirror/src/burp/restore.epp

6885 lines
166 KiB
Plaintext
Raw Normal View History

/*
* PROGRAM: JRD Backup and Restore Program
2001-12-24 03:51:06 +01:00
* MODULE: restore.epp
* DESCRIPTION: Restore 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: Verbose records restored as RESTORE_VERBOSE_INTERVAL,
* also verbose restoring indexes as DEFERRED when verbose
2003-08-21 13:02:33 +02:00
* 2003.08.17 Claudio Valderrama: Fix SF Bug #750659.
*/
/*
$Id: restore.epp,v 1.53 2003-11-07 08:05:38 robocop Exp $
*/
#include "firebird.h"
#include "../jrd/ib_stdio.h"
#include <string.h>
#include <errno.h>
#include "../burp/burp.h"
#include "../jrd/align.h"
#include "../jrd/common.h"
#include "../jrd/flags.h"
#include "../jrd/license.h"
#include "../jrd/obj.h"
#include "../jrd/ods.h"
2001-12-24 03:51:06 +01:00
#include "../jrd/thd_proto.h"
#include "../burp/burp_proto.h"
#include "../burp/canon_proto.h"
#include "../burp/misc_proto.h"
#include "../burp/mvol_proto.h"
#include "../burp/resto_proto.h"
#include "../jrd/gdsassert.h"
#include "../remote/protocol.h"
#ifdef DEBUG
#include "../gpre/prett_proto.h"
#endif
2003-09-23 21:47:50 +02:00
// 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";
2003-09-23 21:47:50 +02:00
#define DB tdgbl->db_handle
#define gds_trans tdgbl->tr_handle
#define isc_status tdgbl->status
namespace // unnamed, private
{
const int DB_VERSION_DDL4 = 4; // ods4 db
const int DB_VERSION_DDL5 = 5; // ods5 db
const int DB_VERSION_DDL8 = 8; // ods8 db
const int DB_VERSION_CURRENT = DB_VERSION_DDL8; // v4.0 is ods8
2003-09-18 23:56:26 +02:00
const char* FOREIGN_KEY = "FOREIGN KEY";
const int DEFERRED_ACTIVE = 3; /* RDB$INDEX_INACTIVE setting for Foreign Keys
2003-09-18 23:56:26 +02:00
* This setting is used temporarily while
* restoring a database. This was required
* in order to differentiate a partial
* "inactive" state of SOME indices from
* "inactive" state of ALL indices (gbak -i)
* -bsriram, 11-May-1999 BUG: 10016
2003-09-18 23:56:26 +02:00
*/
const int RESTORE_VERBOSE_INTERVAL = 10000;
const int cvtbl_len = 28;
2003-09-18 23:56:26 +02:00
enum scan_attr_t {
NO_SKIP = 0, // Not in skipping and scanning mode
BEFORE_SKIP = 1, // After skipping, before scanning next byte for valid attribute
AFTER_SKIP = 2 // After skipping and after scanning next byte for valid attribute
2003-09-18 23:56:26 +02:00
};
void add_files(const UCHAR*);
2003-09-18 23:56:26 +02:00
void bad_attribute(scan_attr_t, ATT_TYPE, USHORT);
USHORT check_db_version (void);
void create_database (const TEXT*);
void decompress (UCHAR *, USHORT);
void eat_blob (void);
BURP_REL find_relation (const TEXT *);
// CVC: when do these functions return false indeed???
// get_acl and get_index are the only exceptions but ironically their
// returned value is not checked by the caller!
bool get_acl (const TEXT*, ISC_QUAD *, ISC_QUAD *);
void get_array (BURP_REL, UCHAR *);
void get_blob (BURP_FLD, UCHAR *);
void get_blr_blob (ISC_QUAD*, bool);
bool get_character_set (void);
bool get_chk_constraint (void);
bool get_collation (void);
rec_type get_data (BURP_REL);
bool get_exception (void);
BURP_FLD get_field (BURP_REL);
bool get_field_dimensions (void);
bool get_files (void);
bool get_filter (void);
bool get_function (void);
void get_function_arg ();
bool get_generator (void);
bool get_global_field (void);
bool get_index (BURP_REL);
void get_misc_blob (ISC_QUAD*, USHORT, bool);
SLONG get_numeric (void);
SINT64 get_int64 (void);
bool get_procedure (void);
bool get_procedure_prm (GDS_NAME );
bool get_ref_constraint (void);
bool get_rel_constraint (void);
bool get_relation (void);
bool get_relation_data (void);
bool get_sql_roles (void);
bool get_security_class (void);
void get_source_blob (ISC_QUAD*, bool);
USHORT get_text (TEXT *, ULONG);
bool get_trigger (void);
bool get_trigger_message (void);
bool get_trigger_old (BURP_REL);
bool get_type (void);
bool get_user_privilege (void);
bool get_view (BURP_REL);
void ignore_array (BURP_REL);
void ignore_blob (void);
rec_type ignore_data (BURP_REL);
void realign (UCHAR *, BURP_REL);
USHORT recompute_length (BURP_REL);
bool restore (const TEXT *, const TEXT *);
2003-09-18 23:56:26 +02:00
void restore_security_class (const TEXT *, const TEXT *);
void store_blr_gen_id (const TEXT*, SINT64);
2003-09-18 23:56:26 +02:00
void stuff_string(UCHAR **, const TEXT *);
void update_global_field (void);
void general_on_error (void);
#ifdef DEBUG
UCHAR debug_on = 0; // able to turn this on in the debugger
#endif
bool flag_on_line = true; /* indicates whether we will bring
the database on-line :
true - we will
false - we will not */
#ifdef sparc
2003-02-13 10:19:08 +01:00
const SSHORT old_sparcs[] =
{0, 0, 0, 2, 0, 0, 0, 0, 2, 4, 4, 4, 8, 8, 0, 0, 8, 8, 8};
#endif
//MVOL_read returns int
2003-09-23 21:47:50 +02:00
static inline int get(tgbl* tdgbl)
{
if (--(tdgbl->io_cnt) >= 0)
return *(tdgbl->io_ptr)++;
else // => superfluous here
return MVOL_read(&tdgbl->io_cnt, &tdgbl->io_ptr);
}
2003-09-23 21:47:50 +02:00
static inline ATT_TYPE get_attribute(ATT_TYPE *att, TGBL tdgbl)
2003-09-21 01:28:38 +02:00
{
*att = (ATT_TYPE) get(tdgbl);
return *att;
}
2003-09-23 21:47:50 +02:00
static inline rec_type get_record(rec_type *rec, TGBL tdgbl)
2003-09-21 01:28:38 +02:00
{
*rec = (rec_type) get(tdgbl);
return *rec;
}
2003-09-23 21:47:50 +02:00
2003-09-21 01:28:38 +02:00
#define GET_TEXT(text) get_text((text), sizeof(text))
2003-09-23 21:47:50 +02:00
static inline void get_skip(tgbl* tdgbl, ULONG n)
{
MVOL_skip_block(tdgbl, n);
}
2003-09-23 21:47:50 +02:00
static inline UCHAR* get_block(tgbl* tdgbl, UCHAR* p, ULONG n)
{
return MVOL_read_block(tdgbl, p, n);
}
2003-09-22 16:13:54 +02:00
// When skipping started, scan_next_attr will be changed from NO_SKIP
// to BEFORE_SKIP. When scanning for next valid attribute after skipping,
// it will flip-flop between BEFORE_SKIP and AFTER_SKIP. When next valid
// attribute is found, it will be changed back to NO_SKIP by 'skip_scan'
2003-09-22 16:13:54 +02:00
static inline void skip_init(scan_attr_t* scan_next_attr)
2003-09-18 23:56:26 +02:00
{
*scan_next_attr = NO_SKIP;
}
2003-09-22 16:13:54 +02:00
static inline void skip_scan(scan_attr_t* scan_next_attr)
2003-09-18 23:56:26 +02:00
{
if (*scan_next_attr == AFTER_SKIP)
*scan_next_attr = BEFORE_SKIP;
else if (*scan_next_attr == BEFORE_SKIP)
*scan_next_attr = NO_SKIP;
//else 0; => nothing, no change in the original macro
2003-09-18 23:56:26 +02:00
}
// User Privilege Flags
2003-09-18 23:56:26 +02:00
const int USER_PRIV_USER = 1;
const int USER_PRIV_GRANTOR = 2;
const int USER_PRIV_PRIVILEGE = 4;
const int USER_PRIV_GRANT_OPTION = 8;
const int USER_PRIV_OBJECT_NAME = 16;
const int USER_PRIV_FIELD_NAME = 32;
const int USER_PRIV_USER_TYPE = 64;
const int USER_PRIV_OBJECT_TYPE = 128;
} // namespace
int RESTORE_restore (const TEXT* file_name,
const TEXT* database_name)
{
/**************************************
*
* R E S T O R E _ r e s t o r e
*
**************************************
*
* Functional description
* Recreate a database from a backup.
*
**************************************/
isc_req_handle req_handle1 = NULL, req_handle2 = NULL, req_handle3 = NULL;
isc_req_handle req_handle4 = NULL;
BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name;
TGBL tdgbl = GET_THREAD_DATA;
tdgbl->io_ptr = NULL;
tdgbl->io_cnt = 0;
tdgbl->relations = NULL;
tdgbl->procedures = NULL;
tdgbl->RESTORE_format = 0;
tdgbl->global_trans = 0;
tdgbl->gbl_sw_transportable = tdgbl->gbl_sw_compress = FALSE;
if (!restore (file_name, database_name))
return FINI_ERROR;
BURP_verbose (76, NULL, NULL, NULL, NULL, NULL);
// msg 76 creating indexes
COMMIT;
ON_ERROR
/* Fix for bug_no 8055:
don't throw away the database just because an index
could not be made */
long error_code;
while (error_code = tdgbl->status_vector[1])
{
switch (error_code)
{
case gds_sort_mem_err:
case gds_no_dup:
strcpy(index_name, (TEXT *)tdgbl->status_vector[3]);
BURP_print_status(tdgbl->status_vector);
FOR (REQUEST_HANDLE req_handle3)
IDX IN RDB$INDICES WITH IDX.RDB$INDEX_NAME EQ index_name
{
BURP_verbose(243, index_name, NULL, NULL, NULL, NULL);
MODIFY IDX USING IDX.RDB$INDEX_INACTIVE = TRUE;
}
BURP_print(240, index_name, NULL, NULL, NULL, NULL);
/* msg 240 Index \"%s\" failed to activate because: */
if ( error_code == gds_no_dup )
{
BURP_print(241, NULL, NULL, NULL, NULL, NULL);
// msg 241 The unique index has duplicate values or NULLs
BURP_print(242, NULL, NULL, NULL, NULL, NULL);
// msg 242 Delete or Update duplicate values or NULLs, and activate index with
}
else
{
BURP_print(244, NULL, NULL, NULL, NULL, NULL);
// msg 244 Not enough disk space to create the sort file for an index
BURP_print(245, NULL, NULL, NULL, NULL, NULL);
// msg 245 Set the TMP environment variable to a directory on a filesystem that does have enough space, and activate index with
}
BURP_print(243, index_name, NULL, NULL, NULL, NULL);
/* msg 243 ALTER INDEX \"%s\" ACTIVE; */
END_MODIFY;
END_FOR;
// don't bring the database on-line
flag_on_line = false;
break;
default:
general_on_error ();
break;
}
COMMIT
ON_ERROR
continue;
END_ERROR
}
END_ERROR;
// Activate the indices for foreign keys and do another commit
if (!(tdgbl->gbl_sw_deactivate_indexes))
{
// Block added to verbose index creation by Toni Martir
if (tdgbl->gbl_sw_verbose)
{
EXEC SQL SET TRANSACTION ISOLATION LEVEL READ COMMITTED NO_AUTO_UNDO;
if (gds_status [1])
EXEC SQL SET TRANSACTION;
// Activate first indexes that are not foreign keys
FOR (REQUEST_HANDLE req_handle1) IDS IN RDB$INDICES WITH
IDS.RDB$INDEX_INACTIVE EQ DEFERRED_ACTIVE AND
IDS.RDB$FOREIGN_KEY MISSING
MODIFY IDS USING IDS.RDB$INDEX_INACTIVE = FALSE;
END_MODIFY;
ON_ERROR
general_on_error();
END_ERROR;
SAVE
// existing ON_ERROR continues past error, beck
ON_ERROR
BURP_print (173, IDS.RDB$INDEX_NAME, NULL, NULL, NULL, NULL);
BURP_print_status(isc_status);
MODIFY IDS USING
IDS.RDB$INDEX_INACTIVE = TRUE;
END_MODIFY;
ON_ERROR
general_on_error ();
END_ERROR;
END_ERROR;
BURP_verbose(122, IDS.RDB$INDEX_NAME, NULL, NULL, NULL, NULL);
END_FOR;
ON_ERROR
general_on_error ();
END_ERROR;
MISC_release_request_silent(req_handle1);
COMMIT;
ON_ERROR
general_on_error ();
END_ERROR;
}
EXEC SQL SET TRANSACTION ISOLATION LEVEL READ COMMITTED NO_AUTO_UNDO;
if (gds_status [1])
EXEC SQL SET TRANSACTION;
/* Only activate Foreign keys that have been marked for deferred
* activation.
* -bsriram, 11-May-1999 BUG: 10016
*/
FOR (REQUEST_HANDLE req_handle1)
CNST IN RDB$RELATION_CONSTRAINTS
CROSS IDS IN RDB$INDICES WITH
CNST.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY AND
CNST.RDB$INDEX_NAME EQ IDS.RDB$INDEX_NAME AND
IDS.RDB$INDEX_INACTIVE EQ DEFERRED_ACTIVE
MODIFY IDS USING
IDS.RDB$INDEX_INACTIVE = FALSE;
END_MODIFY;
ON_ERROR
general_on_error ();
END_ERROR;
SAVE
// existing ON_ERROR continues past error, beck
ON_ERROR
BURP_print (173, IDS.RDB$INDEX_NAME, NULL, NULL, NULL, NULL);
BURP_print_status(isc_status);
MODIFY IDS USING
IDS.RDB$INDEX_INACTIVE = TRUE;
END_MODIFY;
ON_ERROR
general_on_error ();
END_ERROR;
END_ERROR;
BURP_verbose(122, IDS.RDB$INDEX_NAME, NULL, NULL, NULL, NULL);
END_FOR;
ON_ERROR
general_on_error ();
END_ERROR;
MISC_release_request_silent(req_handle1);
COMMIT;
ON_ERROR
general_on_error ();
END_ERROR;
}
if (tdgbl->global_trans)
{
BURP_verbose (68, NULL, NULL, NULL, NULL, NULL);
// msg 68 committing meta data
EXEC SQL COMMIT TRANSACTION tdgbl->global_trans;
if (gds_status [1])
general_on_error ();
// Check to see if there is a warning
if (gds_status [0] == gds_arg_gds && gds_status [1] == 0
2003-09-22 16:13:54 +02:00
&& gds_status [2] != gds_arg_end)
{
BURP_print_warning(gds_status);
2003-09-22 16:13:54 +02:00
}
}
EXEC SQL SET TRANSACTION ISOLATION LEVEL READ COMMITTED NO_AUTO_UNDO;
if (gds_status [1])
EXEC SQL SET TRANSACTION;
/*
** Change ownership of any procedures necessary
*/
for (BURP_PRC procedure = tdgbl->procedures; procedure;
procedure = procedure->prc_next)
{
if (procedure->prc_owner [0])
{
FOR (REQUEST_HANDLE req_handle4)
X IN RDB$PROCEDURES WITH X.RDB$PROCEDURE_NAME EQ procedure->prc_name
MODIFY X
strcpy (X.RDB$OWNER_NAME, procedure->prc_owner);
END_MODIFY;
ON_ERROR
MISC_release_request_silent(req_handle4);
general_on_error ();
END_ERROR;
restore_security_class (procedure->prc_owner, X.RDB$SECURITY_CLASS);
END_FOR;
ON_ERROR
MISC_release_request_silent(req_handle4);
general_on_error ();
END_ERROR;
}
}
MISC_release_request_silent(req_handle4);
// Change ownership of any relations necessary
for (BURP_REL relation = tdgbl->relations; relation; relation = relation->rel_next)
{
if (relation->rel_owner [0])
{
FOR (REQUEST_HANDLE req_handle2)
X IN RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ relation->rel_name
MODIFY X
strcpy (X.RDB$OWNER_NAME, relation->rel_owner);
END_MODIFY;
ON_ERROR
MISC_release_request_silent(req_handle2);
general_on_error ();
END_ERROR;
restore_security_class (relation->rel_owner, X.RDB$SECURITY_CLASS);
restore_security_class (relation->rel_owner, X.RDB$DEFAULT_CLASS);
END_FOR;
ON_ERROR
MISC_release_request_silent(req_handle2);
general_on_error ();
END_ERROR;
}
}
MISC_release_request_silent(req_handle2);
/* Now that changing ownership of tables is over, it is safe to
update the database security class in RDB$DATABASE */
if (tdgbl->database_security_class[0]) // Do it only if it's not NULL
{
FOR (REQUEST_HANDLE req_handle1)
X IN RDB$DATABASE
MODIFY X USING
strncpy(X.RDB$SECURITY_CLASS, tdgbl->database_security_class,
sizeof(X.RDB$SECURITY_CLASS));
END_MODIFY;
ON_ERROR
MISC_release_request_silent(req_handle1);
general_on_error ();
END_ERROR;
END_FOR;
ON_ERROR
MISC_release_request_silent(req_handle1);
general_on_error ();
END_ERROR;
MISC_release_request_silent(req_handle1);
}
COMMIT;
ON_ERROR
general_on_error ();
END_ERROR;
// Check to see if there is a warning
if (gds_status [0] == gds_arg_gds && gds_status [1] == 0
2003-09-22 16:13:54 +02:00
&& gds_status [2] != gds_arg_end)
{
BURP_print_warning(gds_status);
2003-09-22 16:13:54 +02:00
}
BURP_verbose (88, NULL, NULL, NULL, NULL, NULL);
// msg 88 finishing, closing, and going home
UINT64 cumul_count = MVOL_fini_read();
// attach database again to put it online
UCHAR dpb[128];
UCHAR *d = dpb;
*d++ = (UCHAR) gds_dpb_version1;
if (flag_on_line)
{
*d++ = (UCHAR) gds_dpb_online;
*d++ = 0;
}
if (tdgbl->gbl_sw_user)
{
*d++ = (UCHAR) gds_dpb_user_name;
*d++ = (UCHAR) strlen (tdgbl->gbl_sw_user);
for (UCHAR* q = (UCHAR*) tdgbl->gbl_sw_user; *q;)
*d++ = *q++;
}
if (tdgbl->gbl_sw_password)
{
if (!tdgbl->gbl_sw_service_gbak)
*d++ = (UCHAR) gds_dpb_password;
else
*d++ = (UCHAR) gds_dpb_password_enc;
*d++ = (UCHAR) strlen (tdgbl->gbl_sw_password);
for (UCHAR* q = (UCHAR*) tdgbl->gbl_sw_password; *q;)
*d++ = *q++;
}
// set sync writes to engine default
*d++ = (UCHAR) gds_dpb_force_write;
*d++ = 1;
*d++ = (UCHAR) tdgbl->hdr_forced_writes;
2003-09-22 16:13:54 +02:00
// set forced writes to the value which was in the header
SSHORT l = d - dpb;
// long? Are you sure? Why not FRBRD* ???
long db_handle = 0;
if (isc_attach_database (tdgbl->status_vector, 0, database_name,
(isc_db_handle*) &db_handle, l, (SCHAR*) dpb))
{
general_on_error();
}
if (isc_detach_database (tdgbl->status_vector, (isc_db_handle*) &db_handle))
general_on_error();
FINISH
ON_ERROR
general_on_error ();
END_ERROR;
if (!flag_on_line)
{
BURP_print(246, NULL, NULL, NULL, NULL, NULL);
// msg 246 Database is not online due to failure to activate one or more indices.
BURP_print(247, NULL, NULL, NULL, NULL, NULL);
// msg 247 Run gfix -online to bring database online without active indices.
return FINI_DB_NOT_ONLINE;
}
/* If the database is to be restored ReadOnly, set it to read_only now! */
if (tdgbl->gbl_sw_mode && tdgbl->gbl_sw_mode_val)
{
BURP_verbose (280, NULL, NULL, NULL, NULL, NULL);
// msg 280: setting database to read-only access
d = dpb;
*d++ = (UCHAR) gds_dpb_version1;
if (tdgbl->gbl_sw_user)
{
*d++ = (UCHAR) gds_dpb_user_name;
*d++ = (UCHAR) strlen (tdgbl->gbl_sw_user);
for (UCHAR* q = (UCHAR*) tdgbl->gbl_sw_user; *q;)
*d++ = *q++;
}
if (tdgbl->gbl_sw_password)
{
if (!tdgbl->gbl_sw_service_gbak)
*d++ = (UCHAR) gds_dpb_password;
else
*d++ = (UCHAR) gds_dpb_password_enc;
*d++ = (UCHAR) strlen (tdgbl->gbl_sw_password);
for (UCHAR* q = (UCHAR*) tdgbl->gbl_sw_password; *q;)
*d++ = *q++;
}
*d++ = (UCHAR) isc_dpb_set_db_readonly;
*d++ = 1;
*d++ = TRUE; // set database to readOnly mode
l = d - dpb;
db_handle = 0;
if (isc_attach_database (tdgbl->status_vector, 0, database_name,
(isc_db_handle*) &db_handle, l, (SCHAR*) dpb))
{
general_on_error();
}
if (isc_detach_database (tdgbl->status_vector, (isc_db_handle*) &db_handle))
general_on_error();
}
return FINI_OK;
}
namespace // unnamed, private
{
void add_files (const UCHAR* file_name)
{
/**************************************
*
* a d d _ f i l e s
*
**************************************
*
* Functional description
* This should be a multi-file database.
* Store files and starting
* addresses & commit this much.
*
**************************************/
isc_req_handle req_handle1 = NULL;
TGBL tdgbl = GET_THREAD_DATA;
/* store the RDB$FILES records */
SLONG start = 201;
SLONG count = 0;
for (FIL file = tdgbl->gbl_sw_files; file; file = file->fil_next)
{
if (strcmp (file->fil_name, (char*) file_name))
{
count++;
STORE (REQUEST_HANDLE req_handle1)
X IN RDB$FILES
strcpy (X.RDB$FILE_NAME, file->fil_name);
X.RDB$FILE_START = start;
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
MISC_release_request_silent(req_handle1);
BURP_verbose (57, file->fil_name, (void*) start, NULL, NULL, NULL);
// msg 57 adding file %s, starting at page %ld
}
else if (((signed long )file->fil_length) >= start - 1)
file->fil_length -= start - 1;
else
{
2003-09-22 16:13:54 +02:00
BURP_print (96, (void*) file->fil_length, (void*) (start - 1), NULL,
NULL, NULL);
// msg 96 length given for initial file (%ld) is less than minimum (%ld)
file->fil_length = 0;
}
start += file->fil_length;
}
if (count)
{
BURP_verbose (70, NULL, NULL, NULL, NULL, NULL);
// msg 70 committing secondary files
COMMIT
// existing ON_ERROR continues past error, beck
ON_ERROR
BURP_print (174, NULL, NULL, NULL, NULL, NULL);
// msg 174 cannot commit files
BURP_print_status (tdgbl->status_vector);
ROLLBACK;
ON_ERROR
general_on_error ();
END_ERROR;
END_ERROR;
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
if (gds_status [1])
EXEC SQL SET TRANSACTION;
}
}
2003-09-18 23:56:26 +02:00
void bad_attribute (scan_attr_t scan_next_attr,
ATT_TYPE bad_attr,
USHORT type)
{
/**************************************
*
* b a d _ a t t r i b u t e
*
**************************************
*
* Functional description
* We ran into an unsupported attribute.
* but it isn't the end of the world.
* We will try to skip some bad data and
* look for next valid attribute to continue the process.
*
**************************************/
SSHORT skip_l;
TEXT t_name [128];
TGBL tdgbl = GET_THREAD_DATA;
SLONG skip_count = 0;
if (!tdgbl->gbl_sw_skip_count)
{
2003-09-22 16:13:54 +02:00
gds__msg_format(NULL, 12, type, sizeof(t_name), t_name, NULL, NULL,
NULL, NULL, NULL);
BURP_print (80, t_name, (void*) bad_attr, NULL, NULL, NULL);
// msg 80 don't recognize %s attribute %ld -- continuing
skip_l = get(tdgbl);
if (skip_l)
get_skip(tdgbl, skip_l);
}
else
{
if (scan_next_attr == NO_SKIP)
{
skip_count = tdgbl->gbl_sw_skip_count;
get_skip(tdgbl, skip_count);
BURP_print (203, (void*) skip_count, (void*) bad_attr, NULL, NULL, NULL);
//msg 203: skipped %d bytes after reading a bad attribute %d
}
else
{
skip_count ++;
BURP_print (205, (void*) skip_count, (void*) bad_attr, NULL, NULL, NULL);
// msg 205: skipped %d bytes looking for next valid attribute, encountered attribute %d
}
scan_next_attr = AFTER_SKIP;
}
}
USHORT check_db_version (void)
{
/**************************************
*
* c h e c k _ d b _ v e r s i o n
*
**************************************
*
* Functional description
* Find the version number of the database.
*
**************************************/
isc_req_handle req_handle1 = NULL, req_handle2 = NULL;
TGBL tdgbl = GET_THREAD_DATA;
USHORT db_version = DB_VERSION_DDL4;
FOR (REQUEST_HANDLE req_handle1)
FIRST 1 X IN RDB$RELATIONS
WITH X.RDB$RELATION_NAME = "RDB$TRIGGERS"
db_version = DB_VERSION_DDL5;
END_FOR;
ON_ERROR
general_on_error ();
END_ERROR;
MISC_release_request_silent(req_handle1);
FOR (REQUEST_HANDLE req_handle2)
FIRST 1 X IN RDB$RELATIONS
WITH X.RDB$RELATION_NAME = "RDB$PROCEDURES"
db_version = DB_VERSION_DDL8;
END_FOR;
ON_ERROR
general_on_error ();
END_ERROR;
MISC_release_request_silent(req_handle2);
return db_version;
}
void create_database (const TEXT* file_name)
{
/**************************************
*
* c r e a t e _ d a t a b a s e
*
**************************************
*
* Functional description
* create the new database, looking
* to see if there are any interesting
* things to do.
*
**************************************/
SSHORT l;
ISC_STATUS_ARRAY status_vector;
ATT_TYPE attribute;
UCHAR dpb [128], *d, *q;
ULONG page_size, sweep_interval;
USHORT SQL_dialect;
TGBL tdgbl = GET_THREAD_DATA;
/* Get (physical) database record */
page_size = DEFAULT_PAGE_SIZE;
// sweep_interval = -1;
// sweep_interval = 0xFFFFFFFF;
sweep_interval = MAX_ULONG;
bool no_reserve = false;
bool db_read_only = false, SQL_dialect_flag = false;
USHORT forced_writes = 2; // default for the current platform
ULONG page_buffers = 0;
rec_type record;
2003-09-21 01:28:38 +02:00
if (get_record(&record, tdgbl) == rec_physical_db)
{
2003-09-21 01:28:38 +02:00
while (get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_SQL_dialect:
SQL_dialect_flag = true;
SQL_dialect = (USHORT) get_numeric();
break;
case att_page_size:
page_size = get_numeric();
break;
case att_sweep_interval:
sweep_interval = get_numeric();
break;
case att_forced_writes:
forced_writes = (USHORT) get_numeric();
break;
case att_no_reserve:
no_reserve = (USHORT) get_numeric() != FALSE;
break;
case att_db_read_only:
db_read_only = get_numeric() != FALSE;
break;
case att_page_buffers:
page_buffers = get_numeric();
break;
default:
l = get(tdgbl);
if (l)
get_skip(tdgbl, l);
break;
}
}
2003-09-21 01:28:38 +02:00
get_record(&record, tdgbl);
}
if (record != rec_database)
BURP_error_redirect (NULL, 32, 0, 0);
// msg 32 Expected database description record
if (tdgbl->gbl_sw_page_size &&
(tdgbl->gbl_sw_page_size < page_size))
{
2003-09-22 16:13:54 +02:00
BURP_print (110, (void*) page_size,
(void*) (ULONG) tdgbl->gbl_sw_page_size, NULL, NULL, NULL);
// msg 110 Reducing the database page size from %ld bytes to %ld bytes
}
if (tdgbl->gbl_sw_page_size)
page_size = tdgbl->gbl_sw_page_size;
tdgbl->hdr_forced_writes = forced_writes;
if (tdgbl->gbl_sw_no_reserve)
no_reserve = tdgbl->gbl_sw_no_reserve != FALSE;
// Override attribute setting with user requirement
if (tdgbl->gbl_sw_mode)
db_read_only = tdgbl->gbl_sw_mode_val;
else
{
/* No access mode specified by user. Use attribute settings. Since the
* database is set to readOnly only after making it Online in
* RESTORE_restore(), pass on this information through Global structures */
tdgbl->gbl_sw_mode = true;
tdgbl->gbl_sw_mode_val = db_read_only;
}
if (tdgbl->gbl_sw_page_buffers)
page_buffers = tdgbl->gbl_sw_page_buffers;
d = dpb;
*d++ = (UCHAR) isc_dpb_version1;
*d++ = (UCHAR) isc_dpb_page_size;
*d++ = 2;
*d++ = 0;
*d++ = (UCHAR) (page_size >> 8);
*d++ = (UCHAR) isc_dpb_gbak_attach;
*d++ = (UCHAR) strlen(GDS_VERSION);
for (const TEXT* gvp = GDS_VERSION; *gvp;)
*d++ = *gvp++;
if (sweep_interval != MAX_ULONG)
{
*d++ = (UCHAR) isc_dpb_sweep_interval;
*d++ = 4;
*d++ = (UCHAR) sweep_interval;
*d++ = (UCHAR) (sweep_interval >> 8);
*d++ = (UCHAR) (sweep_interval >> 16);
*d++ = (UCHAR) (sweep_interval >> 24);
}
/* If the database is to be restored "read_only", fillup the data pages */
if (no_reserve || db_read_only)
{
*d++ = (UCHAR) isc_dpb_no_reserve;
*d++ = 1;
*d++ = TRUE;
}
if (tdgbl->gbl_sw_user)
{
*d++ = (UCHAR) isc_dpb_user_name;
*d++ = (UCHAR) strlen (tdgbl->gbl_sw_user);
for (q = (UCHAR*) tdgbl->gbl_sw_user; *q;)
*d++ = *q++;
}
if (tdgbl->gbl_sw_password)
{
if (!tdgbl->gbl_sw_service_gbak)
*d++ = (UCHAR) isc_dpb_password;
else
*d++ = (UCHAR) isc_dpb_password_enc;
*d++ = (UCHAR) strlen (tdgbl->gbl_sw_password);
for (q = (UCHAR*) tdgbl->gbl_sw_password; *q;)
*d++ = *q++;
}
if (page_buffers)
{
*d++ = (UCHAR) isc_dpb_set_page_buffers;
*d++ = 4;
*d++ = (UCHAR) page_buffers;
*d++ = (UCHAR) (page_buffers >> 8);
*d++ = (UCHAR) (page_buffers >> 16);
*d++ = (UCHAR) (page_buffers >> 24);
}
// Turn off sync writes during restore
*d++ = (UCHAR) isc_dpb_force_write;
*d++ = 1;
*d++ = 0;
/*
**
** which SQL dialect that this database speaks
** When we restore backup files that came from prior
** to V6, we force the SQL database dialect to 1
**
*/
*d++ = (UCHAR) isc_dpb_sql_dialect;
*d++ = 1;
if (SQL_dialect_flag)
*d++ = (UCHAR) SQL_dialect;
else
*d++ = (UCHAR) SQL_DIALECT_V5;
// start database up shut down
*d++ = (UCHAR) isc_dpb_shutdown;
*d++ = 1;
*d++ = (UCHAR) isc_dpb_shut_attachment;
*d++ = (UCHAR) isc_dpb_shutdown_delay;
*d++ = 2;
*d++ = 0;
*d++ = 0;
l = d - dpb;
if (isc_create_database (status_vector, 0, file_name,
2003-09-23 21:47:50 +02:00
&DB, l, (SCHAR*) dpb, 0))
{
BURP_error_redirect (status_vector, 33, file_name, 0);
// msg 33 failed to create database %s
}
if (tdgbl->gbl_sw_version)
{
BURP_print(139, file_name, NULL, NULL, NULL, NULL);
/* msg 139 Version(s) for database "%s" */
2003-09-23 21:47:50 +02:00
isc_version(&DB, (void (*)()) BURP_output_version, (void*) "\t%s\n");
}
BURP_verbose (74, file_name, (void*) page_size, NULL, NULL, NULL);
// msg 74 created database %s, page_size %ld bytes
}
void decompress (UCHAR* buffer,
2003-09-18 23:56:26 +02:00
USHORT length)
{
/**************************************
*
* d e c o m p r e s s
*
**************************************
*
* Functional description
* Get a number of compressed bytes.
*
**************************************/
UCHAR c, *p, *end;
SSHORT count;
TGBL tdgbl = GET_THREAD_DATA;
p = buffer;
end = p + length;
while (p < end)
{
// This change was made to restore National Semi-Conductor's corrupted
// gbak file and it is in the code base now. -Andrew
count = (SCHAR) get(tdgbl);
if (count > 0)
{
if (end - p < count)
{
BURP_print (202, (void*) (SLONG) count,
(void*) (ULONG) (end - p), NULL, NULL, NULL);
// msg 202: adjusting a decompression length error: invalid length %d was adjusted to %d
count = end - p;
}
p = get_block(tdgbl, p, count);
}
else if (count < 0)
{
if (end + count < p)
{
BURP_print(202, (void*) (SLONG) count,
(void*) (ULONG) (p - end), NULL, NULL, NULL);
// msg 202: adjusting a decompression length error: invalid length %d was adjusted to %d
count = p - end;
}
c = get(tdgbl);
memset (p, c, -count);
p += -count;
}
}
if (p > end)
BURP_error_redirect (NULL, 34, 0, 0);
// msg 34 RESTORE: decompression length error
}
void eat_blob (void)
{
/**************************************
*
* e a t _ b l o b
*
**************************************
*
* Functional description
* Discard a blob from backup file
*
**************************************/
TGBL tdgbl = GET_THREAD_DATA;
SLONG length = get_numeric();
get_skip(tdgbl, length);
}
2003-09-18 23:56:26 +02:00
BURP_REL find_relation (const TEXT *name)
{
/**************************************
*
* f i n d _ r e l a t i o n
*
**************************************
*
* Functional description
* Given a relation name, find the relation block. If there isn't
* one, produce a fatal error.
*
**************************************/
BURP_REL relation;
TGBL tdgbl = GET_THREAD_DATA;
// Why isn't strcmp used here?
for (relation = tdgbl->relations; relation; relation = relation->rel_next)
for (const TEXT *p = relation->rel_name, *q = name; *p == *q; p++, q++)
if (!*p)
return relation;
BURP_error_redirect (NULL, 35, name, 0);
// msg 35 can't find relation %s
return NULL;
}
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 restore.
*
**************************************/
TGBL tdgbl = GET_THREAD_DATA;
2003-09-23 21:47:50 +02:00
BURP_print_status (isc_status);
BURP_abort ();
}
2003-09-18 23:56:26 +02:00
bool get_acl (const TEXT *owner_nm,
ISC_QUAD *blob_id,
ISC_QUAD *new_blob_id)
{
/**************************************
*
* g e t _ a c l
*
**************************************
*
* Functional description
*
* open the blob that contains the ACL list
* get the ACL list of a relation
* replace the owner of the relation in the ACL list with
* the creator of the relation
* create a new blob
* store the new ACL list in the new blob
*
**************************************/
static const SCHAR blr_items [] = {isc_info_blob_max_segment,
isc_info_blob_total_length,
isc_info_blob_num_segments};
ISC_STATUS_ARRAY status_vector;
UCHAR *p, blob_info [32], item, *buffer, static_buffer [1024];
USHORT max_segment, num_segments, new_len = 0;
UCHAR *c_1, *from, *to;
SLONG id_person_len;
isc_blob_handle blob_handle = NULL;
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;
2003-09-23 21:47:50 +02:00
if (isc_open_blob (status_vector, &DB, &gds_trans, &blob, blob_id))
{
// msg 24 gds__open_blob failed
BURP_error_redirect (status_vector, 24, NULL, NULL);
}
if (isc_blob_info (status_vector, &blob, sizeof(blr_items),
(SCHAR *) blr_items, sizeof(blob_info), (SCHAR*) blob_info))
{
// msg 20 gds__blob_info failed
BURP_error_redirect (status_vector, 20, NULL, NULL);
}
SLONG length = 0;
p = blob_info;
while ((item = *p++) != gds_info_end)
{
USHORT l = (USHORT) gds__vax_integer (p, 2);
p += 2;
SLONG n = gds__vax_integer (p, l);
p += l;
switch (item)
{
case isc_info_blob_max_segment:
max_segment = (USHORT) n;
break;
case isc_info_blob_total_length:
length = n;
break;
case isc_info_blob_num_segments:
num_segments = (USHORT) n;
/*
** we assume that the ACL list was written out as
** in one big segment
**
*/
if (num_segments > 1) {
// CVC: I can't see the effect of assert(true)
2003-11-04 00:59:24 +01:00
fb_assert (num_segments > 1);
}
break;
default:
// msg 79 don't understand blob info item %ld
BURP_print (79, (void*) (ULONG) item, NULL, NULL, NULL, NULL);
// CVC: do you return, without closing the blob, dear function???
if (isc_close_blob (status_vector, &blob))
BURP_error_redirect (status_vector, 23, NULL, NULL);
// msg 23 gds__close_blob failed
return false;
2001-12-24 03:51:06 +01:00
}
}
if (!length)
{
if (isc_close_blob (status_vector, &blob))
BURP_error_redirect (status_vector, 23, NULL, NULL);
// msg 23 gds__close_blob failed
return false;
}
// Rdb sometimes gets the length messed up
if (length < max_segment)
length = max_segment;
/*
** Allocate a buffer large enough for the largest segment and start
** grinding.
*/
if (!max_segment || max_segment <= sizeof(static_buffer))
buffer = static_buffer;
else
2003-09-18 23:56:26 +02:00
buffer = BURP_alloc (max_segment);
USHORT return_length = 0;
isc_get_segment (status_vector, &blob, &return_length, max_segment,
(SCHAR*) buffer);
// CVC: we don't check the result of the function. We don't check the
// return_length's value either.
if (isc_close_blob (status_vector, &blob))
{
if (buffer != static_buffer)
BURP_free (buffer);
// msg 23 gds__close_blob failed
BURP_error_redirect (status_vector, 23, NULL, NULL);
}
from = buffer + 3; // skip ACL_version, ACL_id_list, and id_person
id_person_len = (int)*from;
c_1 = (UCHAR*) owner_nm;
UCHAR owner_nm_len = strlen (owner_nm);
2003-09-18 23:56:26 +02:00
UCHAR* new_buffer = BURP_alloc (length - id_person_len + owner_nm_len);
from = buffer;
to = new_buffer;
*to++ = *from++; // copy ACL_verion
*to++ = *from++; // copy ACL_id_list
*to++ = *from++; // copy id_person
*to++ = owner_nm_len;
new_len = new_len + 4;
from = buffer + id_person_len + 4;
for (SLONG cnt = 0; cnt < owner_nm_len; cnt++)
{
*to++ = *c_1++;
new_len++;
}
UCHAR* const end_buffer = buffer + length;
for (from = buffer + id_person_len + 4; from < end_buffer; from++)
{
*to++ = *from;
new_len++;
}
2003-09-23 21:47:50 +02:00
if (isc_create_blob2 (status_vector, &DB, &gds_trans,
&blob_handle, new_blob_id, 0, NULL))
{
if (buffer != static_buffer)
BURP_free (buffer);
if (new_buffer != NULL)
2003-09-18 23:56:26 +02:00
BURP_free (new_buffer);
// msg 37 gds__create_blob failed
BURP_error_redirect (status_vector, 37, 0, 0);
}
if (isc_put_segment (status_vector, &blob_handle, new_len,
reinterpret_cast<const SCHAR*>(new_buffer)))
{
if (buffer != static_buffer)
2003-09-18 23:56:26 +02:00
BURP_free (buffer);
if (new_buffer != NULL)
2003-09-18 23:56:26 +02:00
BURP_free (new_buffer);
// msg 38 gds__put_segment failed
BURP_error_redirect (status_vector, 38, 0, 0);
}
if (isc_close_blob (status_vector, &blob_handle))
{
if (buffer != static_buffer)
2003-09-18 23:56:26 +02:00
BURP_free (buffer);
if (new_buffer != NULL)
2003-09-18 23:56:26 +02:00
BURP_free (new_buffer);
// msg 23 gds__close_blob failed
BURP_error_redirect (status_vector, 23, 0, 0);
}
if (buffer != static_buffer)
2003-09-18 23:56:26 +02:00
BURP_free (buffer);
if (new_buffer != NULL)
2003-09-18 23:56:26 +02:00
BURP_free (new_buffer);
return true;
}
2003-09-18 23:56:26 +02:00
void get_array (BURP_REL relation,
UCHAR *record_buffer)
{
/**************************************
*
* g e t _ a r r a y
*
**************************************
*
* Functional description
* Read array data from input file to nice,
* shiney, new array.
*
**************************************/
BURP_FLD field;
ATT_TYPE attribute;
ISC_STATUS_ARRAY status_vector;
SLONG last_element_dim[MAX_DIMENSION];
SLONG fld_ranges[2 * MAX_DIMENSION];
SLONG *blob_id, return_length, slice_length, *range, *end_ranges,
lcount;
USHORT blr_length, count, field_number, field_length;
UCHAR *buffer, *p;
UCHAR *blr, blr_buffer [200]; // enough for a sdl with 16 dimensions
LSTRING xdr_buffer, xdr_slice;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
// don't free something you don't allocate
xdr_buffer.lstr_allocated = 0;
// Pick up attributes
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_blob_data)
{
switch (attribute)
{
case att_blob_field_number:
field_number = (USHORT)get_numeric();
for (field = relation->rel_fields; field; field = field->fld_next)
if (field->fld_number == field_number)
break;
if (!field)
BURP_error_redirect (NULL, 36, 0, 0);
// msg 36 Can't find field for blob
field_length = field->fld_length;
if (field->fld_type == blr_varying)
field_length += sizeof(USHORT);
slice_length = field_length;
//
// Copy the ranges onto a buffer and let the program
// mess with the copy rather than the original
//
memcpy(fld_ranges,field->fld_ranges, sizeof(fld_ranges));
break;
case att_array_dimensions:
field->fld_dimensions = (SSHORT)get_numeric();
end_ranges = fld_ranges + 2 * field->fld_dimensions;
for (range = fld_ranges; range < end_ranges; range += 2)
{
2003-09-21 01:28:38 +02:00
if (get_attribute(&attribute, tdgbl) != att_array_range_low)
bad_attribute (scan_next_attr, attribute, 58);
// msg 58 array
else
range [0] = get_numeric();
2003-09-21 01:28:38 +02:00
if (get_attribute(&attribute, tdgbl) != att_array_range_high)
bad_attribute (scan_next_attr, attribute, 58);
// msg 58 array
else
range [1] = get_numeric();
slice_length *= (range [1] - range [0] + 1);
}
break;
default:
bad_attribute (scan_next_attr, attribute, 58);
// msg 58 array
break;
}
}
return_length = get(tdgbl);
return_length |= get(tdgbl) << 8;
return_length |= get(tdgbl) << 16;
return_length |= get(tdgbl) << 24;
blob_id = (SLONG*) ((UCHAR*) record_buffer + field->fld_offset);
if (return_length != slice_length)
{
int current_dim, divisor, elements_remaining;
int data_at, elements_written, upper, lower;
int i1, i2, i3;
//
// Ugh! The full array wasn't returned and versions of gbak prior to
// V3.2I don't explicitly signal this. We must recompute the top
// element to restore.
//
// Double Ugh! gbak (Versions prior to 5.0) while backing up calculates
// the top dimensions incorrectly So whatever was written as top dimensions
// is useless. 5.0 gbak has written correct dimensions, but what the heck
// we'll calculate it again
//
elements_remaining = return_length / field_length;
//
// Backup (versions prior to 5.0) has surely written wrong dimensions.
// Ignore whatever is read in fld_ranges and calculate the dimensions
// of the last element. field->fld_ranges has the max dimensions.
// last_element_dim holds only the upper bounds of each dimension.
//
for (i1 = 0, i3 = 0; i1 < field->fld_dimensions; 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);
last_element_dim[i1] =
(elements_remaining - 1) / divisor + field->fld_ranges[i3];
elements_remaining -=
(last_element_dim[i1] - field->fld_ranges[i3]) * divisor;
i3 += 2;
}
#ifdef DEBUG
ib_fprintf(ib_stderr, "\nLast element upper bounds read from backup file:\n");
for (current_dim = 1; current_dim < field->fld_dimensions * 2; current_dim += 2)
ib_fprintf(ib_stderr,"%ld ",fld_ranges[current_dim]);
ib_fprintf(ib_stderr, "\nCalculated Last element upper bounds :\n");
for (current_dim = 0; current_dim < field->fld_dimensions; current_dim++)
ib_fprintf(ib_stderr,"%ld ",last_element_dim[current_dim]);
ib_fprintf(ib_stderr,"return_length = %ld\n", return_length);
ib_fprintf(ib_stderr,"elements_returned = %ld\n", return_length/field_length);
ib_fprintf(ib_stderr,"Max dims[");
for (current_dim = 1; current_dim < field->fld_dimensions * 2; current_dim += 2)
ib_fprintf(ib_stderr,"%ld ",field->fld_ranges[current_dim]);
ib_fprintf(ib_stderr,"]");
#endif
data_at = 0;
//
// We have an irregurlar shaped slice to write. The following for loop
// chops the array into writable rectangular/square slice and sends it
// to the engine. When the loop cycles through all dimensions, we would
// have written the whole of the irregular slice.
//
for (current_dim = 0; current_dim < field->fld_dimensions; current_dim++)
{
blr = blr_buffer;
bool dont_write = false;
// build the sdl
2003-09-18 23:56:26 +02:00
stuff(&blr, gds_sdl_version1);
stuff(&blr, gds_sdl_struct);
2003-09-18 23:56:26 +02:00
stuff(&blr, 1);
if (field->fld_type == blr_text || field->fld_type == blr_varying)
{
if (field->fld_type == blr_text)
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_text2);
else
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_varying2);
stuff_word(&blr, field->fld_character_set_id);
stuff_word(&blr, field->fld_length);
}
else if (field->fld_type == blr_short || field->fld_type == blr_long ||
field->fld_type == blr_quad || field->fld_type == blr_int64)
{
2003-09-18 23:56:26 +02:00
stuff(&blr, field->fld_type);
stuff(&blr, field->fld_scale);
}
else
2003-09-18 23:56:26 +02:00
stuff(&blr, field->fld_type);
stuff(&blr, gds_sdl_relation);
2003-09-18 23:56:26 +02:00
stuff_string(&blr, relation->rel_name);
stuff(&blr, gds_sdl_field);
2003-09-18 23:56:26 +02:00
stuff_string(&blr, field->fld_name);
// each element spec starts here
#ifdef DEBUG
ib_fprintf(ib_stderr,"\nBounds written [");
#endif
elements_written = 1;
end_ranges = field->fld_ranges + 2 * field->fld_dimensions;
//
// Here is the important work. Calculate the the bounds to be written
// so that the resulting slice is a rectangular/square slice.
// For a 2 dimensional array of size 1..N, 1..M, which is partially
// filled, we have already calculated the dims of last element. Say
// if this was x,y (x is row, y is column) then we do
// isc_put_slice(1..x-1, 1..M);
// isc_put_slice(x..x, 1..y);
// similarly for a 3D array [N,M,K] whose last element dims are (x,y,z)
// isc_put_slice(1..x-1, 1..M, 1..K);
// isc_put_slice(x..x, 1..y-1, 1..K);
// isc_put_slice(x..x, y..y, 1..z);
// This is applicable for any number of dimensions.
// Special cases:
// for example in case of a 2D array (10,10) and if the last element
// dims were (1,2), we would just do a isc_put_slice(1..1, 1..2).
// This is applied for any number of dimensions.
//
for (range = field->fld_ranges, count = 0; range < end_ranges;
range += 2, count++)
{
2003-09-22 16:13:54 +02:00
stuff(&blr, gds_sdl_do2);
stuff(&blr, count);
//
// Normally we loop through all dimensions chopping off slices
// and writing them. This works fine but this also means that
// we blindly put slices without actually figuring out if we
// really need to do so. For eg: if we have a 2D array of
// size [10,4] and the last element dims are [6,4] then all
// we need to do is is to put one slice as
// isc_put_slice(1..6,1..4)
// rather than looping through the dimensions and putting
// isc_put_slice(1..5,1..4)
// isc_put_slice(6..6,1..4)
// we could extend this logic to any no of dims. The following
// if condition figures out such cases. This combined with
// the Special case should optimize the no of isc_put_slice
// we perform.
//
if (current_dim + 1 == field->fld_dimensions - 1 &&
field->fld_dimensions-count == 2 &&
last_element_dim[count + 1] == range[3])
{
stuff(&blr, gds_sdl_long_integer);
stuff_long(&blr, range[0]);
lower = range[0];
2003-09-18 23:56:26 +02:00
stuff(&blr, gds_sdl_long_integer);
stuff_long(&blr, last_element_dim [count]);
upper = last_element_dim[count];
elements_written *= (upper - lower + 1);
range += 2;
count++;
2003-09-18 23:56:26 +02:00
stuff(&blr, gds_sdl_do2);
stuff(&blr, count);
stuff(&blr, gds_sdl_long_integer);
stuff_long(&blr, range[0]);
lower = range[0];
2003-09-18 23:56:26 +02:00
stuff(&blr, gds_sdl_long_integer);
stuff_long(&blr, last_element_dim[count]);
upper=last_element_dim[count];
elements_written *= (upper - lower + 1);
++current_dim;
break;
}
if (current_dim == count)
{
2003-09-18 23:56:26 +02:00
stuff(&blr, gds_sdl_long_integer);
stuff_long(&blr, range [0]);
lower = range [0];
stuff(&blr, gds_sdl_long_integer);
upper = (current_dim == field->fld_dimensions - 1) ?
last_element_dim [count] : (last_element_dim [count] - 1);
if (upper < range[0])
{
/**
see Special Case above
**/
dont_write = true;
break;
}
stuff_long(&blr, upper);
}
else if (current_dim < count)
{
2003-09-18 23:56:26 +02:00
stuff(&blr, gds_sdl_long_integer);
stuff_long(&blr, range [0]);
stuff(&blr, gds_sdl_long_integer);
stuff_long(&blr, range [1]);
upper = range[1];
lower = range[0];
}
else if (current_dim > count)
{
stuff(&blr, gds_sdl_long_integer);
stuff_long(&blr, last_element_dim [count]);
stuff(&blr, gds_sdl_long_integer);
stuff_long(&blr, last_element_dim [count]);
upper = lower = last_element_dim[count];
}
elements_written *= (upper - lower + 1);
#ifdef DEBUG
ib_fprintf(ib_stderr,"%d..%d ",lower,upper);
#endif
}
if (dont_write)
continue;
#ifdef DEBUG
ib_fprintf(ib_stderr,"]");
ib_fprintf(ib_stderr,"\n Elements Written=%d ",elements_written);
#endif
2003-09-18 23:56:26 +02:00
stuff(&blr, gds_sdl_element);
stuff(&blr, 1);
stuff(&blr, gds_sdl_scalar);
stuff(&blr, 0);
stuff(&blr, field->fld_dimensions);
for (count = 0; count < field->fld_dimensions; count++)
{
stuff(&blr, gds_sdl_variable);
2003-09-18 23:56:26 +02:00
stuff(&blr, count);
}
2003-09-18 23:56:26 +02:00
stuff(&blr, gds_sdl_eoc);
#ifdef DEBUG
if (debug_on)
PRETTY_print_sdl (blr_buffer, NULL, NULL, 0);
#endif
blr_length = blr - blr_buffer;
if (data_at == 0)
{
2003-09-18 23:56:26 +02:00
buffer = BURP_alloc (return_length);
if (tdgbl->gbl_sw_transportable)
{
2003-09-21 01:28:38 +02:00
if (get_attribute(&attribute, tdgbl) != att_xdr_array)
// msg 55 Expected XDR record length
BURP_error_redirect (NULL, 55, 0, 0);
else
{
xdr_buffer.lstr_allocated = get(tdgbl);
xdr_buffer.lstr_allocated |= get(tdgbl) << 8;
xdr_buffer.lstr_allocated |= get(tdgbl) << 16;
xdr_buffer.lstr_allocated |= get(tdgbl) << 24;
lcount = xdr_buffer.lstr_length = xdr_buffer.lstr_allocated;
2003-09-18 23:56:26 +02:00
xdr_buffer.lstr_address = BURP_alloc (xdr_buffer.lstr_allocated);
xdr_slice.lstr_allocated = xdr_slice.lstr_length = return_length;
xdr_slice.lstr_address = buffer;
p = xdr_buffer.lstr_address;
}
}
else
{
p = buffer;
lcount = return_length;
}
if (lcount)
get_block(tdgbl, p, lcount);
if (tdgbl->gbl_sw_transportable)
CAN_slice (&xdr_buffer, &xdr_slice, FALSE, blr_length, blr_buffer);
}
if (isc_put_slice (status_vector, &DB, &gds_trans,
(ISC_QUAD*) blob_id, blr_length, reinterpret_cast<char*>(blr_buffer),
0, // param length for subset of an array handling
NULL, // param for subset of an array handling
elements_written * field->fld_length,
buffer + data_at))
{
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
return;
}
data_at += elements_written * field->fld_length;
#ifdef DEBUG
ib_fprintf(ib_stderr,"next data_at = %d\n", data_at);
#endif
}
}
else
{ /** This is the regular case we've got the entire array **/
blr = blr_buffer;
// build the sdl
2003-09-18 23:56:26 +02:00
stuff(&blr, gds_sdl_version1);
stuff(&blr, gds_sdl_struct);
2003-09-18 23:56:26 +02:00
stuff(&blr, 1);
if (field->fld_type == blr_text || field->fld_type == blr_varying)
{
if (field->fld_type == blr_text)
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_text2);
else
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_varying2);
stuff_word(&blr, field->fld_character_set_id);
stuff_word(&blr, field->fld_length);
}
else if (field->fld_type == blr_short || field->fld_type == blr_long ||
field->fld_type == blr_quad || field->fld_type == blr_int64)
{
2003-09-18 23:56:26 +02:00
stuff(&blr, field->fld_type);
stuff(&blr, field->fld_scale);
}
else
2003-09-18 23:56:26 +02:00
stuff(&blr, field->fld_type);
stuff(&blr, gds_sdl_relation);
2003-09-18 23:56:26 +02:00
stuff_string(&blr, relation->rel_name);
stuff(&blr, gds_sdl_field);
2003-09-18 23:56:26 +02:00
stuff_string(&blr, field->fld_name);
// each element spec starts here
for (range = fld_ranges, count = 0; range < end_ranges; range += 2, count++)
{
2003-09-18 23:56:26 +02:00
stuff(&blr, gds_sdl_do2);
stuff(&blr, count);
stuff(&blr, gds_sdl_long_integer);
stuff_long(&blr, range [0]);
stuff(&blr, gds_sdl_long_integer);
stuff_long(&blr, range [1]);
}
2003-09-18 23:56:26 +02:00
stuff(&blr, gds_sdl_element);
stuff(&blr, 1);
stuff(&blr, gds_sdl_scalar);
stuff(&blr, 0);
stuff(&blr, field->fld_dimensions);
for (count = 0; count < field->fld_dimensions; count++)
{
2003-09-18 23:56:26 +02:00
stuff(&blr, gds_sdl_variable);
stuff(&blr, count);
}
2003-09-18 23:56:26 +02:00
stuff(&blr, gds_sdl_eoc);
#ifdef DEBUG
if (debug_on)
PRETTY_print_sdl (blr_buffer, NULL, NULL, 0);
#endif
blr_length = blr - blr_buffer;
2003-09-18 23:56:26 +02:00
buffer = BURP_alloc (return_length);
if (tdgbl->gbl_sw_transportable)
{
2003-09-21 01:28:38 +02:00
if (get_attribute(&attribute, tdgbl) != att_xdr_array)
BURP_error_redirect (NULL, 55, 0, 0);
// msg 55 Expected XDR record length
else
{
xdr_buffer.lstr_allocated = get(tdgbl);
xdr_buffer.lstr_allocated |= get(tdgbl) << 8;
xdr_buffer.lstr_allocated |= get(tdgbl) << 16;
xdr_buffer.lstr_allocated |= get(tdgbl) << 24;
lcount = xdr_buffer.lstr_length = xdr_buffer.lstr_allocated;
2003-09-18 23:56:26 +02:00
xdr_buffer.lstr_address = BURP_alloc (xdr_buffer.lstr_allocated);
xdr_slice.lstr_allocated = xdr_slice.lstr_length = return_length;
xdr_slice.lstr_address = buffer;
p = xdr_buffer.lstr_address;
}
}
else
{
p = buffer;
lcount = return_length;
}
if (lcount)
get_block(tdgbl, p, lcount);
if (tdgbl->gbl_sw_transportable)
CAN_slice (&xdr_buffer, &xdr_slice, FALSE, blr_length, blr_buffer);
if (isc_put_slice (status_vector, &DB, &gds_trans,
(ISC_QUAD*) blob_id, blr_length,
reinterpret_cast<char*>(blr_buffer),
0, // param length for subset of an array handling
NULL, // param for subset of an array handling
return_length, buffer))
{
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
return;
}
}
2003-09-18 23:56:26 +02:00
BURP_free (buffer);
if (tdgbl->gbl_sw_transportable && xdr_buffer.lstr_allocated)
2003-09-18 23:56:26 +02:00
BURP_free (xdr_buffer.lstr_address);
}
2003-09-18 23:56:26 +02:00
void get_blob (BURP_FLD fields,
UCHAR *record_buffer)
{
/**************************************
*
* g e t _ b l o b
*
**************************************
*
* Functional description
* Read blob attributes and copy data from input file to nice,
* shiny, new blob.
*
**************************************/
BURP_FLD field;
ATT_TYPE attribute;
ISC_STATUS_ARRAY status_vector;
USHORT field_number, max_segment, length;
UCHAR *buffer, static_buffer [1024];
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
// Pick up attributes
ULONG segments = 0;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_blob_data)
{
switch (attribute)
{
case att_blob_field_number:
field_number = (USHORT)get_numeric();
break;
case att_blob_max_segment:
max_segment = (USHORT)get_numeric();
break;
case att_blob_number_segments:
segments = get_numeric();
break;
case att_blob_type:
get_numeric();
break;
default:
bad_attribute (scan_next_attr, attribute, 64);
// msg 64 blob
break;
}
}
// Find the field associated with the blob
for (field = fields; field; field = field->fld_next)
if (field->fld_number == field_number)
break;
if (!field)
BURP_error_redirect (NULL, 36, 0, 0);
// msg 36 Can't find field for blob
// Create new blob
ISC_QUAD* blob_id = (ISC_QUAD*) ((UCHAR*) record_buffer + field->fld_offset);
FRBRD* blob = NULL;
if (isc_create_blob (status_vector, &DB, &gds_trans, &blob,
(ISC_QUAD*) blob_id))
{
BURP_error_redirect (status_vector, 37, 0, 0);
// msg 37 gds__create_blob failed
}
// Allocate blob buffer is static buffer is too short
if (!max_segment || max_segment <= sizeof(static_buffer))
buffer = static_buffer;
else
2003-09-18 23:56:26 +02:00
buffer = BURP_alloc (max_segment);
// Eat up blob segments
for (; segments > 0; --segments )
{
length = get(tdgbl);
length |= get(tdgbl) << 8;
if (length)
{
get_block(tdgbl, buffer, length);
}
if (isc_put_segment (status_vector, &blob, length,
reinterpret_cast<const SCHAR*>(buffer)))
{
BURP_error_redirect (status_vector, 38, 0, 0);
// msg 38 gds__put_segment failed
}
}
if (isc_close_blob (status_vector, &blob))
BURP_error_redirect (status_vector, 23, 0, 0);
// msg 23 gds__close_blob failed
if (buffer != static_buffer)
2003-09-18 23:56:26 +02:00
BURP_free (buffer);
}
2003-09-18 23:56:26 +02:00
void get_blr_blob (ISC_QUAD *blob_id,
bool glb_trans)
{
/**************************************
*
* g e t _ b l r _ b l o b
*
**************************************
*
* Functional description
* Read blob attributes and copy data from input file to nice,
* shiney, new blob.
*
**************************************/
ISC_STATUS_ARRAY status_vector;
UCHAR *buffer, static_buffer[1024], *p;
isc_tr_handle local_trans;
TGBL tdgbl = GET_THREAD_DATA;
ULONG length = (ULONG)get_numeric();
// Create new blob
FRBRD* blob = NULL;
if (glb_trans && tdgbl->global_trans)
local_trans = tdgbl->global_trans;
else
local_trans = gds_trans;
2003-09-23 21:47:50 +02:00
if (isc_create_blob (status_vector, &DB, &local_trans, &blob, blob_id))
{
BURP_error_redirect (status_vector, 37, 0, 0);
// msg 37 gds__create_blob failed
}
// Allocate blob buffer is static buffer is too short
/* 03 Jun 2003. Nickolay Samofatov. Workaround bug of GCC 3.2.X #11068.
Original code was:
if (!length || length + 1 <= (USHORT)(sizeof(static_buffer)) )
*/
if (length + 1 <= sizeof(static_buffer) )
buffer = static_buffer;
else
2003-09-18 23:56:26 +02:00
buffer = BURP_alloc (length + 1);
if (length)
{
p = get_block(tdgbl, buffer, length);
// Make sure it has an eoc
if (p[-1] != blr_eoc) {
p[0] = blr_eoc;
length++;
}
}
if (isc_put_segment (status_vector, &blob, length,
reinterpret_cast<const SCHAR*>(buffer)))
{
BURP_error_redirect (status_vector, 38, 0, 0);
// msg 38 gds__put_segment failed
}
if (isc_close_blob (status_vector, &blob))
BURP_error_redirect (status_vector, 23, 0, 0);
// msg 23 gds__close_blob failed
if (buffer != static_buffer)
2003-09-18 23:56:26 +02:00
BURP_free (buffer);
}
bool get_character_set (void)
{
/**************************************
*
* g e t _ c h a r a c t e r _ s e t s
*
**************************************
*
* Functional description
* Restore data for user defined character sets
*
**************************************/
2003-09-18 23:56:26 +02:00
ATT_TYPE attribute;
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
STORE (REQUEST_HANDLE tdgbl->handles_get_character_sets_req_handle1)
X IN RDB$CHARACTER_SETS
X.RDB$CHARACTER_SET_NAME.NULL = TRUE;
X.RDB$FORM_OF_USE.NULL = TRUE;
X.RDB$NUMBER_OF_CHARACTERS.NULL = TRUE;
X.RDB$DEFAULT_COLLATE_NAME.NULL = TRUE;
X.RDB$CHARACTER_SET_ID.NULL = TRUE;
X.RDB$SYSTEM_FLAG.NULL = TRUE;
X.RDB$DESCRIPTION.NULL = TRUE;
X.RDB$FUNCTION_NAME.NULL = TRUE;
X.RDB$BYTES_PER_CHARACTER.NULL = TRUE;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_charset_name:
X.RDB$CHARACTER_SET_NAME.NULL = FALSE;
GET_TEXT(X.RDB$CHARACTER_SET_NAME);
2003-09-22 16:13:54 +02:00
BURP_verbose (msgVerbose_restore_charset,
X.RDB$CHARACTER_SET_NAME, NULL, NULL, NULL, NULL);
break;
case att_charset_form:
X.RDB$FORM_OF_USE.NULL = FALSE;
GET_TEXT(X.RDB$FORM_OF_USE);
break;
case att_charset_numchar:
X.RDB$NUMBER_OF_CHARACTERS.NULL = FALSE;
X.RDB$NUMBER_OF_CHARACTERS = (USHORT) get_numeric();
break;
case att_charset_coll:
X.RDB$DEFAULT_COLLATE_NAME.NULL = FALSE;
GET_TEXT(X.RDB$DEFAULT_COLLATE_NAME);
break;
case att_charset_id:
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
X.RDB$CHARACTER_SET_ID = (USHORT) get_numeric();
break;
case att_charset_sysflag:
X.RDB$SYSTEM_FLAG.NULL = FALSE;
X.RDB$SYSTEM_FLAG = (USHORT) get_numeric();
break;
case att_charset_description:
X.RDB$DESCRIPTION.NULL = FALSE;
get_source_blob (&X.RDB$DESCRIPTION, false);
break;
case att_charset_funct:
X.RDB$FUNCTION_NAME.NULL = FALSE;
GET_TEXT(X.RDB$FUNCTION_NAME);
break;
case att_charset_bytes_char:
X.RDB$BYTES_PER_CHARACTER.NULL = FALSE;
X.RDB$BYTES_PER_CHARACTER = (USHORT) get_numeric();
break;
default:
bad_attribute (scan_next_attr, attribute, msgErr_restore_charset);
/* RDB$CHARSETS */
break;
}
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
return true;
}
bool get_chk_constraint (void)
{
/**************************************
*
* g e t _ c h k _ c o n s t r a i n t
*
**************************************
*
* Functional description
* Restore data for check constraints.
*
**************************************/
2003-09-18 23:56:26 +02:00
ATT_TYPE attribute;
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
STORE (REQUEST_HANDLE tdgbl->handles_get_chk_constraint_req_handle1)
X IN RDB$CHECK_CONSTRAINTS
X.RDB$CONSTRAINT_NAME.NULL = TRUE;
X.RDB$TRIGGER_NAME.NULL = TRUE;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_chk_constraint_name:
X.RDB$CONSTRAINT_NAME.NULL = FALSE;
GET_TEXT(X.RDB$CONSTRAINT_NAME);
break;
case att_chk_trigger_name:
X.RDB$TRIGGER_NAME.NULL = FALSE;
GET_TEXT(X.RDB$TRIGGER_NAME);
break;
default:
bad_attribute (scan_next_attr, attribute, 208);
// msg 208 relation constraint
break;
}
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
return true;
}
bool get_collation (void)
{
/**************************************
*
* g e t _ c o l l a t i o n
*
**************************************
*
* Functional description
* Restore data for user defined collations
*
**************************************/
2003-09-18 23:56:26 +02:00
ATT_TYPE attribute;
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
STORE (REQUEST_HANDLE tdgbl->handles_get_collation_req_handle1)
X IN RDB$COLLATIONS
X.RDB$COLLATION_NAME.NULL = TRUE;
X.RDB$COLLATION_ID.NULL = TRUE;
X.RDB$CHARACTER_SET_ID.NULL = TRUE;
X.RDB$COLLATION_ATTRIBUTES.NULL = TRUE;
X.RDB$SYSTEM_FLAG.NULL = TRUE;
X.RDB$DESCRIPTION.NULL = TRUE;
X.RDB$FUNCTION_NAME.NULL = TRUE;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_coll_name:
X.RDB$COLLATION_NAME.NULL = FALSE;
GET_TEXT(X.RDB$COLLATION_NAME);
2003-09-22 16:13:54 +02:00
BURP_verbose(msgVerbose_restore_collation, X.RDB$COLLATION_NAME,
NULL, NULL, NULL, NULL);
break;
case att_coll_id:
X.RDB$COLLATION_ID.NULL = FALSE;
X.RDB$COLLATION_ID = (USHORT) get_numeric();
break;
case att_coll_cs_id:
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
X.RDB$CHARACTER_SET_ID = (USHORT) get_numeric();
break;
case att_coll_attr:
X.RDB$COLLATION_ATTRIBUTES.NULL = FALSE;
X.RDB$COLLATION_ATTRIBUTES = (USHORT) get_numeric();
break;
case att_coll_subtype: // No longer used: 93-11-15 DBS
// still present to handle V4 R&D gbak files
get_numeric();
break;
case att_coll_sysflag:
X.RDB$SYSTEM_FLAG.NULL = FALSE;
X.RDB$SYSTEM_FLAG = (USHORT) get_numeric();
break;
case att_coll_description:
X.RDB$DESCRIPTION.NULL = FALSE;
get_source_blob (&X.RDB$DESCRIPTION, false);
break;
case att_coll_funct:
X.RDB$FUNCTION_NAME.NULL = FALSE;
GET_TEXT(X.RDB$FUNCTION_NAME);
break;
default:
bad_attribute (scan_next_attr, attribute, msgErr_restore_collation);
/* Bad RDB$COLLATION */
break;
}
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
return true;
}
rec_type get_data (BURP_REL relation)
{
/**************************************
*
* g e t _ d a t a
*
**************************************
*
* Functional description
* Write data records for a relation.
*
**************************************/
BURP_FLD field;
TEXT *p;
USHORT l;
SSHORT alignment, dtype;
SSHORT *buffer;
LSTRING data;
SLONG *blob_id;
isc_req_handle req_handle = NULL;
BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name;
TGBL tdgbl = GET_THREAD_DATA;
// If we're only doing meta-data, ignore data records
if (tdgbl->gbl_sw_meta)
return ignore_data (relation);
// Start by counting the interesting fields
RCRD_OFFSET offset = 0;
ULONG length = 0;
USHORT count = 0;
for (field = relation->rel_fields; field; field = field->fld_next)
{
if (!(field->fld_flags & FLD_computed))
{
count++;
length += field->fld_name_length;
}
}
if (tdgbl->RESTORE_format >= 2)
count += count;
// Time to generate blr to store data. Whoppee.
2003-09-18 23:56:26 +02:00
UCHAR* const blr_buffer = (UCHAR*) BURP_alloc (200 + length + count * 18);
UCHAR* blr = blr_buffer;
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_version4);
stuff(&blr, blr_begin);
stuff(&blr, blr_message);
stuff(&blr, 0); // Message number
stuff_word(&blr, count); // Number of fields, counting eof
// Let's reset count.
count = 0;
for (field = relation->rel_fields; field; field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
continue;
// arrays are of various fld_types but are really blobs
dtype = field->fld_type;
length = field->fld_length;
alignment = 4;
if (field->fld_flags & FLD_array)
dtype = blr_blob;
if (dtype <= DTYPE_BLR_MAX)
{
l = gds_cvt_blr_dtype [dtype];
alignment = type_alignments [l];
if (l = type_lengths [l])
length = l;
}
switch (dtype)
{
case blr_text:
case blr_varying:
if (dtype == blr_text)
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_text2);
else
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_varying2);
stuff_word(&blr, field->fld_character_set_id);
stuff_word(&blr, field->fld_length);
if (dtype == blr_varying)
length += sizeof(USHORT);
break;
case blr_short:
case blr_long:
case blr_quad:
case blr_int64:
2003-09-18 23:56:26 +02:00
stuff(&blr, field->fld_type);
stuff(&blr, field->fld_scale);
break;
case blr_float:
case blr_double:
case blr_timestamp:
case blr_sql_time:
case blr_sql_date:
2003-09-18 23:56:26 +02:00
stuff(&blr, field->fld_type);
break;
case blr_blob:
alignment = type_alignments [dtype_blob];
length = type_lengths [dtype_blob];
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_quad);
stuff(&blr, 0);
break;
default:
BURP_error (26, true, isc_arg_number, (void*) (SLONG) field->fld_type,
0, NULL, 0, NULL, 0, NULL, 0, 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;
}
// If this is format version 2, build fields for null flags
if (tdgbl->RESTORE_format >= 2)
for (field = relation->rel_fields; field; field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
continue;
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_short);
stuff(&blr, 0);
offset = FB_ALIGN(offset, sizeof(SSHORT));
field->fld_missing_parameter = count++;
offset += sizeof(SSHORT);
}
length = offset;
// Build STORE statement
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_receive);
stuff(&blr, 0);
stuff(&blr, blr_store);
stuff(&blr, blr_relation);
stuff_string(&blr, relation->rel_name);
stuff(&blr, 0); // context variable
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_begin);
for (field = relation->rel_fields; field; field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
continue;
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_assignment);
if (tdgbl->RESTORE_format >= 2)
{
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_parameter2);
stuff(&blr, 0);
2003-09-18 23:56:26 +02:00
stuff_word(&blr, field->fld_parameter);
stuff_word(&blr, field->fld_missing_parameter);
}
else
{
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_parameter);
stuff(&blr, 0);
stuff_word(&blr, field->fld_parameter);
}
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_field);
stuff(&blr, 0);
stuff_string(&blr, field->fld_name);
}
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_end);
stuff(&blr, blr_end);
stuff(&blr, blr_eoc);
// Compile request
#ifdef DEBUG
isc_print_blr (blr_buffer, NULL, NULL, 0);
#endif
FRBRD *request = NULL;
ISC_STATUS_ARRAY status_vector;
USHORT blr_length = blr - blr_buffer;
if (isc_compile_request (status_vector, &DB, &request,
blr_length, reinterpret_cast<const char*>(blr_buffer)))
{
isc_print_blr(reinterpret_cast<char*>(blr_buffer), NULL, NULL, 0);
if (!tdgbl->gbl_sw_incremental)
BURP_error_redirect (status_vector, 27, 0, 0);
// msg 27 gds__compile_request failed
else
{
BURP_print_status (status_vector);
2003-09-18 23:56:26 +02:00
BURP_free (blr_buffer);
return ignore_data (relation);
}
}
2003-09-18 23:56:26 +02:00
BURP_free (blr_buffer);
buffer = NULL;
BURP_verbose (124, relation->rel_name, NULL, NULL, NULL, NULL);
// msg 124 restoring data for relation %s
data.lstr_allocated = 0;
data.lstr_address = NULL;
ULONG old_length = 0;
ULONG records = 0;
rec_type record;
while (true)
{
if (get(tdgbl) != att_data_length)
BURP_error_redirect (NULL, 39, 0, 0);
// msg 39 expected record length
l = (USHORT) get_numeric();
if (!tdgbl->gbl_sw_transportable && l != length)
{
if (!old_length)
old_length = recompute_length (relation);
if (l != old_length)
{
BURP_error(40, true, isc_arg_number, (void*)length,
isc_arg_number, (void*) (ULONG) l,
0, NULL, 0, NULL, 0, NULL);
// msg 40 wrong length record, expected %ld encountered %ld
}
}
if (!buffer)
2003-09-18 23:56:26 +02:00
buffer = (SSHORT *) BURP_alloc (MAX (length, l));
if (tdgbl->gbl_sw_transportable)
{
if (get(tdgbl) != att_xdr_length)
BURP_error_redirect (NULL, 55, 0, 0);
// msg 55 Expected XDR record length
else
{
data.lstr_length = l = (USHORT) get_numeric();
if (l > data.lstr_allocated)
{
data.lstr_allocated = l;
if (data.lstr_address)
2003-09-18 23:56:26 +02:00
BURP_free (data.lstr_address);
data.lstr_address = (UCHAR *) BURP_alloc (data.lstr_allocated);
}
p = (TEXT*) data.lstr_address;
}
}
else
p = (TEXT*) buffer;
if (get(tdgbl) != att_data_data)
BURP_error_redirect (NULL, 41, 0, 0);
// msg 41 expected data attribute
if (tdgbl->gbl_sw_compress)
decompress ((UCHAR*) p, l);
else
{
get_block(tdgbl, (UCHAR*) p, l);
}
if (old_length)
realign ((UCHAR *)buffer, relation);
if (tdgbl->gbl_sw_transportable)
CAN_encode_decode (relation, &data, (UCHAR *)buffer, FALSE);
records++;
if ((records % RESTORE_VERBOSE_INTERVAL) == 0)
BURP_verbose(107, (void*) (SLONG) records, NULL, NULL, NULL, NULL);
for (field = relation->rel_fields; field; field = field->fld_next)
if ((field->fld_type == blr_blob) || (field->fld_flags & FLD_array))
{
blob_id = (SLONG*) ((SCHAR*) buffer + field->fld_offset);
blob_id[0] = blob_id[1] = 0;
}
2003-09-21 01:28:38 +02:00
get_record(&record, tdgbl);
while (record == rec_blob || record == rec_array)
{
if (record == rec_blob)
get_blob (relation->rel_fields, (UCHAR *) buffer);
else if (record == rec_array)
get_array (relation, (UCHAR *) buffer);
2003-09-21 01:28:38 +02:00
get_record(&record, tdgbl);
}
if (isc_start_and_send (status_vector, &request, &gds_trans, 0,
(USHORT) length, buffer, 0))
{
if (status_vector [1] == gds_not_valid)
{
if (tdgbl->gbl_sw_incremental)
{
BURP_print (138, relation->rel_name, NULL, NULL, NULL, NULL);
// msg 138 validation error on field in relation %s
BURP_print_status (status_vector);
}
else
BURP_error_redirect (status_vector, 47, 0, 0);
// msg 47 warning -- record could not be restored
}
else {
if (tdgbl->gbl_sw_incremental)
{
BURP_print (114, relation->rel_name, NULL, NULL, NULL, NULL);
// msg 114 restore failed for record in relation %s
BURP_print_status (status_vector);
}
else
BURP_error_redirect (status_vector, 48, 0, 0);
// msg 48 gds__send failed
}
}
if (record != rec_data)
break;
} // while (true)
2003-09-18 23:56:26 +02:00
BURP_free (buffer);
if (data.lstr_address)
2003-09-18 23:56:26 +02:00
BURP_free (data.lstr_address);
isc_release_request(status_vector, &request);
if (tdgbl->gbl_sw_incremental)
{
BURP_verbose (72, relation->rel_name, NULL, NULL, NULL, NULL);
// msg 72 committing data for relation %s
COMMIT
// existing ON_ERROR continues past error, beck
ON_ERROR
/* Fix for bug_no 8055:
don't throw away the database just because an index
could not be made */
ISC_STATUS error_code;
while (error_code = tdgbl->status_vector[1])
{
switch (error_code)
{
case gds_sort_mem_err:
case gds_no_dup:
strcpy(index_name, (TEXT *)tdgbl->status_vector[3]);
BURP_print_status(tdgbl->status_vector);
FOR (REQUEST_HANDLE req_handle)
IDX IN RDB$INDICES WITH IDX.RDB$INDEX_NAME EQ index_name
MODIFY IDX USING IDX.RDB$INDEX_INACTIVE = TRUE;
BURP_print(240, index_name, NULL, NULL, NULL, NULL);
/* msg 240 Index \"%s\" failed to activate because: */
if ( error_code == gds_no_dup )
{
BURP_print(241, NULL, NULL, NULL, NULL, NULL);
// msg 241 The unique index has duplicate values or NULLs
BURP_print(242, NULL, NULL, NULL, NULL, NULL);
// msg 242 Delete or Update duplicate values or NULLs, and activate index with
}
else
{
BURP_print(244, NULL, NULL, NULL, NULL, NULL);
// msg 244 Not enough disk space to create the sort file for an index
BURP_print(245, NULL, NULL, NULL, NULL, NULL);
// msg 245 Set the TMP environment variable to a directory on a filesystem that does have enough space, and activate index with
}
BURP_print(243, index_name, NULL, NULL, NULL, NULL);
/* msg 243 ALTER INDEX \"%s\" ACTIVE; */
END_MODIFY;
END_FOR;
// don't bring the database on-line
flag_on_line = false;
// commit one more time
COMMIT
ON_ERROR
continue;
END_ERROR
break;
default:
BURP_print (69, relation->rel_name, NULL, NULL, NULL, NULL);
// msg 69 commit failed on relation %s
BURP_print_status (tdgbl->status_vector);
ROLLBACK;
ON_ERROR
general_on_error ();
END_ERROR;
break;
} // end of switch
} // end of while
END_ERROR;
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
if (gds_status [1])
EXEC SQL SET TRANSACTION;
}
BURP_verbose (107, (void*) (SLONG) records, NULL, NULL, NULL, NULL);
// msg 107 %ld records restored
return record;
}
bool get_exception(void)
{
/**************************************
*
* g e t _ e x c e p t i o n
*
**************************************
*
* Functional description
* Reconstruct a exception.
*
**************************************/
ATT_TYPE attribute;
TEXT temp [GDS_NAME_LEN];
ULONG l;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
STORE (REQUEST_HANDLE tdgbl->handles_get_exception_req_handle1)
X IN RDB$EXCEPTIONS
X.RDB$DESCRIPTION.NULL = TRUE;
X.RDB$MESSAGE.NULL = TRUE;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_exception_name:
l = GET_TEXT(X.RDB$EXCEPTION_NAME);
MISC_terminate (X.RDB$EXCEPTION_NAME, temp, l, sizeof(temp));
BURP_verbose (199, temp, NULL, NULL, NULL, NULL);
// msg 199 restoring exception %s
break;
case att_exception_description:
get_misc_blob (&X.RDB$DESCRIPTION, 0, false);
X.RDB$DESCRIPTION.NULL = FALSE;
break;
case att_exception_description2:
get_source_blob (&X.RDB$DESCRIPTION, false);
X.RDB$DESCRIPTION.NULL = FALSE;
break;
case att_exception_msg:
GET_TEXT(X.RDB$MESSAGE);
X.RDB$MESSAGE.NULL = FALSE;
break;
default:
bad_attribute (scan_next_attr, attribute, 89);
// msg 89 function
break;
}
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
return true;
}
2003-09-18 23:56:26 +02:00
BURP_FLD get_field (BURP_REL relation)
{
/**************************************
*
* g e t _ f i e l d
*
**************************************
*
* Functional description
* Reconstruct a local field.
*
**************************************/
2003-09-18 23:56:26 +02:00
ATT_TYPE attribute;
scan_attr_t scan_next_attr;
isc_tr_handle local_trans;
TGBL tdgbl = GET_THREAD_DATA;
// If it is a view and there is a global transaction then use it
bool global_tr = false;
if ((relation->rel_flags & REL_view) && (tdgbl->global_trans))
{
local_trans = tdgbl->global_trans;
global_tr = true;
}
else
local_trans = gds_trans;
2003-09-18 23:56:26 +02:00
BURP_FLD field = (BURP_FLD) BURP_alloc_zero (sizeof(burp_fld));
STORE (TRANSACTION_HANDLE local_trans
REQUEST_HANDLE tdgbl->handles_get_field_req_handle1)
X IN RDB$RELATION_FIELDS
strcpy (X.RDB$RELATION_NAME, relation->rel_name);
X.RDB$FIELD_POSITION = 0;
memset (X.RDB$QUERY_NAME, ' ', sizeof(X.RDB$QUERY_NAME));
X.RDB$VIEW_CONTEXT.NULL = TRUE;
X.RDB$BASE_FIELD.NULL = TRUE;
X.RDB$SECURITY_CLASS.NULL = TRUE;
X.RDB$QUERY_NAME.NULL = TRUE;
X.RDB$QUERY_HEADER.NULL = TRUE;
X.RDB$EDIT_STRING.NULL = TRUE;
X.RDB$DESCRIPTION.NULL = TRUE;
X.RDB$FIELD_POSITION.NULL = TRUE;
X.RDB$SYSTEM_FLAG.NULL = TRUE;
X.RDB$COMPLEX_NAME.NULL = TRUE;
X.RDB$UPDATE_FLAG.NULL = TRUE;
X.RDB$DEFAULT_SOURCE.NULL = TRUE;
X.RDB$DEFAULT_VALUE.NULL = TRUE;
X.RDB$NULL_FLAG.NULL = TRUE;
X.RDB$COLLATION_ID.NULL = TRUE;
skip_init(&scan_next_attr);
2003-09-21 01:28:38 +02:00
while (get_attribute(&attribute, tdgbl) != att_end)
{
switch (skip_scan(&scan_next_attr), attribute)
{
case att_field_name:
field->fld_name_length = GET_TEXT(field->fld_name);
BURP_verbose (115, field->fld_name, NULL, NULL, NULL, NULL);
// msg 115 restoring field %s
strcpy (X.RDB$FIELD_NAME, field->fld_name);
break;
case att_field_source:
GET_TEXT(X.RDB$FIELD_SOURCE);
break;
case att_field_security_class:
GET_TEXT(X.RDB$SECURITY_CLASS);
X.RDB$SECURITY_CLASS.NULL = FALSE;
break;
case att_field_query_name:
GET_TEXT(X.RDB$QUERY_NAME);
X.RDB$QUERY_NAME.NULL = FALSE;
break;
case att_field_query_header:
X.RDB$QUERY_HEADER.NULL = FALSE;
get_source_blob (&X.RDB$QUERY_HEADER, global_tr);
break;
case att_field_edit_string:
GET_TEXT(X.RDB$EDIT_STRING);
X.RDB$EDIT_STRING.NULL = FALSE;
break;
case att_field_position:
X.RDB$FIELD_POSITION.NULL = FALSE;
X.RDB$FIELD_POSITION = (USHORT) get_numeric();
break;
case att_field_number:
field->fld_number = (USHORT) get_numeric();
break;
case att_field_type:
field->fld_type = (USHORT) get_numeric();
break;
case att_field_length:
field->fld_length = (USHORT) get_numeric();
break;
case att_field_scale:
field->fld_scale = (USHORT) get_numeric();
break;
case att_field_sub_type:
field->fld_sub_type = (USHORT) get_numeric();
break;
case att_field_system_flag:
X.RDB$SYSTEM_FLAG = (USHORT) get_numeric();
X.RDB$SYSTEM_FLAG.NULL = FALSE;
break;
case att_view_context:
X.RDB$VIEW_CONTEXT = (USHORT) get_numeric();
X.RDB$VIEW_CONTEXT.NULL = FALSE;
break;
case att_field_computed_flag:
if (get_numeric())
field->fld_flags |= FLD_computed;
break;
case att_base_field:
GET_TEXT(X.RDB$BASE_FIELD);
X.RDB$BASE_FIELD.NULL = FALSE;
break;
case att_field_description:
X.RDB$DESCRIPTION.NULL = FALSE;
get_misc_blob (&X.RDB$DESCRIPTION, 1, global_tr);
break;
case att_field_description2:
X.RDB$DESCRIPTION.NULL = FALSE;
get_source_blob (&X.RDB$DESCRIPTION, global_tr);
break;
case att_field_complex_name:
GET_TEXT(X.RDB$COMPLEX_NAME);
X.RDB$COMPLEX_NAME.NULL = FALSE;
break;
case att_field_dimensions:
{
field->fld_dimensions = (USHORT) get_numeric();
field->fld_flags |= FLD_array;
USHORT n = field->fld_dimensions;
for (SLONG *rp = field->fld_ranges; n; rp += 2, n--)
{
2003-09-21 01:28:38 +02:00
if (get_attribute(&attribute, tdgbl) != att_field_range_low)
bad_attribute (scan_next_attr, attribute, 58);
// msg 58 array
else
*rp = get_numeric();
2003-09-21 01:28:38 +02:00
if (get_attribute(&attribute, tdgbl) != att_field_range_high)
bad_attribute (scan_next_attr, attribute, 58);
// msg 58 array
else
*(rp + 1) = get_numeric();
}
}
break;
case att_field_update_flag:
X.RDB$UPDATE_FLAG.NULL = FALSE;
X.RDB$UPDATE_FLAG = (USHORT) get_numeric();
break;
case att_field_character_length:
field->fld_character_length = (USHORT) get_numeric();
break;
case att_field_default_source:
X.RDB$DEFAULT_SOURCE.NULL = FALSE;
get_source_blob (&X.RDB$DEFAULT_SOURCE, global_tr);
break;
case att_field_default_value:
X.RDB$DEFAULT_VALUE.NULL = FALSE;
get_blr_blob (&X.RDB$DEFAULT_VALUE, global_tr);
break;
case att_field_null_flag:
X.RDB$NULL_FLAG.NULL = FALSE;
X.RDB$NULL_FLAG = (USHORT) get_numeric();
break;
case att_field_character_set:
field->fld_character_set_id = (USHORT) get_numeric();
break;
case att_field_collation_id:
field->fld_collation_id = (USHORT) get_numeric();
X.RDB$COLLATION_ID.NULL = FALSE;
X.RDB$COLLATION_ID = field->fld_collation_id;
break;
default:
bad_attribute (scan_next_attr, attribute, 84);
// msg 84 field
break;
}
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
return field;
}
bool get_field_dimensions (void)
{
/**************************************
*
* g e t _ f i e l d _ d i m e n s i o n s
*
**************************************
*
* Functional description
* Get array field dimensions in rdb$field_dimensions.
*
**************************************/
2003-09-18 23:56:26 +02:00
ATT_TYPE attribute;
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
STORE (REQUEST_HANDLE tdgbl->handles_get_field_dimensions_req_handle1)
X IN RDB$FIELD_DIMENSIONS
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_field_name:
GET_TEXT(X.RDB$FIELD_NAME);
break;
case att_field_dimensions:
X.RDB$DIMENSION = (USHORT) get_numeric();
break;
case att_field_range_low:
X.RDB$LOWER_BOUND = get_numeric();
break;
case att_field_range_high:
X.RDB$UPPER_BOUND = get_numeric();
break;
default:
bad_attribute (scan_next_attr, attribute, 58);
// msg 58 array
break;
}
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
return true;
}
bool get_files (void)
{
/**************************************
*
* g e t _ f i l e s
*
**************************************
*
* Functional description
* Get any files that were stored; let
* somebody else worry about what to do with them.
*
**************************************/
2003-09-18 23:56:26 +02:00
ATT_TYPE attribute;
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
STORE (REQUEST_HANDLE tdgbl->handles_get_files_req_handle1)
X IN RDB$FILES
X.RDB$FILE_FLAGS = 0;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_file_filename:
GET_TEXT(X.RDB$FILE_NAME);
BURP_verbose (116,
X.RDB$FILE_NAME, NULL, NULL, NULL, NULL);
// msg 116 restoring file %s
break;
2003-09-22 16:13:54 +02:00
case att_file_sequence:
X.RDB$FILE_SEQUENCE = (USHORT) get_numeric();
break;
2003-09-22 16:13:54 +02:00
case att_file_start:
X.RDB$FILE_START = get_numeric();
break;
2003-09-22 16:13:54 +02:00
case att_file_length:
X.RDB$FILE_LENGTH = get_numeric();
break;
2003-09-22 16:13:54 +02:00
case att_file_flags:
X.RDB$FILE_FLAGS |= get_numeric();
break;
2003-09-22 16:13:54 +02:00
case att_shadow_number:
X.RDB$SHADOW_NUMBER = (USHORT) get_numeric();
if (tdgbl->gbl_sw_kill && X.RDB$SHADOW_NUMBER)
X.RDB$FILE_FLAGS |= FILE_inactive;
break;
2003-09-22 16:13:54 +02:00
default:
bad_attribute (scan_next_attr, attribute, 85);
// msg 85 file
break;
}
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
return true;
}
bool get_filter (void)
{
/**************************************
*
* g e t _ f i l t e r
*
**************************************
*
* Functional description
* Get a type definition in rdb$filters.
*
**************************************/
2003-09-18 23:56:26 +02:00
ATT_TYPE attribute;
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
STORE (REQUEST_HANDLE tdgbl->handles_get_filter_req_handle1)
X IN RDB$FILTERS
X.RDB$DESCRIPTION.NULL = TRUE;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_filter_name:
GET_TEXT(X.RDB$FUNCTION_NAME);
BURP_verbose (117, X.RDB$FUNCTION_NAME, NULL, NULL, NULL, NULL);
// msg 117 restoring filter %s
break;
case att_filter_description:
X.RDB$DESCRIPTION.NULL = FALSE;
get_misc_blob (&X.RDB$DESCRIPTION, 1, false);
break;
case att_filter_description2:
X.RDB$DESCRIPTION.NULL = FALSE;
get_source_blob (&X.RDB$DESCRIPTION, false);
break;
case att_filter_module_name:
GET_TEXT(X.RDB$MODULE_NAME);
break;
case att_filter_entrypoint:
GET_TEXT(X.RDB$ENTRYPOINT);
break;
case att_filter_input_sub_type:
X.RDB$INPUT_SUB_TYPE = (USHORT) get_numeric();
break;
case att_filter_output_sub_type:
X.RDB$OUTPUT_SUB_TYPE = (USHORT) get_numeric();
break;
default:
bad_attribute (scan_next_attr, attribute, 87);
// msg 87 filter
break;
}
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
return true;
}
bool get_function (void)
{
/**************************************
*
* g e t _ f u n c t i o n
*
**************************************
*
* Functional description
* Reconstruct a function.
*
**************************************/
ATT_TYPE attribute;
GDS_NAME function_name;
TEXT temp [GDS_NAME_LEN];
SSHORT l;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
STORE (REQUEST_HANDLE tdgbl->handles_get_function_req_handle1)
X IN RDB$FUNCTIONS
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_function_name:
l = GET_TEXT(X.RDB$FUNCTION_NAME);
MISC_terminate (X.RDB$FUNCTION_NAME, temp, l, sizeof(temp));
BURP_verbose (118, temp, NULL, NULL, NULL, NULL);
// msg 118 restoring function %s
break;
case att_function_description:
get_misc_blob (&X.RDB$DESCRIPTION, 0, false);
break;
case att_function_description2:
get_source_blob (&X.RDB$DESCRIPTION, false);
break;
case att_function_module_name:
GET_TEXT(X.RDB$MODULE_NAME);
break;
case att_function_entrypoint:
GET_TEXT(X.RDB$ENTRYPOINT);
break;
case att_function_return_arg:
X.RDB$RETURN_ARGUMENT = (USHORT) get_numeric();
break;
case att_function_query_name:
GET_TEXT(X.RDB$QUERY_NAME);
break;
case att_function_type:
X.RDB$FUNCTION_TYPE = (USHORT) get_numeric();
break;
default:
bad_attribute (scan_next_attr, attribute, 89);
// msg 89 function
break;
}
}
strcpy (function_name, X.RDB$FUNCTION_NAME);
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
// at the end of args for a function is the rec_function_end marker
while (get(tdgbl) == rec_function_arg)
get_function_arg();
return true;
}
2003-09-22 16:13:54 +02:00
void get_function_arg()
{
/**************************************
*
* g e t _ f u n c t i o n _ a r g
*
**************************************
*
* Functional description
* Reconstruct function argument.
*
**************************************/
ATT_TYPE attribute;
SSHORT l;
TEXT temp [GDS_NAME_LEN];
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
if (tdgbl->RESTORE_format >= 6)
{
/* with RDB$FIELD_PRECISION */
STORE (REQUEST_HANDLE tdgbl->handles_get_function_arg_req_handle1)
X IN RDB$FUNCTION_ARGUMENTS
X.RDB$FIELD_SUB_TYPE.NULL = TRUE;
X.RDB$CHARACTER_SET_ID.NULL = TRUE;
X.RDB$FIELD_PRECISION.NULL = TRUE;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_functionarg_name:
l = GET_TEXT(X.RDB$FUNCTION_NAME);
MISC_terminate (X.RDB$FUNCTION_NAME, temp, l, sizeof(temp));
BURP_verbose (119, temp, NULL, NULL, NULL, NULL);
// msg 119 restoring argument for function %s
break;
case att_functionarg_position:
X.RDB$ARGUMENT_POSITION = (USHORT) get_numeric();
break;
case att_functionarg_mechanism:
X.RDB$MECHANISM = (USHORT) get_numeric();
break;
case att_functionarg_field_type:
X.RDB$FIELD_TYPE = (USHORT) get_numeric();
break;
case att_functionarg_field_scale:
X.RDB$FIELD_SCALE = (USHORT) get_numeric();
break;
case att_functionarg_field_length:
X.RDB$FIELD_LENGTH = (USHORT) get_numeric();
break;
case att_functionarg_field_sub_type:
X.RDB$FIELD_SUB_TYPE.NULL = FALSE;
X.RDB$FIELD_SUB_TYPE = (USHORT) get_numeric();
break;
case att_functionarg_character_set:
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
X.RDB$CHARACTER_SET_ID = (USHORT) get_numeric();
break;
case att_functionarg_field_precision:
X.RDB$FIELD_PRECISION.NULL = FALSE;
X.RDB$FIELD_PRECISION = (USHORT) get_numeric();
break;
default:
bad_attribute (scan_next_attr, attribute, 90);
// msg 90 function argument
break;
}
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
}
else
{
/* without RDB$FIELD_PRECISION */
STORE (REQUEST_HANDLE tdgbl->handles_get_function_arg_req_handle1)
X IN RDB$FUNCTION_ARGUMENTS
X.RDB$FIELD_SUB_TYPE.NULL = TRUE;
X.RDB$CHARACTER_SET_ID.NULL = TRUE;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_functionarg_name:
l = GET_TEXT(X.RDB$FUNCTION_NAME);
MISC_terminate (X.RDB$FUNCTION_NAME, temp, l, sizeof(temp));
BURP_verbose (119, temp, NULL, NULL, NULL, NULL);
// msg 119 restoring argument for function %s
break;
case att_functionarg_position:
X.RDB$ARGUMENT_POSITION = (USHORT) get_numeric();
break;
case att_functionarg_mechanism:
X.RDB$MECHANISM = (USHORT) get_numeric();
break;
case att_functionarg_field_type:
X.RDB$FIELD_TYPE = (USHORT) get_numeric();
break;
case att_functionarg_field_scale:
X.RDB$FIELD_SCALE = (USHORT) get_numeric();
break;
case att_functionarg_field_length:
X.RDB$FIELD_LENGTH = (USHORT) get_numeric();
break;
case att_functionarg_field_sub_type:
X.RDB$FIELD_SUB_TYPE.NULL = FALSE;
X.RDB$FIELD_SUB_TYPE = (USHORT) get_numeric();
break;
case att_functionarg_character_set:
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
X.RDB$CHARACTER_SET_ID = (USHORT) get_numeric();
break;
default:
bad_attribute (scan_next_attr, attribute, 90);
// msg 90 function argument
break;
}
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
}
}
bool get_generator (void)
{
/**************************************
*
* g e t _ g e n e r a t o r
*
**************************************
*
* Functional description
* Pick up a gen-id. Like most things, there is ughly history.
* In the modern world, gen_id are free floating records. In the
* bad old days they were attributes of relations. Handle both
* nicely.
*
**************************************/
SINT64 value = 0;
BASED_ON RDB$GENERATORS.RDB$GENERATOR_NAME name;
name[0] = 0; // just in case.
ATT_TYPE attribute;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_gen_generator:
GET_TEXT(name);
break;
case att_gen_value:
// IB v5 or earlier, gen_id value is an SLONG
value = (SINT64) get_numeric();
break;
case att_gen_value_int64:
// IB v6 or later, gen_id value is an SINT64
value = get_int64();
break;
default:
bad_attribute (scan_next_attr, attribute, 93);
// msg 93 index
break;
}
}
store_blr_gen_id (name, value);
return true;
}
bool get_global_field (void)
{
/**************************************
*
* g e t _ g l o b a l _ f i e l d
*
**************************************
*
* Functional description
* Reconstruct a global field.
*
**************************************/
ATT_TYPE attribute;
TEXT temp [GDS_NAME_LEN];
SSHORT l;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
GFLD gfield = NULL;
if (tdgbl->RESTORE_format >= 6)
{
/* with rdb$field_precision */
STORE (REQUEST_HANDLE tdgbl->handles_get_global_field_req_handle1)
X IN RDB$FIELDS
X.RDB$FIELD_SCALE = X.RDB$SEGMENT_LENGTH = 0;
X.RDB$CHARACTER_SET_ID = X.RDB$COLLATION_ID = 0;
X.RDB$FIELD_SUB_TYPE = 0;
X.RDB$COMPUTED_BLR.NULL = TRUE;
X.RDB$COMPUTED_SOURCE.NULL = TRUE;
X.RDB$QUERY_NAME.NULL = TRUE;
X.RDB$EDIT_STRING.NULL = TRUE;
X.RDB$QUERY_HEADER.NULL = TRUE;
X.RDB$MISSING_VALUE.NULL = TRUE;
X.RDB$DEFAULT_VALUE.NULL = TRUE;
X.RDB$VALIDATION_BLR.NULL = TRUE;
X.RDB$VALIDATION_SOURCE.NULL = TRUE;
X.RDB$SYSTEM_FLAG.NULL = TRUE;
X.RDB$NULL_FLAG.NULL = TRUE;
X.RDB$DESCRIPTION.NULL = TRUE;
X.RDB$DIMENSIONS.NULL = TRUE;
X.RDB$EXTERNAL_LENGTH.NULL = TRUE;
X.RDB$EXTERNAL_TYPE.NULL = TRUE;
X.RDB$EXTERNAL_SCALE.NULL = TRUE;
X.RDB$SEGMENT_LENGTH.NULL = TRUE;
X.RDB$CHARACTER_LENGTH.NULL = TRUE;
X.RDB$MISSING_SOURCE.NULL = TRUE;
X.RDB$DEFAULT_SOURCE.NULL = TRUE;
X.RDB$FIELD_SUB_TYPE.NULL = TRUE;
X.RDB$CHARACTER_SET_ID.NULL = TRUE;
X.RDB$COLLATION_ID.NULL = TRUE;
X.RDB$FIELD_PRECISION.NULL = TRUE;
memset (X.RDB$QUERY_NAME, ' ', sizeof(X.RDB$QUERY_NAME));
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_field_name:
l = GET_TEXT(X.RDB$FIELD_NAME);
MISC_terminate (X.RDB$FIELD_NAME, temp, l, sizeof(temp));
BURP_verbose (121, temp, NULL, NULL, NULL, NULL);
// msg 121 restoring global field %s
break;
case att_field_query_name:
GET_TEXT(X.RDB$QUERY_NAME);
X.RDB$QUERY_NAME.NULL = FALSE;
break;
case att_field_edit_string:
GET_TEXT(X.RDB$EDIT_STRING);
X.RDB$EDIT_STRING.NULL = FALSE;
break;
case att_field_query_header:
X.RDB$QUERY_HEADER.NULL = FALSE;
get_source_blob (&X.RDB$QUERY_HEADER, false);
break;
case att_field_type:
X.RDB$FIELD_TYPE = (USHORT) get_numeric();
break;
case att_field_length:
X.RDB$FIELD_LENGTH = (USHORT) get_numeric();
break;
case att_field_scale:
X.RDB$FIELD_SCALE = (USHORT) get_numeric();
X.RDB$FIELD_SCALE.NULL = FALSE;
break;
case att_field_sub_type:
X.RDB$FIELD_SUB_TYPE = (USHORT) get_numeric();
X.RDB$FIELD_SUB_TYPE.NULL = FALSE;
break;
case att_field_segment_length:
X.RDB$SEGMENT_LENGTH = (USHORT) get_numeric();
if (X.RDB$SEGMENT_LENGTH)
X.RDB$SEGMENT_LENGTH.NULL = FALSE;
break;
case att_field_computed_blr:
X.RDB$COMPUTED_BLR.NULL = FALSE;
get_blr_blob (&X.RDB$COMPUTED_BLR, false);
break;
case att_field_computed_source:
X.RDB$COMPUTED_SOURCE.NULL = FALSE;
get_misc_blob (&X.RDB$COMPUTED_SOURCE, 1, false);
break;
case att_field_computed_source2:
X.RDB$COMPUTED_SOURCE.NULL = FALSE;
get_source_blob (&X.RDB$COMPUTED_SOURCE, false);
break;
case att_field_validation_blr:
if (tdgbl->gbl_sw_novalidity)
eat_blob();
else
{
// if we are going against a V4.0 database,
// restore the global fields in 2 phases.
if (tdgbl->global_trans)
{
if (!gfield)
gfield = (GFLD)BURP_alloc_zero(sizeof(gfld));
get_blr_blob (&gfield->gfld_vb, true);
gfield->gfld_flags |= GFLD_validation_blr;
}
else
{
X.RDB$VALIDATION_BLR.NULL = FALSE;
get_blr_blob (&X.RDB$VALIDATION_BLR, false);
}
}
break;
case att_field_validation_source:
if (tdgbl->gbl_sw_novalidity)
eat_blob();
else
{
// if we are going against a V4.0 database,
// restore the global fields in 2 phases.
if (tdgbl->global_trans)
{
if (!gfield)
gfield = (GFLD)BURP_alloc_zero(sizeof(gfld));
get_misc_blob (&gfield->gfld_vs, 0, true);
gfield->gfld_flags |= GFLD_validation_source;
}
else
{
X.RDB$VALIDATION_SOURCE.NULL = FALSE;
get_misc_blob (&X.RDB$VALIDATION_SOURCE, 0, false);
}
}
break;
case att_field_validation_source2:
if (tdgbl->gbl_sw_novalidity)
eat_blob();
else
{
// if we are going against a V4.0 database,
// restore the global fields in 2 phases.
if (tdgbl->global_trans)
{
if (!gfield)
gfield = (GFLD)BURP_alloc_zero(sizeof(gfld));
get_source_blob (&gfield->gfld_vs2, true);
gfield->gfld_flags |= GFLD_validation_source2;
}
else
{
X.RDB$VALIDATION_SOURCE.NULL = FALSE;
get_source_blob (&X.RDB$VALIDATION_SOURCE, false);
}
}
break;
case att_field_missing_value:
X.RDB$MISSING_VALUE.NULL = FALSE;
get_blr_blob (&X.RDB$MISSING_VALUE, false);
break;
case att_field_default_value:
X.RDB$DEFAULT_VALUE.NULL = FALSE;
get_blr_blob (&X.RDB$DEFAULT_VALUE, false);
break;
case att_field_system_flag:
X.RDB$SYSTEM_FLAG = (USHORT) get_numeric();
X.RDB$SYSTEM_FLAG.NULL = FALSE;
break;
case att_field_null_flag:
X.RDB$NULL_FLAG = (USHORT) get_numeric();
X.RDB$NULL_FLAG.NULL = FALSE;
break;
case att_field_description:
X.RDB$DESCRIPTION.NULL = FALSE;
get_misc_blob (&X.RDB$DESCRIPTION, 1, false);
break;
case att_field_description2:
X.RDB$DESCRIPTION.NULL = FALSE;
get_source_blob (&X.RDB$DESCRIPTION, false);
break;
case att_field_external_length:
X.RDB$EXTERNAL_LENGTH.NULL = FALSE;
X.RDB$EXTERNAL_LENGTH = (USHORT) get_numeric();
break;
case att_field_external_scale:
X.RDB$EXTERNAL_SCALE.NULL = FALSE;
X.RDB$EXTERNAL_SCALE = (USHORT) get_numeric();
break;
case att_field_external_type:
X.RDB$EXTERNAL_TYPE.NULL = FALSE;
X.RDB$EXTERNAL_TYPE = (USHORT) get_numeric();
break;
case att_field_dimensions:
X.RDB$DIMENSIONS.NULL = FALSE;
X.RDB$DIMENSIONS = (USHORT) get_numeric();
break;
case att_field_character_length:
X.RDB$CHARACTER_LENGTH.NULL = FALSE;
X.RDB$CHARACTER_LENGTH = (USHORT) get_numeric();
break;
case att_field_default_source:
X.RDB$DEFAULT_SOURCE.NULL = FALSE;
get_source_blob (&X.RDB$DEFAULT_SOURCE, false);
break;
case att_field_missing_source:
X.RDB$MISSING_SOURCE.NULL = FALSE;
get_source_blob (&X.RDB$MISSING_SOURCE, false);
break;
case att_field_character_set:
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
X.RDB$CHARACTER_SET_ID = (USHORT) get_numeric();
break;
case att_field_collation_id:
X.RDB$COLLATION_ID.NULL = FALSE;
X.RDB$COLLATION_ID = (USHORT) get_numeric();
break;
case att_field_precision:
X.RDB$FIELD_PRECISION.NULL = FALSE;
X.RDB$FIELD_PRECISION = (USHORT) get_numeric();
break;
default:
bad_attribute (scan_next_attr, attribute, 92);
// msg 92 global field
break;
}
}
if (X.RDB$FIELD_TYPE <= DTYPE_BLR_MAX)
{
l = gds_cvt_blr_dtype [X.RDB$FIELD_TYPE];
if (l = type_lengths [l])
X.RDB$FIELD_LENGTH = l;
}
if (gfield)
strcpy (gfield->gfld_name, X.RDB$FIELD_NAME);
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
}
else /* RESTORE_format < 6 */
{
/* without rdb$field_precision */
STORE (REQUEST_HANDLE tdgbl->handles_get_global_field_req_handle1)
X IN RDB$FIELDS
X.RDB$FIELD_SCALE = X.RDB$SEGMENT_LENGTH = 0;
X.RDB$CHARACTER_SET_ID = X.RDB$COLLATION_ID = 0;
X.RDB$FIELD_SUB_TYPE = 0;
X.RDB$COMPUTED_BLR.NULL = TRUE;
X.RDB$COMPUTED_SOURCE.NULL = TRUE;
X.RDB$QUERY_NAME.NULL = TRUE;
X.RDB$EDIT_STRING.NULL = TRUE;
X.RDB$QUERY_HEADER.NULL = TRUE;
X.RDB$MISSING_VALUE.NULL = TRUE;
X.RDB$DEFAULT_VALUE.NULL = TRUE;
X.RDB$VALIDATION_BLR.NULL = TRUE;
X.RDB$VALIDATION_SOURCE.NULL = TRUE;
X.RDB$SYSTEM_FLAG.NULL = TRUE;
X.RDB$NULL_FLAG.NULL = TRUE;
X.RDB$DESCRIPTION.NULL = TRUE;
X.RDB$DIMENSIONS.NULL = TRUE;
X.RDB$EXTERNAL_LENGTH.NULL = TRUE;
X.RDB$EXTERNAL_TYPE.NULL = TRUE;
X.RDB$EXTERNAL_SCALE.NULL = TRUE;
X.RDB$SEGMENT_LENGTH.NULL = TRUE;
X.RDB$CHARACTER_LENGTH.NULL = TRUE;
X.RDB$MISSING_SOURCE.NULL = TRUE;
X.RDB$DEFAULT_SOURCE.NULL = TRUE;
X.RDB$FIELD_SUB_TYPE.NULL = TRUE;
X.RDB$CHARACTER_SET_ID.NULL = TRUE;
X.RDB$COLLATION_ID.NULL = TRUE;
memset (X.RDB$QUERY_NAME, ' ', sizeof(X.RDB$QUERY_NAME));
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_field_name:
l = GET_TEXT(X.RDB$FIELD_NAME);
MISC_terminate (X.RDB$FIELD_NAME, temp, l, sizeof(temp));
BURP_verbose (121, temp, NULL, NULL, NULL, NULL);
// msg 121 restoring global field %s
break;
case att_field_query_name:
GET_TEXT(X.RDB$QUERY_NAME);
X.RDB$QUERY_NAME.NULL = FALSE;
break;
case att_field_edit_string:
GET_TEXT(X.RDB$EDIT_STRING);
X.RDB$EDIT_STRING.NULL = FALSE;
break;
case att_field_query_header:
X.RDB$QUERY_HEADER.NULL = FALSE;
get_source_blob (&X.RDB$QUERY_HEADER, false);
break;
case att_field_type:
X.RDB$FIELD_TYPE = (USHORT) get_numeric();
break;
case att_field_length:
X.RDB$FIELD_LENGTH = (USHORT) get_numeric();
break;
case att_field_scale:
X.RDB$FIELD_SCALE = (USHORT) get_numeric();
X.RDB$FIELD_SCALE.NULL = FALSE;
break;
case att_field_sub_type:
X.RDB$FIELD_SUB_TYPE = (USHORT) get_numeric();
X.RDB$FIELD_SUB_TYPE.NULL = FALSE;
break;
case att_field_segment_length:
X.RDB$SEGMENT_LENGTH = (USHORT) get_numeric();
if (X.RDB$SEGMENT_LENGTH)
X.RDB$SEGMENT_LENGTH.NULL = FALSE;
break;
case att_field_computed_blr:
X.RDB$COMPUTED_BLR.NULL = FALSE;
get_blr_blob (&X.RDB$COMPUTED_BLR, false);
break;
case att_field_computed_source:
X.RDB$COMPUTED_SOURCE.NULL = FALSE;
get_misc_blob (&X.RDB$COMPUTED_SOURCE, 1, false);
break;
case att_field_computed_source2:
X.RDB$COMPUTED_SOURCE.NULL = FALSE;
get_source_blob (&X.RDB$COMPUTED_SOURCE, false);
break;
case att_field_validation_blr:
if (tdgbl->gbl_sw_novalidity)
eat_blob();
else
{
// if we are going against a V4.0 database,
// restore the global fields in 2 phases.
if (tdgbl->global_trans)
{
if (!gfield)
gfield = (GFLD)BURP_alloc_zero(sizeof(gfld));
get_blr_blob (&gfield->gfld_vb, true);
gfield->gfld_flags |= GFLD_validation_blr;
}
else
{
X.RDB$VALIDATION_BLR.NULL = FALSE;
get_blr_blob (&X.RDB$VALIDATION_BLR, false);
}
}
break;
case att_field_validation_source:
if (tdgbl->gbl_sw_novalidity)
eat_blob();
else
{
// if we are going against a V4.0 database,
// restore the global fields in 2 phases.
if (tdgbl->global_trans)
{
if (!gfield)
gfield = (GFLD)BURP_alloc_zero(sizeof(gfld));
get_misc_blob (&gfield->gfld_vs, 0, true);
gfield->gfld_flags |= GFLD_validation_source;
}
else
{
X.RDB$VALIDATION_SOURCE.NULL = FALSE;
get_misc_blob (&X.RDB$VALIDATION_SOURCE, 0, false);
}
}
break;
case att_field_validation_source2:
if (tdgbl->gbl_sw_novalidity)
eat_blob();
else
{
// if we are going against a V4.0 database,
// restore the global fields in 2 phases.
if (tdgbl->global_trans)
{
if (!gfield)
gfield = (GFLD)BURP_alloc_zero(sizeof(gfld));
get_source_blob (&gfield->gfld_vs2, true);
gfield->gfld_flags |= GFLD_validation_source2;
}
else
{
X.RDB$VALIDATION_SOURCE.NULL = FALSE;
get_source_blob (&X.RDB$VALIDATION_SOURCE, false);
}
}
break;
case att_field_missing_value:
X.RDB$MISSING_VALUE.NULL = FALSE;
get_blr_blob (&X.RDB$MISSING_VALUE, false);
break;
case att_field_default_value:
X.RDB$DEFAULT_VALUE.NULL = FALSE;
get_blr_blob (&X.RDB$DEFAULT_VALUE, false);
break;
case att_field_system_flag:
X.RDB$SYSTEM_FLAG = (USHORT) get_numeric();
X.RDB$SYSTEM_FLAG.NULL = FALSE;
break;
case att_field_null_flag:
X.RDB$NULL_FLAG = (USHORT) get_numeric();
X.RDB$NULL_FLAG.NULL = FALSE;
break;
case att_field_description:
X.RDB$DESCRIPTION.NULL = FALSE;
get_misc_blob (&X.RDB$DESCRIPTION, 1, false);
break;
case att_field_description2:
X.RDB$DESCRIPTION.NULL = FALSE;
get_source_blob (&X.RDB$DESCRIPTION, false);
break;
case att_field_external_length:
X.RDB$EXTERNAL_LENGTH.NULL = FALSE;
X.RDB$EXTERNAL_LENGTH = (USHORT) get_numeric();
break;
case att_field_external_scale:
X.RDB$EXTERNAL_SCALE.NULL = FALSE;
X.RDB$EXTERNAL_SCALE = (USHORT) get_numeric();
break;
case att_field_external_type:
X.RDB$EXTERNAL_TYPE.NULL = FALSE;
X.RDB$EXTERNAL_TYPE = (USHORT) get_numeric();
break;
case att_field_dimensions:
X.RDB$DIMENSIONS.NULL = FALSE;
X.RDB$DIMENSIONS = (USHORT) get_numeric();
break;
case att_field_character_length:
X.RDB$CHARACTER_LENGTH.NULL = FALSE;
X.RDB$CHARACTER_LENGTH = (USHORT) get_numeric();
break;
case att_field_default_source:
X.RDB$DEFAULT_SOURCE.NULL = FALSE;
get_source_blob (&X.RDB$DEFAULT_SOURCE, false);
break;
case att_field_missing_source:
X.RDB$MISSING_SOURCE.NULL = FALSE;
get_source_blob (&X.RDB$MISSING_SOURCE, false);
break;
case att_field_character_set:
X.RDB$CHARACTER_SET_ID.NULL = FALSE;
X.RDB$CHARACTER_SET_ID = (USHORT) get_numeric();
break;
case att_field_collation_id:
X.RDB$COLLATION_ID.NULL = FALSE;
X.RDB$COLLATION_ID = (USHORT) get_numeric();
break;
default:
bad_attribute (scan_next_attr, attribute, 92);
// msg 92 global field
break;
}
}
if (X.RDB$FIELD_TYPE <= DTYPE_BLR_MAX)
{
l = gds_cvt_blr_dtype [X.RDB$FIELD_TYPE];
if (l = type_lengths [l])
X.RDB$FIELD_LENGTH = l;
}
if (gfield)
strcpy (gfield->gfld_name, X.RDB$FIELD_NAME);
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
}
if (gfield)
{
gfield->gfld_next = tdgbl->gbl_global_fields;
tdgbl->gbl_global_fields = gfield;
}
return true;
}
2003-09-18 23:56:26 +02:00
bool get_index (BURP_REL relation)
{
/**************************************
*
* g e t _ i n d e x
*
**************************************
*
* Functional description
* Build an index. At the end stop
* and check that all fields are defined.
* If any fields are missing, delete the
* index.
*
**************************************/
BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name;
ATT_TYPE attribute;
bool foreign_index = false;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
SSHORT count = 0, segments = 0;
STORE (REQUEST_HANDLE tdgbl->handles_get_index_req_handle1)
X IN RDB$INDICES
strcpy (X.RDB$RELATION_NAME, relation->rel_name);
X.RDB$UNIQUE_FLAG = 0;
if (!tdgbl->gbl_sw_deactivate_indexes)
X.RDB$INDEX_INACTIVE = FALSE;
else
X.RDB$INDEX_INACTIVE = TRUE;
X.RDB$INDEX_TYPE.NULL = TRUE;
X.RDB$DESCRIPTION.NULL = TRUE;
X.RDB$FOREIGN_KEY.NULL = TRUE;
X.RDB$EXPRESSION_SOURCE.NULL = TRUE;
X.RDB$EXPRESSION_BLR.NULL = TRUE;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_index_name:
GET_TEXT(X.RDB$INDEX_NAME);
strcpy (index_name, X.RDB$INDEX_NAME);
BURP_verbose (122, X.RDB$INDEX_NAME, NULL, NULL, NULL, NULL);
break;
case att_segment_count:
X.RDB$SEGMENT_COUNT = segments = (USHORT) get_numeric();
break;
case att_index_unique_flag:
X.RDB$UNIQUE_FLAG = (USHORT) get_numeric();
break;
case att_index_inactive:
X.RDB$INDEX_INACTIVE = (USHORT) get_numeric();
// Defer foreign key index activation
// Modified by Toni Martir, all index deferred when verbose
if (tdgbl->gbl_sw_verbose)
{
if (X.RDB$INDEX_INACTIVE == FALSE)
X.RDB$INDEX_INACTIVE = DEFERRED_ACTIVE;
}
else
{
if (X.RDB$INDEX_INACTIVE == FALSE && foreign_index)
X.RDB$INDEX_INACTIVE = DEFERRED_ACTIVE;
}
if (tdgbl->gbl_sw_deactivate_indexes)
X.RDB$INDEX_INACTIVE = TRUE;
break;
case att_index_type:
X.RDB$INDEX_TYPE.NULL = FALSE;
X.RDB$INDEX_TYPE = (USHORT) get_numeric();
break;
case att_index_field_name:
STORE (REQUEST_HANDLE tdgbl->handles_get_index_req_handle2)
Y IN RDB$INDEX_SEGMENTS
GET_TEXT(Y.RDB$FIELD_NAME);
strcpy (Y.RDB$INDEX_NAME, X.RDB$INDEX_NAME);
Y.RDB$FIELD_POSITION = count++;
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
break;
case att_index_description:
X.RDB$DESCRIPTION.NULL = FALSE;
get_misc_blob (&X.RDB$DESCRIPTION, 0, false);
break;
case att_index_description2:
X.RDB$DESCRIPTION.NULL = FALSE;
get_source_blob (&X.RDB$DESCRIPTION, false);
break;
case att_index_expression_source:
X.RDB$EXPRESSION_SOURCE.NULL = FALSE;
get_source_blob (&X.RDB$EXPRESSION_SOURCE, false);
break;
case att_index_expression_blr:
X.RDB$EXPRESSION_BLR.NULL = FALSE;
get_blr_blob (&X.RDB$EXPRESSION_BLR, false);
break;
case att_index_foreign_key:
foreign_index = true;
// Defer foreign key index activation
if (X.RDB$INDEX_INACTIVE == FALSE)
X.RDB$INDEX_INACTIVE = DEFERRED_ACTIVE;
if (tdgbl->gbl_sw_deactivate_indexes)
X.RDB$INDEX_INACTIVE = TRUE;
X.RDB$FOREIGN_KEY.NULL = FALSE;
GET_TEXT(X.RDB$FOREIGN_KEY);
break;
default:
bad_attribute (scan_next_attr, attribute, 93);
// msg 93 index
break;
}
}
count = 0;
FOR (REQUEST_HANDLE tdgbl->handles_get_index_req_handle3)
RFR IN RDB$RELATION_FIELDS CROSS I_S IN RDB$INDEX_SEGMENTS
OVER RDB$FIELD_NAME WITH I_S.RDB$INDEX_NAME = index_name AND
RFR.RDB$RELATION_NAME = relation->rel_name
count++;
END_FOR;
ON_ERROR
general_on_error ();
END_ERROR;
if (count != segments)
{
FOR (REQUEST_HANDLE tdgbl->handles_get_index_req_handle4)
I_S IN RDB$INDEX_SEGMENTS WITH I_S.RDB$INDEX_NAME = index_name
ERASE I_S;
ON_ERROR
general_on_error ();
END_ERROR;
END_FOR;
ON_ERROR
general_on_error ();
END_ERROR;
return false;
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
return true;
}
2003-09-18 23:56:26 +02:00
void get_misc_blob (ISC_QUAD *blob_id,
USHORT sub_type,
bool glb_trans)
{
/**************************************
*
* g e t _ m i s c _ b l o b
*
**************************************
*
* Functional description
* Read blob attributes and copy data from input file to nice,
* shiney, new blob.
*
**************************************/
ISC_STATUS_ARRAY status_vector;
UCHAR static_buffer [1024];
isc_tr_handle local_trans;
TGBL tdgbl = GET_THREAD_DATA;
USHORT length = (USHORT)get_numeric();
// Create new blob
FRBRD* blob = NULL;
USHORT bpb_length = 0;
UCHAR* bpb = NULL;
if (glb_trans && tdgbl->global_trans)
local_trans = tdgbl->global_trans;
else
local_trans = gds_trans;
if (isc_create_blob2 (status_vector, &DB, &local_trans, &blob,
blob_id, bpb_length,
reinterpret_cast<const SCHAR*>(bpb)))
{
BURP_error_redirect (status_vector, 37, 0, 0);
// msg 37 gds__create_blob failed
}
// Allocate blob buffer is static buffer is too short
UCHAR* buffer;
if (!length || length <= (USHORT)(sizeof(static_buffer)) )
buffer = static_buffer;
else
2003-09-18 23:56:26 +02:00
buffer = BURP_alloc (length);
if (length)
{
get_block(tdgbl, buffer, length);
}
if (isc_put_segment (status_vector, &blob, length,
reinterpret_cast<const SCHAR*>(buffer)))
{
BURP_error_redirect (status_vector, 38, 0, 0);
// msg 38 gds__put_segment failed
}
if (isc_close_blob (status_vector, &blob))
BURP_error_redirect (status_vector, 23, 0, 0);
// msg 23 gds__close_blob failed
if (buffer != static_buffer)
2003-09-18 23:56:26 +02:00
BURP_free (buffer);
}
SLONG get_numeric (void)
{
/**************************************
*
* g e t _ n u m e r i c
*
**************************************
*
* Functional description
* Get a numeric value from the input stream.
*
**************************************/
2001-12-24 03:51:06 +01:00
SLONG value[2];
// get_text needs additional space for the terminator,
// because it treats everything as strings.
2003-11-04 00:59:24 +01:00
fb_assert(sizeof(value) > sizeof(SLONG));
SSHORT length = get_text((TEXT*) value, sizeof(value));
2001-12-24 03:51:06 +01:00
return isc_vax_integer ((SCHAR *) value, length);
}
SINT64 get_int64 (void)
{
/**************************************
*
* g e t _ i n t 6 4
*
**************************************
*
* Functional description
* Get a possibly-64-bit numeric value from the input stream.
*
**************************************/
2001-12-24 03:51:06 +01:00
SLONG value [4];
// get_text needs additional space for the terminator,
// because it treats everything as strings.
2003-11-04 00:59:24 +01:00
fb_assert (sizeof(value) > sizeof(SINT64));
SSHORT length = get_text ((TEXT *) value, sizeof(value));
2001-12-24 03:51:06 +01:00
return isc_portable_integer ((UCHAR *) value, length);
}
bool get_procedure (void)
{
/**************************************
*
* g e t _ p r o c e d u r e
*
**************************************
*
* Functional description
* Reconstruct a stored procedure.
* Use the global_trans so we don't have to commit
* until after the indices are activated. This
* will allow us to use a PLAN in a SP.
*
**************************************/
ATT_TYPE attribute;
GDS_NAME procedure_name;
TEXT temp [GDS_NAME_LEN];
SSHORT l;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
isc_tr_handle local_trans;
TGBL tdgbl = GET_THREAD_DATA;
local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans;
2003-09-18 23:56:26 +02:00
BURP_PRC procedure = (BURP_PRC) BURP_alloc_zero (sizeof(burp_prc));
procedure->prc_next = tdgbl->procedures;
tdgbl->procedures = procedure;
STORE (TRANSACTION_HANDLE local_trans
REQUEST_HANDLE tdgbl->handles_get_procedure_req_handle1)
X IN RDB$PROCEDURES
X.RDB$PROCEDURE_SOURCE.NULL = TRUE;
X.RDB$DESCRIPTION.NULL = TRUE;
X.RDB$SECURITY_CLASS.NULL = TRUE;
X.RDB$OWNER_NAME.NULL = TRUE;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_procedure_name:
l = GET_TEXT(X.RDB$PROCEDURE_NAME);
procedure->prc_name_length = l;
strcpy (procedure->prc_name, X.RDB$PROCEDURE_NAME);
MISC_terminate (X.RDB$PROCEDURE_NAME, temp, l, sizeof(temp));
BURP_verbose (195, temp, NULL, NULL, NULL, NULL);
// msg 195 restoring stored procedure %s
break;
case att_procedure_description:
get_misc_blob (&X.RDB$DESCRIPTION, 0, true);
X.RDB$DESCRIPTION.NULL = FALSE;
break;
case att_procedure_description2:
get_source_blob (&X.RDB$DESCRIPTION, true);
X.RDB$DESCRIPTION.NULL = FALSE;
break;
case att_procedure_source:
get_misc_blob (&X.RDB$PROCEDURE_SOURCE, 0, true);
X.RDB$PROCEDURE_SOURCE.NULL = FALSE;
break;
case att_procedure_source2:
get_source_blob (&X.RDB$PROCEDURE_SOURCE, true);
X.RDB$PROCEDURE_SOURCE.NULL = FALSE;
break;
case att_procedure_blr:
get_blr_blob (&X.RDB$PROCEDURE_BLR, true);
break;
case att_procedure_security_class:
GET_TEXT(X.RDB$SECURITY_CLASS);
X.RDB$SECURITY_CLASS.NULL = FALSE;
break;
case att_procedure_owner_name:
GET_TEXT(procedure->prc_owner);
break;
case att_procedure_inputs:
X.RDB$PROCEDURE_INPUTS = (USHORT) get_numeric();
if (X.RDB$PROCEDURE_INPUTS == 0)
X.RDB$PROCEDURE_INPUTS.NULL = TRUE;
else
X.RDB$PROCEDURE_INPUTS.NULL = FALSE;
break;
case att_procedure_outputs:
X.RDB$PROCEDURE_OUTPUTS = (USHORT) get_numeric();
break;
default:
bad_attribute (scan_next_attr, attribute, 89);
// msg 89 function
break;
}
}
strcpy (procedure_name, X.RDB$PROCEDURE_NAME);
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
// at the end of prms for a procedure is the rec_procedure_end marker
while (get(tdgbl) == rec_procedure_prm)
get_procedure_prm (procedure_name);
return true;
}
2003-09-18 23:56:26 +02:00
bool get_procedure_prm (GDS_NAME procptr)
{
/**************************************
*
* g e t _ p r o c e d u r e _ p r m
*
**************************************
*
* Functional description
* Reconstruct stored procedure parameter.
* Use the global_trans so we don't have to commit
* until after the indices are activated. This
* will allow us to use a PLAN in a SP.
*
**************************************/
ATT_TYPE attribute;
SSHORT l;
TEXT temp [GDS_NAME_LEN];
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
isc_tr_handle local_trans;
TGBL tdgbl = GET_THREAD_DATA;
local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans;
STORE (TRANSACTION_HANDLE local_trans
REQUEST_HANDLE tdgbl->handles_get_procedure_prm_req_handle1)
X IN RDB$PROCEDURE_PARAMETERS
X.RDB$DESCRIPTION.NULL = TRUE;
strcpy (X.RDB$PROCEDURE_NAME, procptr);
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_procedureprm_name:
l = GET_TEXT(X.RDB$PARAMETER_NAME);
MISC_terminate (X.RDB$PARAMETER_NAME, temp, l, sizeof(temp));
BURP_verbose (196, temp, NULL, NULL, NULL, NULL);
// msg 196 restoring parameter %s for stored procedure
break;
case att_procedureprm_type:
X.RDB$PARAMETER_TYPE= (USHORT) get_numeric();
break;
case att_procedureprm_number:
X.RDB$PARAMETER_NUMBER= (USHORT) get_numeric();
break;
case att_procedureprm_field_source:
GET_TEXT(X.RDB$FIELD_SOURCE);
break;
case att_procedureprm_description:
get_misc_blob (&X.RDB$DESCRIPTION, 0, true);
X.RDB$DESCRIPTION.NULL = FALSE;
break;
case att_procedureprm_description2:
get_source_blob (&X.RDB$DESCRIPTION, true);
X.RDB$DESCRIPTION.NULL = FALSE;
break;
default:
bad_attribute (scan_next_attr, attribute, 90);
// msg 90 function argument
break;
}
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
return true;
}
bool get_ref_constraint (void)
{
/**************************************
*
* g e t _ r e f _ c o n s t r a i n t
*
**************************************
*
* Functional description
* Restore data for referential constraints.
*
**************************************/
ATT_TYPE attribute;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
STORE (REQUEST_HANDLE tdgbl->handles_get_ref_constraint_req_handle1)
X IN RDB$REF_CONSTRAINTS
X.RDB$CONSTRAINT_NAME.NULL = TRUE;
X.RDB$CONST_NAME_UQ.NULL = TRUE;
X.RDB$MATCH_OPTION.NULL = TRUE;
X.RDB$UPDATE_RULE.NULL = TRUE;
X.RDB$DELETE_RULE.NULL = TRUE;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_ref_constraint_name:
X.RDB$CONSTRAINT_NAME.NULL = FALSE;
GET_TEXT(X.RDB$CONSTRAINT_NAME);
break;
case att_ref_unique_const_name:
X.RDB$CONST_NAME_UQ.NULL = FALSE;
GET_TEXT(X.RDB$CONST_NAME_UQ);
break;
case att_ref_match_option:
X.RDB$MATCH_OPTION.NULL = FALSE;
GET_TEXT(X.RDB$MATCH_OPTION);
break;
case att_ref_update_rule:
X.RDB$UPDATE_RULE.NULL = FALSE;
GET_TEXT(X.RDB$UPDATE_RULE);
break;
case att_ref_delete_rule:
X.RDB$DELETE_RULE.NULL = FALSE;
GET_TEXT(X.RDB$DELETE_RULE);
break;
default:
bad_attribute (scan_next_attr, attribute, 208);
// msg 208 relation constraint
break;
}
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
return true;
}
bool get_relation (void)
{
/**************************************
*
* g e t _ r e l a t i o n
*
**************************************
*
* Functional description
* Write relation meta-data and data.
* Use the default transaction for RELATIONS,
* and use the global_trans for VIEWS. This
* enables us to have views of SP and views
* with plans. Assume it is a view if it has
* RDB$VIEW_BLR, also assume RDB$VIEW_BLR is
* the first blob in the backup file.
*
*
**************************************/
TEXT temp [GDS_NAME_LEN];
SSHORT l;
ATT_TYPE attribute;
rec_type record;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
SLONG rel_flags = 0, sys_flag = 0;
bool rel_flags_null = true, sys_flag_null = true;
GDS_QUAD view_blr = isc_blob_null, view_src = isc_blob_null,
rel_desc = isc_blob_null, ext_desc = isc_blob_null;
bool view_blr_null = true, view_src_null = true, rel_desc_null = true,
ext_desc_null = true;
BASED_ON RDB$RELATIONS.RDB$SECURITY_CLASS sec_class;
sec_class[0] = '\0';
bool sec_class_null = true;
BASED_ON RDB$RELATIONS.RDB$EXTERNAL_FILE ext_file_name;
ext_file_name[0] = '\0';
bool ext_file_name_null = true;
isc_tr_handle local_trans;
TGBL tdgbl = GET_THREAD_DATA;
// Pick up relation attributes
2003-09-18 23:56:26 +02:00
BURP_REL relation = (BURP_REL) BURP_alloc_zero (sizeof(burp_rel));
relation->rel_next = tdgbl->relations;
tdgbl->relations = relation;
/*
STORE (REQUEST_HANDLE tdgbl->handles_get_relation_req_handle1)
X IN RDB$RELATIONS
X.RDB$SYSTEM_FLAG.NULL = TRUE;
X.RDB$FLAGS.NULL = TRUE;
X.RDB$SECURITY_CLASS.NULL = TRUE;
X.RDB$VIEW_BLR.NULL = TRUE;
X.RDB$VIEW_SOURCE.NULL = TRUE;
X.RDB$DESCRIPTION.NULL = TRUE;
X.RDB$RUNTIME.NULL = TRUE;
X.RDB$EXTERNAL_DESCRIPTION.NULL = TRUE;
*/
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_relation_name:
l = GET_TEXT(relation->rel_name);
relation->rel_name_length = l;
MISC_terminate (relation->rel_name, temp, l, sizeof(temp));
BURP_verbose (167, temp, NULL, NULL, NULL, NULL);
// msg 167 restoring relation %s
break;
case att_relation_security_class:
sec_class_null = false;
GET_TEXT(sec_class);
break;
2001-12-24 03:51:06 +01:00
case att_relation_view_blr:
view_blr_null = false;
get_blr_blob(&view_blr, true);
relation->rel_flags |= REL_view;
break;
2001-12-24 03:51:06 +01:00
case att_relation_view_source:
view_src_null = false;
get_misc_blob (&view_src, 1, !view_blr_null);
break;
case att_relation_view_source2:
view_src_null = false;
get_source_blob(&view_src, !view_blr_null);
break;
case att_relation_description:
rel_desc_null = false;
get_misc_blob(&rel_desc, 1, !view_blr_null);
break;
case att_relation_description2:
rel_desc_null = false;
get_source_blob(&rel_desc, !view_blr_null);
break;
case att_relation_flags:
rel_flags_null = false;
rel_flags = get_numeric();
break;
case att_relation_system_flag:
sys_flag_null = false;
sys_flag = get_numeric();
break;
case att_relation_ext_description:
ext_desc_null = false;
get_misc_blob(&ext_desc, 1, !view_blr_null);
break;
case att_relation_ext_description2:
ext_desc_null = false;
get_source_blob(&ext_desc, !view_blr_null);
break;
case att_relation_owner_name:
GET_TEXT(relation->rel_owner);
break;
case att_relation_ext_file_name:
ext_file_name_null = false;
GET_TEXT(ext_file_name);
break;
default:
bad_attribute (scan_next_attr, attribute, 111);
// msg 111 relation
break;
}
}
// If this is a view and there is a global transaction then use it
if (view_blr_null || !tdgbl->global_trans)
local_trans = gds_trans;
else
local_trans = tdgbl->global_trans;
STORE (TRANSACTION_HANDLE local_trans
REQUEST_HANDLE tdgbl->handles_get_relation_req_handle1)
X IN RDB$RELATIONS
X.RDB$SYSTEM_FLAG.NULL = sys_flag_null;
X.RDB$FLAGS.NULL = rel_flags_null;
X.RDB$SECURITY_CLASS.NULL = sec_class_null;
X.RDB$VIEW_BLR.NULL = view_blr_null;
X.RDB$VIEW_SOURCE.NULL = view_src_null;
X.RDB$DESCRIPTION.NULL = rel_desc_null;
X.RDB$RUNTIME.NULL = TRUE;
X.RDB$EXTERNAL_DESCRIPTION.NULL = ext_desc_null;
X.RDB$EXTERNAL_FILE.NULL = ext_file_name_null;
X.RDB$SYSTEM_FLAG = (USHORT) sys_flag;
X.RDB$FLAGS = (USHORT) rel_flags;
X.RDB$VIEW_BLR = view_blr;
X.RDB$VIEW_SOURCE = view_src;
X.RDB$DESCRIPTION = rel_desc;
X.RDB$EXTERNAL_DESCRIPTION = ext_desc;
strcpy(X.RDB$SECURITY_CLASS, sec_class);
strcpy(X.RDB$RELATION_NAME, relation->rel_name);
strcpy(X.RDB$EXTERNAL_FILE, ext_file_name);
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
// Eat up misc. records
BURP_FLD field = NULL;
BURP_FLD *ptr = &relation->rel_fields;
2003-09-21 01:28:38 +02:00
while (get_record(&record, tdgbl) != rec_data)
{
switch (record)
{
case rec_relation_end:
if (tdgbl->gbl_sw_incremental)
{
BURP_verbose (170, relation->rel_name, NULL, NULL, NULL, NULL);
// msg 170: committing metadata for relation %s
COMMIT
// existing ON_ERROR continues past error, beck
ON_ERROR
BURP_print (171, relation->rel_name, NULL, NULL, NULL, NULL);
// msg 171: error committing metadata for relation %s
BURP_print_status (tdgbl->status_vector);
ROLLBACK;
ON_ERROR
general_on_error ();
END_ERROR;
END_ERROR;
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
if (gds_status [1])
EXEC SQL SET TRANSACTION;
}
return true;
case rec_field:
*ptr = field = get_field (relation);
if (!field)
return false;
ptr = &field->fld_next;
break;
case rec_view:
get_view (relation);
break;
default:
BURP_error(43, true, isc_arg_number, (void*) record,
0, NULL, 0, NULL, 0, NULL, 0, NULL);
// msg 43 don't recognize record type %ld
break;
}
}
// If we fall thru, there are data records to be gotten
/* we can get here only when restoring ancient gbak'ed files where rec_data
was once embedded into rec_relation ... otherwise, meta commit happens
when we see the first rec_relation_data */
BURP_verbose (68, NULL, NULL, NULL, NULL, NULL);
// msg 68 committing meta data
COMMIT;
ON_ERROR
general_on_error ();
END_ERROR;
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
if (gds_status [1])
EXEC SQL SET TRANSACTION;
get_data (relation);
return true;
}
bool get_rel_constraint (void)
{
/**************************************
*
* g e t _ r e l _ c o n s t r a i n t
*
**************************************
*
* Functional description
* Restore data for relation constraints.
*
**************************************/
2003-09-18 23:56:26 +02:00
ATT_TYPE attribute;
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
STORE (REQUEST_HANDLE tdgbl->handles_get_rel_constraint_req_handle1)
X IN RDB$RELATION_CONSTRAINTS
X.RDB$CONSTRAINT_NAME.NULL = TRUE;
X.RDB$CONSTRAINT_TYPE.NULL = TRUE;
X.RDB$RELATION_NAME.NULL = TRUE;
X.RDB$DEFERRABLE.NULL = TRUE;
X.RDB$INITIALLY_DEFERRED.NULL = TRUE;
X.RDB$INDEX_NAME.NULL = TRUE;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_rel_constraint_name:
X.RDB$CONSTRAINT_NAME.NULL = FALSE;
GET_TEXT(X.RDB$CONSTRAINT_NAME);
break;
case att_rel_constraint_type:
X.RDB$CONSTRAINT_TYPE.NULL = FALSE;
GET_TEXT(X.RDB$CONSTRAINT_TYPE);
break;
case att_rel_constraint_rel_name:
X.RDB$RELATION_NAME.NULL = FALSE;
GET_TEXT(X.RDB$RELATION_NAME);
break;
case att_rel_constraint_defer:
X.RDB$DEFERRABLE.NULL = FALSE;
GET_TEXT(X.RDB$DEFERRABLE);
break;
case att_rel_constraint_init:
X.RDB$INITIALLY_DEFERRED.NULL = FALSE;
GET_TEXT(X.RDB$INITIALLY_DEFERRED);
break;
case att_rel_constraint_index:
X.RDB$INDEX_NAME.NULL = FALSE;
GET_TEXT(X.RDB$INDEX_NAME);
break;
default:
bad_attribute (scan_next_attr, attribute, 208);
// msg 208 relation constraint
break;
}
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
return true;
}
bool get_relation_data (void)
{
/**************************************
*
* g e t _ r e l a t i o n _ d a t a
*
**************************************
*
* Functional description
* Restore data for a relation. This is called when the data is
* standing free from the relation definition. We first need to
* find the relation named. If we can't find it, give up.
*
**************************************/
BURP_REL relation;
BASED_ON RDB$RELATIONS.RDB$RELATION_NAME name;
SLONG gen_id;
ATT_TYPE attribute;
rec_type record;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
relation = NULL;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_relation_name:
GET_TEXT(name);
relation = find_relation (name);
break;
default:
bad_attribute (scan_next_attr, attribute, 111);
// msg 111 relation
break;
}
}
if (!relation)
BURP_error_redirect (NULL, 49, 0, 0);
// msg 49 no relation name for data
// Eat up misc. records
2003-09-21 01:28:38 +02:00
get_record(&record, tdgbl);
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), true)
{
switch (record)
{
case rec_relation_end:
return true;
case rec_data:
record = get_data (relation);
// get_data does a GET_RECORD
break;
case rec_gen_id:
gen_id = get_numeric();
store_blr_gen_id (name, gen_id);
2003-09-21 01:28:38 +02:00
get_record(&record, tdgbl);
break;
case rec_index:
get_index (relation);
2003-09-21 01:28:38 +02:00
get_record(&record, tdgbl);
break;
case rec_trigger: // old style trigger
get_trigger_old (relation);
2003-09-21 01:28:38 +02:00
get_record(&record, tdgbl);
break;
default:
bad_attribute (scan_next_attr, attribute, 111);
// msg 111 relation
2003-09-21 01:28:38 +02:00
get_record(&record, tdgbl);
break;
}
}
}
bool get_sql_roles (void)
{
/**************************************
*
* g e t _ s q l _ r o l e s
*
**************************************
*
* Functional description
* Restore data for SQL roles
*
**************************************/
ATT_TYPE attribute;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
TEXT temp [GDS_NAME_LEN];
SSHORT l;
TGBL tdgbl = GET_THREAD_DATA;
STORE (REQUEST_HANDLE tdgbl->handles_get_sql_roles_req_handle1)
X IN RDB$ROLES
X.RDB$ROLE_NAME.NULL = TRUE;
X.RDB$OWNER_NAME.NULL = TRUE;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_role_name:
X.RDB$ROLE_NAME.NULL = FALSE;
l = GET_TEXT(X.RDB$ROLE_NAME);
MISC_terminate (X.RDB$ROLE_NAME, temp, l, sizeof(temp));
/************************************************
**
** msg 251, restoring SQL role: %s
**
*************************************************/
BURP_verbose (251, temp, NULL, NULL, NULL, NULL);
break;
case att_role_owner_name:
X.RDB$OWNER_NAME.NULL = FALSE;
GET_TEXT(X.RDB$OWNER_NAME);
break;
default:
/*************************************************
**
** msg 250, Bad attribute for restoring SQL role
**
**************************************************/
bad_attribute (scan_next_attr, attribute, 250);
break;
}
}
END_STORE
ON_ERROR
general_on_error ();
END_ERROR;
return true;
}
bool is_ascii_name (const TEXT *name, const SSHORT len)
{
/**************************************
*
* i s _ a s c i i _ n a m e
*
**************************************
*
* Functional description
* Check if the input text is valid ASCII name
*
**************************************/
SSHORT i = 0;
2003-09-15 03:50:15 +02:00
while (i < len &&
( (name[i] >= 'A' && name[i] <= 'Z') ||
(name[i] >= '0' && name[i] <= '9') ||
name[i] == '_' || name[i] == '$' ) )
{
++i;
}
return (i == len);
}
bool get_security_class (void)
{
/**************************************
*
* g e t _ s e c u r i t y _ c l a s s
*
**************************************
*
* Functional description
* Restore a security class record including access control list.
*
**************************************/
ATT_TYPE attribute;
TEXT temp [GDS_NAME_LEN];
SSHORT l = 0;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
bool is_valid_sec_class = false;
TGBL tdgbl = GET_THREAD_DATA;
STORE (REQUEST_HANDLE tdgbl->handles_get_security_class_req_handle1)
X IN RDB$SECURITY_CLASSES
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
X.RDB$DESCRIPTION.NULL = TRUE;
switch (attribute)
{
case att_class_security_class:
l = GET_TEXT(X.RDB$SECURITY_CLASS);
/* Bug fix for bug_no 7299: There was a V3 bug that inserted
garbage security class entry when doing GBAK. In order to
restore the V3 gbak file with this bad security entry to
V4 database. We should check if the security class is a
valid ASCII name. If not, skip this entry by setting
'is_valid_sec_class' to false.
*/
is_valid_sec_class = is_ascii_name(X.RDB$SECURITY_CLASS, l);
if (!is_valid_sec_class)
{
MISC_terminate (X.RDB$SECURITY_CLASS, temp, l, sizeof(temp));
BURP_print (234, temp, NULL, NULL, NULL, NULL);
// msg 234 Skipped bad security class entry: %s
break;
}
MISC_terminate (X.RDB$SECURITY_CLASS, temp, l, sizeof(temp));
BURP_verbose (125, temp, NULL, NULL, NULL, NULL);
// msg 125 restoring security class %s
break;
case att_class_acl:
get_misc_blob (&X.RDB$ACL, 0, false);
break;
case att_class_description:
X.RDB$DESCRIPTION.NULL = FALSE;
get_misc_blob (&X.RDB$DESCRIPTION, 0, false);
break;
case att_class_description2:
X.RDB$DESCRIPTION.NULL = FALSE;
get_source_blob (&X.RDB$DESCRIPTION, false);
break;
default:
bad_attribute (scan_next_attr, attribute, 131);
// msg 131 security class
break;
}
}
// If the security class is not valid ASCII name, don't store it to the
// database. Simply return from here and the entry is discarded.
if (!is_valid_sec_class)
{
return true;
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
return true;
}
void get_source_blob (
ISC_QUAD *blob_id,
bool glb_trans)
{
/**************************************
*
* g e t _ s o u r c e _ b l o b
*
**************************************
*
* Functional description
* Read source blob and query header attributes and copy data from
* input file to nice, shiney, new blob.
*
**************************************/
ISC_STATUS_ARRAY status_vector;
UCHAR static_buffer [1024];
isc_tr_handle local_trans;
TGBL tdgbl = GET_THREAD_DATA;
SLONG length = get_numeric();
// Create new blob
FRBRD *blob = NULL;
if (glb_trans && tdgbl->global_trans)
local_trans = tdgbl->global_trans;
else
local_trans = gds_trans;
2003-09-23 21:47:50 +02:00
if (isc_create_blob (status_vector, &DB, &local_trans, &blob, blob_id))
{
BURP_error_redirect (status_vector, 37, 0, 0);
// msg 37 gds__create_blob failed
}
// Allocate blob buffer is static buffer is too short
UCHAR* buffer;
if (!length || length <= (USHORT)(sizeof(static_buffer)) )
buffer = static_buffer;
else
2003-09-18 23:56:26 +02:00
buffer = BURP_alloc (length);
while (length)
{
UCHAR* p = buffer;
while (*p++ = get(tdgbl))
length--;
--p;
--length;
USHORT seg_len = p - buffer;
if (isc_put_segment (status_vector, &blob, seg_len,
reinterpret_cast<const SCHAR*>(buffer)))
{
BURP_error_redirect (status_vector, 38, 0, 0);
// msg 38 gds__put_segment failed
}
}
if (isc_close_blob (status_vector, &blob))
BURP_error_redirect (status_vector, 23, 0, 0);
// msg 23 gds__close_blob failed
if (buffer != static_buffer)
2003-09-18 23:56:26 +02:00
BURP_free (buffer);
}
USHORT get_text (
TEXT *text,
ULONG length)
{
/**************************************
*
* g e t _ t e x t
*
**************************************
*
* Functional description
* Move a text attribute to a string and fill.
*
**************************************/
TGBL tdgbl = GET_THREAD_DATA;
ULONG l = get(tdgbl);
if (length <= l)
BURP_error_redirect (NULL, 46, 0, 0);
// msg 46 string truncated
if (l)
text = (TEXT*) get_block(tdgbl, (UCHAR*) text, l);
*text = 0;
return (USHORT) l;
}
bool get_trigger_old (
BURP_REL relation)
{
/**************************************
*
* g e t _ t r i g g e r _ o l d
*
**************************************
*
* Functional description
* Get a trigger definition for a relation.
*
**************************************/
enum trig_t type;
ATT_TYPE attribute;
TEXT *q, *p, *end, name [GDS_NAME_LEN];
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
STORE (REQUEST_HANDLE tdgbl->handles_get_trigger_old_req_handle1)
X IN RDB$TRIGGERS
X.RDB$DESCRIPTION.NULL = TRUE;
X.RDB$TRIGGER_BLR.NULL = TRUE;
X.RDB$TRIGGER_SOURCE.NULL = TRUE;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_trig_type:
type = (enum trig_t) get_numeric();
break;
case att_trig_blr:
X.RDB$TRIGGER_BLR.NULL = FALSE;
get_blr_blob (&X.RDB$TRIGGER_BLR, false);
break;
case att_trig_source:
X.RDB$TRIGGER_SOURCE.NULL = FALSE;
get_misc_blob (&X.RDB$TRIGGER_SOURCE, 1, false);
break;
case att_trig_source2:
X.RDB$TRIGGER_SOURCE.NULL = FALSE;
get_source_blob (&X.RDB$TRIGGER_SOURCE, false);
break;
default:
bad_attribute (scan_next_attr, attribute, 134);
// msg 134 trigger
break;
}
}
// fill in rest of attributes unique to new trigger format
p = X.RDB$TRIGGER_NAME;
end = p + 31;
q = relation->rel_name;
while (*q)
*p++ = *q++;
if (type == trig_pre_store)
{
X.RDB$TRIGGER_TYPE = TRIG_TYPE_PRE_STORE;
q = "$STORE";
}
else if (type == trig_pre_modify)
{
X.RDB$TRIGGER_TYPE = TRIG_TYPE_PRE_MODIFY;
q = "$MODIFY";
}
else if (type == trig_post_erase)
{
X.RDB$TRIGGER_TYPE = TRIG_TYPE_POST_ERASE;
q = "$ERASE";
}
else
{
bad_attribute (scan_next_attr, attribute, 136);
// msg 136 trigger type
return 0;
}
while (*q && p < end)
*p++ = *q++;
*p = 0;
BURP_verbose (126, X.RDB$TRIGGER_NAME, NULL, NULL, NULL, NULL);
// msg 126 restoring trigger %s
strncpy (X.RDB$RELATION_NAME, relation->rel_name, GDS_NAME_LEN);
strcpy (name, X.RDB$TRIGGER_NAME);
X.RDB$TRIGGER_SEQUENCE = TRIGGER_SEQUENCE_DEFAULT;
X.RDB$SYSTEM_FLAG = 0; // restore as vanilla user type
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
if (tdgbl->gbl_sw_incremental)
{
COMMIT
// existing ON_ERROR continues past error, beck
ON_ERROR
BURP_print (94, name, NULL, NULL, NULL, NULL);
// msg 94 trigger %s is invalid
BURP_print_status (tdgbl->status_vector);
ROLLBACK;
ON_ERROR
general_on_error ();
END_ERROR;
END_ERROR;
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
if (gds_status [1])
EXEC SQL SET TRANSACTION;
}
return true;
}
bool get_trigger (void)
{
/**************************************
*
* g e t _ t r i g g e r
*
**************************************
*
* Functional description
* Get a trigger definition in rdb$triggers.
*
**************************************/
ATT_TYPE attribute;
BASED_ON RDB$TRIGGERS.RDB$TRIGGER_NAME name;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
isc_tr_handle local_trans;
TGBL tdgbl = GET_THREAD_DATA;
local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans;
STORE (TRANSACTION_HANDLE local_trans
REQUEST_HANDLE tdgbl->handles_get_trigger_req_handle1)
X IN RDB$TRIGGERS
X.RDB$DESCRIPTION.NULL = TRUE;
X.RDB$TRIGGER_BLR.NULL = TRUE;
X.RDB$TRIGGER_SOURCE.NULL = TRUE;
X.RDB$SYSTEM_FLAG.NULL = TRUE;
X.RDB$FLAGS.NULL = TRUE;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_trig_type:
X.RDB$TRIGGER_TYPE = (USHORT) get_numeric();
break;
case att_trig_flags:
X.RDB$FLAGS = (USHORT) get_numeric();
X.RDB$FLAGS.NULL = FALSE;
break;
case att_trig_blr:
X.RDB$TRIGGER_BLR.NULL = FALSE;
get_blr_blob (&X.RDB$TRIGGER_BLR, true);
break;
case att_trig_source:
X.RDB$TRIGGER_SOURCE.NULL = FALSE;
get_misc_blob (&X.RDB$TRIGGER_SOURCE, 1, true);
break;
case att_trig_source2:
X.RDB$TRIGGER_SOURCE.NULL = FALSE;
get_source_blob (&X.RDB$TRIGGER_SOURCE, true);
break;
case att_trig_name:
GET_TEXT(X.RDB$TRIGGER_NAME);
strcpy (name, X.RDB$TRIGGER_NAME);
BURP_verbose (126, X.RDB$TRIGGER_NAME, NULL, NULL, NULL, NULL);
// msg 126 restoring trigger %s
break;
case att_trig_relation_name:
GET_TEXT(X.RDB$RELATION_NAME);
break;
case att_trig_sequence:
X.RDB$TRIGGER_SEQUENCE = (USHORT) get_numeric();
break;
case att_trig_description:
X.RDB$DESCRIPTION.NULL = FALSE;
get_misc_blob (&X.RDB$DESCRIPTION, 1, true);
break;
case att_trig_description2:
X.RDB$DESCRIPTION.NULL = FALSE;
get_source_blob (&X.RDB$DESCRIPTION, true);
break;
case att_trig_system_flag:
X.RDB$SYSTEM_FLAG = (USHORT) get_numeric();
X.RDB$SYSTEM_FLAG.NULL = FALSE;
break;
case att_trig_inactive:
X.RDB$TRIGGER_INACTIVE = (USHORT) get_numeric();
break;
default:
bad_attribute (scan_next_attr, attribute, 134);
// msg 134 trigger
break;
}
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
if (tdgbl->gbl_sw_incremental)
{
COMMIT
// existing ON_ERROR continues past error, beck
ON_ERROR
BURP_print (94, name, NULL, NULL, NULL, NULL);
// msg 94 trigger %s is invalid
BURP_print_status (tdgbl->status_vector);
ROLLBACK;
ON_ERROR
general_on_error ();
END_ERROR;
END_ERROR;
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
if (gds_status [1])
EXEC SQL SET TRANSACTION;
}
return true;
}
bool get_trigger_message (void)
{
/**************************************
*
* g e t _ t r i g g e r _ m e s s a g e
*
**************************************
*
* Functional description
* Get a trigger message text.
*
**************************************/
ATT_TYPE attribute;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
isc_tr_handle local_trans;
BASED_ON RDB$TRIGGER_MESSAGES.RDB$TRIGGER_NAME name;
BASED_ON RDB$TRIGGER_MESSAGES.RDB$MESSAGE_NUMBER number;
BASED_ON RDB$TRIGGER_MESSAGES.RDB$MESSAGE message;
TGBL tdgbl = GET_THREAD_DATA;
bool flag = false;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_trigmsg_name:
GET_TEXT(name);
flag = false;
FOR (REQUEST_HANDLE tdgbl->handles_get_trigger_message_req_handle1)
FIRST 1 X IN RDB$TRIGGERS WITH
X.RDB$SYSTEM_FLAG EQ 1 AND X.RDB$TRIGGER_NAME EQ name
flag = true;
END_FOR;
ON_ERROR
general_on_error ();
END_ERROR;
BURP_verbose (127, name, NULL, NULL, NULL, NULL);
// msg 127 restoring trigger message for %s
break;
case att_trigmsg_number:
number = (USHORT) get_numeric();
break;
case att_trigmsg_text:
GET_TEXT(message);
break;
default:
bad_attribute (scan_next_attr, attribute, 135);
// msg 135 trigger message
break;
}
}
if (flag)
return true;
local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans;
STORE (TRANSACTION_HANDLE local_trans
REQUEST_HANDLE tdgbl->handles_get_trigger_message_req_handle2)
X IN RDB$TRIGGER_MESSAGES
strcpy (X.RDB$TRIGGER_NAME, name);
X.RDB$MESSAGE_NUMBER = number;
strcpy (X.RDB$MESSAGE, message);
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
if (tdgbl->gbl_sw_incremental)
{
COMMIT
// existing ON_ERROR continues past error, beck
ON_ERROR
BURP_print (94, name, NULL, NULL, NULL, NULL);
// msg 94 trigger %s is invalid
BURP_print_status (tdgbl->status_vector);
ROLLBACK;
ON_ERROR
general_on_error ();
END_ERROR;
END_ERROR;
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
if (gds_status [1])
EXEC SQL SET TRANSACTION;
}
return true;
}
bool get_type (void)
{
/**************************************
*
* g e t _ t y p e
*
**************************************
*
* Functional description
* Get a type definition in rdb$types.
*
**************************************/
ATT_TYPE attribute;
ULONG l;
TEXT temp [GDS_NAME_LEN];
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
STORE (REQUEST_HANDLE tdgbl->handles_get_type_req_handle1)
X IN RDB$TYPES
X.RDB$DESCRIPTION.NULL = TRUE;
X.RDB$SYSTEM_FLAG.NULL = TRUE;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_type_name:
l = GET_TEXT(X.RDB$TYPE_NAME);
break;
case att_type_type:
X.RDB$TYPE = (USHORT) get_numeric();
break;
case att_type_field_name:
GET_TEXT(X.RDB$FIELD_NAME);
break;
case att_type_description:
X.RDB$DESCRIPTION.NULL = FALSE;
get_misc_blob (&X.RDB$DESCRIPTION, 1, false);
break;
case att_type_description2:
X.RDB$DESCRIPTION.NULL = FALSE;
get_source_blob (&X.RDB$DESCRIPTION, false);
break;
case att_type_system_flag:
X.RDB$SYSTEM_FLAG = (USHORT) get_numeric();
X.RDB$SYSTEM_FLAG.NULL = FALSE;
break;
default:
bad_attribute (scan_next_attr, attribute, 136);
// msg 136 trigger type
break;
}
}
MISC_terminate (X.RDB$TYPE_NAME, temp, l, sizeof(temp));
BURP_verbose (128, temp, X.RDB$FIELD_NAME, NULL, NULL, NULL);
// msg 128 restoring type %s for field %s
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
return true;
}
bool get_user_privilege (void)
{
/**************************************
*
* g e t _ u s e r _ p r i v i l e g e
*
**************************************
*
* Functional description
* Get a user privilege.
* Get next interesting user privilege.
*
**************************************/
ATT_TYPE attribute;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
USHORT flags = 0;
isc_tr_handle local_trans = NULL;
BASED_ON RDB$USER_PRIVILEGES.RDB$USER user;
BASED_ON RDB$USER_PRIVILEGES.RDB$GRANTOR grantor;
BASED_ON RDB$USER_PRIVILEGES.RDB$PRIVILEGE privilege;
BASED_ON RDB$USER_PRIVILEGES.RDB$GRANT_OPTION grant_option;
BASED_ON RDB$USER_PRIVILEGES.RDB$RELATION_NAME relation_name;
BASED_ON RDB$USER_PRIVILEGES.RDB$FIELD_NAME field_name;
BASED_ON RDB$USER_PRIVILEGES.RDB$USER_TYPE user_type;
BASED_ON RDB$USER_PRIVILEGES.RDB$OBJECT_TYPE object_type;
TGBL tdgbl = GET_THREAD_DATA;
user_type = obj_user;
object_type = obj_relation;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_priv_user:
// default USER_TYPE to USER
flags |= USER_PRIV_USER;
GET_TEXT(user);
BURP_verbose (123, user, NULL, NULL, NULL, NULL);
// msg 123 restoring privilege for user %s
break;
case att_priv_grantor:
flags |= USER_PRIV_GRANTOR;
GET_TEXT(grantor);
break;
case att_priv_privilege:
flags |= USER_PRIV_PRIVILEGE;
GET_TEXT(privilege);
break;
case att_priv_grant_option:
flags |= USER_PRIV_GRANT_OPTION;
grant_option = (USHORT) get_numeric();
break;
case att_priv_object_name:
flags |= USER_PRIV_OBJECT_NAME;
// default OBJECT_TYPE to RELATION
GET_TEXT(relation_name);
break;
case att_priv_field_name:
flags |= USER_PRIV_FIELD_NAME;
GET_TEXT(field_name);
break;
case att_priv_user_type:
flags |= USER_PRIV_USER_TYPE;
user_type = (USHORT) get_numeric();
break;
case att_priv_obj_type:
flags |= USER_PRIV_OBJECT_TYPE;
object_type = (USHORT) get_numeric();
break;
default:
bad_attribute (scan_next_attr, attribute, 105);
// msg 105 privilege
break;
}
}
// Check if object exists
bool exists = false;
switch (object_type)
{
case obj_procedure:
{
for (BURP_PRC proc = tdgbl->procedures; proc; proc = proc->prc_next)
if (!strcmp(proc->prc_name, relation_name))
{
exists = true;
local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans;
break;
}
}
break;
case obj_relation:
{
for (BURP_REL rel = tdgbl->relations; rel; rel = rel->rel_next)
if (!strcmp(rel->rel_name, relation_name))
{
exists = true;
if (rel->rel_flags & REL_view)
local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans;
break;
}
}
break;
default:
exists = true;
break;
}
if (exists)
{
if (!local_trans)
local_trans = gds_trans;
STORE (TRANSACTION_HANDLE local_trans
REQUEST_HANDLE tdgbl->handles_get_user_privilege_req_handle1) X
IN RDB$USER_PRIVILEGES
X.RDB$FIELD_NAME.NULL = TRUE;
X.RDB$OBJECT_TYPE.NULL = TRUE;
if (flags & USER_PRIV_USER)
strcpy (X.RDB$USER, user);
if (flags & USER_PRIV_GRANTOR)
strcpy (X.RDB$GRANTOR, grantor);
if (flags & USER_PRIV_PRIVILEGE)
strcpy (X.RDB$PRIVILEGE, privilege);
if (flags & USER_PRIV_GRANT_OPTION)
{
X.RDB$GRANT_OPTION = grant_option;
if (grant_option == 0)
X.RDB$GRANT_OPTION.NULL = TRUE;
else
X.RDB$GRANT_OPTION.NULL = FALSE;
}
if (flags & USER_PRIV_OBJECT_NAME)
strcpy (X.RDB$RELATION_NAME, relation_name);
if (flags & USER_PRIV_FIELD_NAME)
{
X.RDB$FIELD_NAME.NULL = FALSE;
strcpy (X.RDB$FIELD_NAME, field_name);
}
/*
* USER_TYPE & OBJECT_TYPE are fields that did not exist before
* V4.0. So, we have to reconstruct them and initialize them to
* reasonable values. If they existed before then user_type and
* object_type contain the proper values. If they didn't exist
* then user_type and object_type contain the reasonable default
* values.
*/
X.RDB$USER_TYPE.NULL = FALSE;
X.RDB$USER_TYPE = user_type;
X.RDB$OBJECT_TYPE.NULL = FALSE;
X.RDB$OBJECT_TYPE = object_type;
/*
* If OBJECT_TYPE didn't exist before and we have a field level
* user privileges, then use obj_field instead.
*
* NOTE: Scanning the V4.0 code base, obj_field has never been
* used at all. The following code should be uncommented
* in case we ever introduce obj_field to the picture.
*/
/***********************************************************
if ( !(flags & USER_PRIV_OBJECT_TYPE) )
{
if ( flags & USER_PRIV_FIELD_NAME )
{
X.RDB$OBJECT_TYPE = obj_field;
}
}
***********************************************************/
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
}
return true;
}
2003-09-18 23:56:26 +02:00
bool get_view (BURP_REL relation)
{
/**************************************
*
* g e t _ v i e w
*
**************************************
*
* Functional description
* Store a record in RDB$VIEW_RELATIONS.
*
**************************************/
ATT_TYPE attribute;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
isc_tr_handle local_trans;
TGBL tdgbl = GET_THREAD_DATA;
// If there is a global transaction then use it
local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans;
STORE (TRANSACTION_HANDLE local_trans
REQUEST_HANDLE tdgbl->handles_get_view_req_handle1)
X IN RDB$VIEW_RELATIONS
strcpy (X.RDB$VIEW_NAME, relation->rel_name);
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_view_relation_name:
GET_TEXT(X.RDB$RELATION_NAME);
break;
case att_view_context_name:
GET_TEXT(X.RDB$CONTEXT_NAME);
break;
case att_view_context_id:
X.RDB$VIEW_CONTEXT = (USHORT) get_numeric();
break;
default:
bad_attribute (scan_next_attr, attribute, 140);
// msg 140 view
break;
}
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
return true;
}
2003-09-18 23:56:26 +02:00
void ignore_array (BURP_REL relation)
{
/**************************************
*
* i g n o r e _ a r r a y
*
**************************************
*
* Functional description
* Read array data from input file to nice,
* shiney, new array.
*
**************************************/
BURP_FLD field;
ATT_TYPE attribute;
SLONG length, lcount, *range, *end_ranges;
USHORT field_number;
LSTRING xdr_buffer;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
// don't free something you don't allocate
xdr_buffer.lstr_allocated = 0;
// Pick up attributes
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_blob_data)
{
switch (attribute)
{
case att_blob_field_number:
field_number = (USHORT) get_numeric();
for (field = relation->rel_fields; field; field = field->fld_next)
if (field->fld_number == field_number)
break;
if (!field)
BURP_error_redirect (NULL, 36, 0, 0);
// msg 36 Can't find field for blob
break;
case att_array_dimensions:
field->fld_dimensions = (SSHORT)get_numeric();
end_ranges = field->fld_ranges + 2 * field->fld_dimensions;
for (range = field->fld_ranges; range < end_ranges; range += 2)
{
2003-09-21 01:28:38 +02:00
if (get_attribute(&attribute, tdgbl) != att_array_range_low)
bad_attribute (scan_next_attr, attribute, 58);
// msg 58 array
else
range [0] = get_numeric();
2003-09-21 01:28:38 +02:00
if (get_attribute(&attribute, tdgbl) != att_array_range_high)
bad_attribute (scan_next_attr, attribute, 58);
// msg 58 array
else
range [1] = get_numeric();
}
break;
default:
bad_attribute (scan_next_attr, attribute, 58);
// msg 58 array
break;
}
}
length = get(tdgbl);
length |= get(tdgbl) << 8;
length |= get(tdgbl) << 16;
length |= get(tdgbl) << 24;
if (tdgbl->gbl_sw_transportable)
{
2003-09-21 01:28:38 +02:00
if (get_attribute(&attribute, tdgbl) != att_xdr_array)
BURP_error_redirect (NULL, 55, 0, 0);
// msg 55 Expected XDR record length
else
{
xdr_buffer.lstr_allocated = get(tdgbl);
xdr_buffer.lstr_allocated |= get(tdgbl) << 8;
xdr_buffer.lstr_allocated |= get(tdgbl) << 16;
xdr_buffer.lstr_allocated |= get(tdgbl) << 24;
lcount = xdr_buffer.lstr_length = xdr_buffer.lstr_allocated;
}
}
else
{
lcount = length;
}
if (lcount)
get_skip(tdgbl, lcount);
}
void ignore_blob (void)
{
/**************************************
*
* i g n o r e _ b l o b
*
**************************************
*
* Functional description
* Skip over blob data records.
*
**************************************/
ATT_TYPE attribute;
SLONG segments;
USHORT length;
2003-09-18 23:56:26 +02:00
scan_attr_t scan_next_attr;
TGBL tdgbl = GET_THREAD_DATA;
// Pick up attributes
segments = 0;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_blob_data)
{
switch (attribute)
{
case att_blob_field_number:
get_numeric();
break;
case att_blob_max_segment:
get_numeric();
break;
case att_blob_number_segments:
segments = get_numeric();
break;
case att_blob_type:
get_numeric();
break;
default:
bad_attribute (scan_next_attr, attribute, 64);
// msg 64 blob
break;
}
}
// Eat up blob segments
while (--segments >= 0)
{
length = get(tdgbl);
length |= get(tdgbl) << 8;
if (length)
get_skip(tdgbl, length);
}
}
2003-09-18 23:56:26 +02:00
rec_type ignore_data (BURP_REL relation)
{
/**************************************
*
* i g n o r e _ d a t a
*
**************************************
*
* Functional description
* Ignore data records for a relation.
*
**************************************/
rec_type record;
TGBL tdgbl = GET_THREAD_DATA;
ULONG records = 0;
while (true)
{
if (get(tdgbl) != att_data_length)
BURP_error_redirect (NULL, 39, 0, 0);
// msg 39 expected record length
USHORT l = (USHORT) get_numeric();
if (tdgbl->gbl_sw_transportable)
{
if (get(tdgbl) != att_xdr_length)
BURP_error_redirect (NULL, 55, 0, 0);
// msg 55 Expected XDR record length
else
l = (USHORT) get_numeric();
}
if (get(tdgbl) != att_data_data)
BURP_error_redirect (NULL, 41, 0, 0);
// msg 41 expected data attribute
2003-09-15 03:50:15 +02:00
if (l) {
if (tdgbl->gbl_sw_compress)
{
2003-09-18 23:56:26 +02:00
UCHAR *buffer = (UCHAR*) BURP_alloc (l);
decompress (buffer, l);
2003-09-18 23:56:26 +02:00
BURP_free (buffer);
}
else
get_skip(tdgbl, l);
}
records++;
2003-09-21 01:28:38 +02:00
while (get_record(&record, tdgbl))
{
if (record == rec_blob)
ignore_blob();
else if (record == rec_array)
ignore_array (relation);
else
break;
}
if (record != rec_data)
break;
}
BURP_verbose (106, (void*) records, NULL, NULL, NULL, NULL);
// msg 106 %ld records ignored
return record;
}
2003-09-18 23:56:26 +02:00
void realign (UCHAR *buffer,
BURP_REL relation)
{
/**************************************
*
* r e a l i g n
*
**************************************
*
* Functional description
* Miserable input record is misaligned.
* Shuffle fields around. N.B. this one
* only works if the old buffer is longer
* than the new.
*
**************************************/
BURP_FLD field;
UCHAR *p, *q;
USHORT l;
TGBL tdgbl = GET_THREAD_DATA;
for (field = relation->rel_fields; field; field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
continue;
p = buffer + field->fld_offset;
q = buffer + field->fld_old_offset;
l = field->fld_length;
// CVC: This code assumes fld_offset < fld_old_offset,
// why not use memmove() instead?
// Beware of overlaps here - don't use memcpy
while (l--)
*p++ = *q++;
if (field->fld_type == blr_varying)
{
*p++ = *q++;
*p++ = *q++;
}
}
// If this is format version 2, build fields for null flags
if (tdgbl->RESTORE_format >= 2)
{
for (field = relation->rel_fields; field; field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
continue;
p = buffer + FB_ALIGN(p - buffer, sizeof(SSHORT));
q = buffer + FB_ALIGN(q - buffer, sizeof(SSHORT));
*p++ = *q++;
*p++ = *q++;
}
}
}
2003-09-18 23:56:26 +02:00
USHORT recompute_length (BURP_REL relation)
{
/**************************************
*
* r e c o m p u t e _ l e n g t h
*
**************************************
*
* Functional description
* Recompute length of a record using an old
* alignment if there is one. At the moment,
* only SPARC has one.
*
**************************************/
#ifdef sparc
BURP_FLD field;
ULONG offset, length, dtype, alignment;
const SSHORT *alignments = old_sparcs;
TGBL tdgbl = GET_THREAD_DATA;
for (field = relation->rel_fields; field; field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
continue;
length = field->fld_length;
alignment = 4;
// arrays are of various fld_types but are really blobs
dtype = field->fld_type;
if (field->fld_flags & FLD_array)
{
dtype = blr_blob;
length = 8;
}
alignment = alignments [gds_cvt_blr_dtype [field->fld_type]];
if (dtype == blr_varying)
length += sizeof(USHORT);
if (alignment)
offset = FB_ALIGN(offset, alignment);
field->fld_old_offset = offset;
offset += length;
}
// If this is format version 2, build fields for null flags
if (tdgbl->RESTORE_format >= 2)
{
for (field = relation->rel_fields; field; field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
continue;
offset = FB_ALIGN(offset, sizeof(SSHORT));
offset += sizeof(SSHORT);
}
}
return offset;
#else
return 0;
#endif
}
bool restore (const TEXT* file_name,
const TEXT* database_name)
{
/**************************************
*
* r e s t o r e
*
**************************************
*
* Functional description
* Perform the body of restore.
*
**************************************/
rec_type record;
ATT_TYPE attribute;
isc_req_handle req_handle1 = NULL, req_handle2 = NULL, req_handle3 = NULL,
req_handle5 = NULL;
TGBL tdgbl = GET_THREAD_DATA;
// Read burp record first
MVOL_init_read ((UCHAR*) tdgbl->gbl_database_file_name, (UCHAR*) file_name,
&tdgbl->RESTORE_format, &tdgbl->io_cnt, &tdgbl->io_ptr);
if (tdgbl->gbl_sw_transportable)
BURP_verbose (133, NULL, NULL, NULL, NULL, NULL);
// msg 133 transportable backup -- data in XDR format
if (tdgbl->gbl_sw_compress)
BURP_verbose (61, NULL, NULL, NULL, NULL, NULL);
// msg 61 backup file is compressed
// restore only from those backup files created by current or previous GBAK
if (tdgbl->RESTORE_format < 1 || tdgbl->RESTORE_format > ATT_BACKUP_FORMAT)
{
BURP_error(44, true, isc_arg_number, (void*)(ULONG)tdgbl->RESTORE_format,
0, NULL, 0, NULL, 0, NULL, 0, NULL);
// msg 44 Expected backup version 1, 2, or 3. Found %ld
}
create_database (database_name);
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
if (gds_status [1])
EXEC SQL SET TRANSACTION;
/* For V4.0, start a read commited transaction. This will be used
* to create blobs for global fields and update the record in the
* RDB$FIELDS table.
*/
EXEC SQL SET TRANSACTION NAME tdgbl->global_trans ISOLATION LEVEL READ COMMITTED;
USHORT db_version = check_db_version();
if (db_version < DB_VERSION_CURRENT)
{
BURP_error(51, true, isc_arg_number, (void*) (ULONG) db_version,
0, NULL, 0, NULL, 0, NULL, 0, NULL);
// msg 51 database format %ld is too old to restore to
}
BURP_verbose (129, NULL, NULL, NULL, NULL, NULL);
// msg 129 started transaction
2003-09-21 01:28:38 +02:00
while (get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
case att_database_security_class:
/* Instead of updating the security class in RDB$DATABASE,
just store the value in tdgbl. It will be updated at
the very end to prevent security class validation
failures during change table ownership operation */
GET_TEXT(tdgbl->database_security_class);
break;
case att_database_description:
case att_database_description2:
FOR (REQUEST_HANDLE req_handle2)
X IN RDB$DATABASE
MODIFY X USING
if (attribute == att_database_description2)
get_source_blob (&X.RDB$DESCRIPTION, false);
else
get_misc_blob (&X.RDB$DESCRIPTION, 1, false);
END_MODIFY;
ON_ERROR
general_on_error ();
END_ERROR;
END_FOR;
ON_ERROR
general_on_error ();
END_ERROR;
break;
case att_database_dfl_charset:
FOR (REQUEST_HANDLE req_handle3)
X IN RDB$DATABASE
MODIFY X USING
GET_TEXT(X.RDB$CHARACTER_SET_NAME);
END_MODIFY;
ON_ERROR
general_on_error ();
END_ERROR;
END_FOR;
ON_ERROR
general_on_error ();
END_ERROR;
break;
default:
{
SSHORT l = get(tdgbl);
if (l)
get_skip(tdgbl, l);
break;
}
}
}
MISC_release_request_silent(req_handle1);
MISC_release_request_silent(req_handle2);
MISC_release_request_silent(req_handle3);
// If this should be a multi-file database, add the files
if (tdgbl->gbl_sw_files && tdgbl->gbl_sw_files->fil_next)
add_files ((UCHAR*) database_name);
// Get global fields and relations
bool flag_norel = true; // To fix bug 10098
bool flag = false;
2003-09-21 01:28:38 +02:00
while (get_record(&record, tdgbl) != rec_end)
{
switch (record)
{
case rec_charset:
if (!get_character_set())
return false;
flag = true;
break;
case rec_collation:
if (!get_collation())
return false;
flag = true;
break;
case rec_chk_constraint:
if (!get_chk_constraint())
return false;
flag = true;
break;
case rec_global_field:
if (!get_global_field())
return false;
flag = true;
break;
case rec_field_dimensions:
if (!get_field_dimensions())
return false;
flag = true;
break;
case rec_relation:
if (!get_relation())
return false;
flag = true;
flag_norel = false;
break;
case rec_ref_constraint:
if (!get_ref_constraint())
return false;
flag = true;
break;
case rec_rel_constraint:
if (!get_rel_constraint())
return false;
flag = true;
break;
case rec_function:
if (!get_function())
return false;
flag = true;
break;
case rec_procedure:
if (!get_procedure())
return false;
flag = true;
break;
case rec_exception:
if (!get_exception())
return false;
flag = true;
break;
case rec_system_type: /* rdb$types */
if (!get_type())
return false;
flag = true;
break;
case rec_filter: /* rdb$filters */
if (!get_filter())
return false;
flag = true;
break;
case rec_generator:
if (!get_generator())
return false;
flag = true;
break;
case rec_relation_data:
if (flag)
{
BURP_verbose (68, NULL, NULL, NULL, NULL, NULL);
// msg 68 committing meta data
COMMIT;
ON_ERROR
general_on_error ();
END_ERROR;
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
if (gds_status [1])
EXEC SQL SET TRANSACTION;
flag = false;
}
if (!get_relation_data())
return false;
break;
case rec_trigger: // new trigger type
if (!get_trigger())
return false;
flag = true;
break;
case rec_trigger_message:
if (!get_trigger_message())
return false;
flag = true;
break;
case rec_user_privilege:
if (!get_user_privilege())
return false;
flag = true;
break;
case rec_security_class:
if (!get_security_class())
return false;
flag = true;
break;
case rec_files:
if (!get_files())
return false;
flag = true;
break;
case rec_sql_roles:
if (!get_sql_roles())
return false;
flag = true;
break;
default:
BURP_error(43, true, isc_arg_number, (void*) record,
0, NULL, 0, NULL, 0, NULL, 0, NULL);
// msg 43 don't recognize record type %ld
break;
}
}
/* This piece of code is to fix bug 10098: restore of database with
only domains and no relations aborts with the message ERROR: deadlock
This is because insertion of domains into RDB$FIELDS is happening in
the default transaction, whereas updation of RDB$FIELDS to add
constraints to the domains is done in tdgbl->global_trans. In case of
no relations, no COMMIT of default transaction occurs till this point
because of which rows in RDB$FIELDS for domains are still locked by
default transaction. The below code COMMITs the default transaction
in that particular situation */
if (flag_norel)
{
COMMIT;
ON_ERROR
general_on_error ();
END_ERROR;
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
if (gds_status [1])
EXEC SQL SET TRANSACTION;
}
// put validation clauses for global fields
update_global_field ();
// Purge shadow metadata if necessary
if (tdgbl->gbl_sw_kill)
FOR (REQUEST_HANDLE req_handle5)
FIL IN RDB$FILES WITH FIL.RDB$SHADOW_NUMBER NOT MISSING
AND FIL.RDB$SHADOW_NUMBER NE 0
ERASE FIL;
ON_ERROR
general_on_error ();
END_ERROR;
END_FOR;
ON_ERROR
general_on_error ();
END_ERROR;
MISC_release_request_silent(req_handle5);
return true;
}
2003-09-18 23:56:26 +02:00
void restore_security_class (const TEXT *owner_nm,
const TEXT *sec_class_nm)
{
/**************************************
*
* r e s t o r e _ s e c u r i t y _ c l a s s
*
**************************************
*
* Functional description
* restore the ownership of the relation in the ACL list
*
**************************************/
isc_tr_handle local_trans;
isc_req_handle req_handle2 = NULL;
ISC_QUAD new_blob_id;
TGBL tdgbl = GET_THREAD_DATA;
local_trans = gds_trans;
FOR (REQUEST_HANDLE req_handle2)
X IN RDB$SECURITY_CLASSES WITH X.RDB$SECURITY_CLASS EQ sec_class_nm
new_blob_id.gds_quad_high = 0;
new_blob_id.gds_quad_low = 0;
get_acl (owner_nm, &X.RDB$ACL, &new_blob_id);
MODIFY X;
MOVE_FAST (&new_blob_id, &X.RDB$ACL, sizeof(ISC_QUAD));
END_MODIFY;
ON_ERROR
MISC_release_request_silent(req_handle2);
general_on_error ();
END_ERROR;
END_FOR;
ON_ERROR
MISC_release_request_silent(req_handle2);
general_on_error ();
END_ERROR;
MISC_release_request_silent(req_handle2);
}
2003-09-18 23:56:26 +02:00
void store_blr_gen_id (const TEXT* gen_name, // TEXT GDS_NAME[GDS_NAME_LEN]
SINT64 value)
{
/**************************************
*
* s t o r e _ b l r _ g e n _ i d
*
**************************************
*
* Functional description
* Store the blr_gen_id for the relation.
*
**************************************/
ISC_STATUS_ARRAY status_vector;
TGBL tdgbl = GET_THREAD_DATA;
STORE (REQUEST_HANDLE tdgbl->handles_store_blr_gen_id_req_handle1)
X IN RDB$GENERATORS
strcpy (X.RDB$GENERATOR_NAME, gen_name);
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
if (!value)
{
#pragma FB_COMPILER_MESSAGE("BRS: casting SINT64 to SLONG")
BURP_verbose (185, gen_name, (void*) (SLONG) value, NULL, NULL, NULL);
// msg 185 restoring generator %s value: %ld
return;
}
FRBRD *gen_id_reqh = NULL;
UCHAR blr_buffer [100]; // enough to fit blr
UCHAR *blr = blr_buffer;
// build the blr with the right relation name
if (tdgbl->RESTORE_format >= 6)
{
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_version5);
}
else
{
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_version4);
}
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_begin);
if (tdgbl->RESTORE_format >= 6)
{
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_dcl_variable);
stuff_word(&blr, 0);
stuff(&blr, blr_int64);
stuff(&blr, 0);
}
else
{
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_dcl_variable);
stuff_word(&blr, 0);
stuff(&blr, blr_long);
stuff(&blr, 0);
}
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_begin);
stuff(&blr, blr_assignment);
stuff(&blr, blr_gen_id);
stuff_string(&blr, gen_name);
if (tdgbl->RESTORE_format >= 6)
{
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_literal);
stuff(&blr, blr_int64);
stuff(&blr, 0);
stuff_int64(&blr, value);
}
else
{
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_literal);
stuff(&blr, blr_long);
stuff(&blr, 0);
stuff_long(&blr, (SLONG)value);
}
2003-09-18 23:56:26 +02:00
stuff(&blr, blr_variable);
stuff_word(&blr, 0);
stuff(&blr, blr_end);
stuff(&blr, blr_end);
stuff(&blr, blr_eoc);
SSHORT blr_length = blr - blr_buffer;
2003-09-23 21:47:50 +02:00
if (isc_compile_request (status_vector, &DB, &gen_id_reqh,
blr_length, (const SCHAR*) blr_buffer))
{
isc_print_blr ((SCHAR*) blr_buffer, NULL, NULL, 0);
BURP_error_redirect (status_vector, 42, 0, 0);
// msg 42 Failed in store_blr_gen_id
}
2003-09-15 03:50:15 +02:00
if (isc_start_request (status_vector, &gen_id_reqh,
&gds_trans, // use the same one generated by gpre
0))
{
isc_print_blr ((SCHAR*) blr_buffer, NULL, NULL, 0);
BURP_error_redirect (status_vector, 42, 0, 0);
// msg 42 Failed in store_blr_gen_id
}
#pragma FB_COMPILER_MESSAGE("BRS: casting SINT64 to SLONG")
BURP_verbose (185, gen_name, (void*) (SLONG) value, NULL, NULL, NULL);
// msg 185 restoring generator %s value: %ld
isc_release_request (status_vector, &gen_id_reqh);
}
2003-09-18 23:56:26 +02:00
void stuff_string(UCHAR **ptr,
const TEXT *string)
{
/**************************************
*
* s t u f f _ s t r i n g
*
**************************************
*
* Functional description
* Stuff a name input a BLR string -- byte count first.
*
**************************************/
2003-09-18 23:56:26 +02:00
stuff(ptr, strlen (string));
while (*string)
2003-09-18 23:56:26 +02:00
stuff(ptr, *string++);
}
void update_global_field (void)
{
/**************************************
*
* u p d a t e _ g l o b a l _ f i e l d
*
**************************************
*
* Functional description
* Update the global field definition to add constraints.
* The blobs have been created already.
*
**************************************/
GFLD n_gfield, gfield;
USHORT length;
UCHAR *p, *q;
isc_req_handle req_handle1 = NULL;
TGBL tdgbl = GET_THREAD_DATA;
for (gfield = tdgbl->gbl_global_fields; gfield; )
{
FOR (TRANSACTION_HANDLE tdgbl->global_trans REQUEST_HANDLE req_handle1)
X IN RDB$FIELDS WITH X.RDB$FIELD_NAME EQ gfield->gfld_name
MODIFY X
if (gfield->gfld_flags & GFLD_validation_blr)
{
X.RDB$VALIDATION_BLR.NULL = FALSE;
if (length = sizeof(ISC_QUAD))
{
p = (UCHAR *)&X.RDB$VALIDATION_BLR;
q = (UCHAR *)&gfield->gfld_vb;
do *p++ = *q++; while (--length);
}
}
if (gfield->gfld_flags & GFLD_validation_source)
{
X.RDB$VALIDATION_SOURCE.NULL = FALSE;
if (length = sizeof(ISC_QUAD))
{
p = (UCHAR *)&X.RDB$VALIDATION_SOURCE;
q = (UCHAR *)&gfield->gfld_vs;
do *p++ = *q++; while (--length);
}
}
if (gfield->gfld_flags & GFLD_validation_source2)
{
X.RDB$VALIDATION_SOURCE.NULL = FALSE;
if (length = sizeof(ISC_QUAD))
{
p = (UCHAR *)&X.RDB$VALIDATION_SOURCE;
q = (UCHAR *)&gfield->gfld_vs2;
do *p++ = *q++; while (--length);
}
}
END_MODIFY;
ON_ERROR
general_on_error ();
END_ERROR;
END_FOR;
ON_ERROR
general_on_error ();
END_ERROR;
n_gfield = gfield->gfld_next;
2003-09-18 23:56:26 +02:00
BURP_free (gfield);
gfield = n_gfield;
}
MISC_release_request_silent(req_handle1);
tdgbl->gbl_global_fields = NULL;
}
} // namespace