8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-29 06:43:03 +01:00
firebird-mirror/src/qli/meta.epp

3885 lines
93 KiB
Plaintext
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Command Oriented Query Language
* MODULE: meta.epp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Meta-data interface
*
* 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): ______________________________________.
*/
#include "firebird.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/ib_stdio.h"
#include <string.h>
#include "../qli/dtr.h"
#include "../qli/compile.h"
#include "../qli/exe.h"
#include "../jrd/license.h"
#include "../jrd/flags.h"
#include "../jrd/gds.h"
#include "../qli/reqs.h"
#include "../qli/all_proto.h"
#include "../qli/err_proto.h"
#include "../qli/gener_proto.h"
#include "../qli/hsh_proto.h"
#include "../qli/meta_proto.h"
#include "../gpre/prett_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/isc_f_proto.h"
#include "../jrd/utl_proto.h"
#include "../wal/walf_proto.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
2003-07-14 18:55:04 +02:00
// needed for unlink in MinGW 3.0 rc2
#ifdef MINGW
#include <io.h>
#endif
2001-05-23 15:26:42 +02:00
DATABASE DB = FILENAME "yachts.lnk";
DATABASE DB1 = FILENAME "yachts.lnk";
extern USHORT sw_buffers;
static void add_field(QLI_REL, QLI_FLD, USHORT);
static void add_sql_field(QLI_REL, QLI_FLD, USHORT, RLB);
static int blob_copy(RLB, QLI_REL, SLONG *);
static void change_field(QLI_REL, QLI_FLD);
2003-09-10 19:52:12 +02:00
static bool check_global_field(DBB, QLI_FLD, TEXT *);
static bool check_relation(QLI_REL);
static int clone_fields(QLI_REL, QLI_REL);
static int clone_global_fields(QLI_REL, QLI_REL);
static void define_global_field(DBB, QLI_FLD, SYM);
static void delete_fields(QLI_REL);
2003-04-10 12:16:09 +02:00
static ISC_STATUS detach(ISC_STATUS *, DBB);
2003-09-10 19:52:12 +02:00
static void execute_dynamic_ddl(DBB, RLB);
2001-05-23 15:26:42 +02:00
static int field_length(USHORT, USHORT);
static void get_database_type(DBB);
static void get_log_names(DBB, SCHAR *, LLS *, SCHAR *, SLONG, SSHORT,
SSHORT);
static void get_log_names_serial(LLS *);
static TEXT *get_query_header(DBB, SLONG[2]);
static void install(DBB);
static SYN make_node(NOD_T, USHORT);
static TEXT *make_string(TEXT *, SSHORT);
static SYM make_symbol(TEXT *, SSHORT);
static CON missing_value(SLONG *, SYM);
static SYN parse_blr(UCHAR **, SYM);
static SYN parse_blr_blob(SLONG *, SYM);
static void purge_relation(QLI_REL);
static void put_dyn_string(RLB, const TEXT*);
2001-05-23 15:26:42 +02:00
static void rollback_update(DBB);
static void set_capabilities(DBB);
static DBB setup_update(DBB);
static void sql_grant_revoke(SYN, USHORT);
static void stuff_priv(RLB, USHORT, const TEXT*, USHORT, const TEXT*, const TEXT*);
2001-05-23 15:26:42 +02:00
static int truncate_string(TEXT *);
static void wal_info(UCHAR *, SLONG *, SCHAR *, SLONG *);
2003-02-13 10:42:18 +01:00
static const UCHAR tpb[] = { gds_tpb_version1, gds_tpb_write };
static const UCHAR db_info[] = { gds_info_implementation, gds_info_end };
static UCHAR global_parm_buffer[256];
2001-05-23 15:26:42 +02:00
2003-02-13 10:42:18 +01:00
static const UCHAR db_log_info[] =
{ gds_info_logfile, gds_info_cur_logfile_name,
gds_info_cur_log_part_offset };
2001-05-23 15:26:42 +02:00
/*
2003-02-13 10:42:18 +01:00
static const UCHAR dpb_trace [] = { gds_dpb_version1, gds_dpb_trace, 1, 1 };
static const UCHAR dpb_num_buffers [ ] = { gds_dpb_version1, gds_dpb_num_buffers, 1, 1 };
2001-05-23 15:26:42 +02:00
*/
#define STUFF_STRING(str) put_dyn_string (rlb, str)
#define BLR_BYTE *blr++
2003-02-13 10:42:18 +01:00
static const USHORT blr_dtypes[] = {
2001-05-23 15:26:42 +02:00
0,
blr_text,
blr_text,
blr_varying,
0,
0,
0,
0,
blr_short,
blr_long,
blr_quad,
blr_float,
blr_double,
blr_double,
blr_sql_date,
blr_sql_time,
blr_timestamp,
blr_blob,
0,
blr_int64
2001-05-23 15:26:42 +02:00
};
/*
table used to determine capabilities, checking for specific
fields in system relations
2001-05-23 15:26:42 +02:00
*/
struct rfr_tab_t {
2003-02-13 10:42:18 +01:00
const TEXT *relation;
const TEXT *field;
2001-05-23 15:26:42 +02:00
int bit_mask;
};
2001-05-23 15:26:42 +02:00
2003-09-23 12:13:39 +02:00
static const rfr_tab_t rfr_table[] = {
{ "RDB$INDICES", "RDB$INDEX_INACTIVE", DBB_cap_idx_inactive },
/* OBSOLETE - 1996-Aug-06 David Schnepper
{ "RDB$RELATIONS", "RDB$STORE_TRIGGER", DBB_cap_triggers },
2001-05-23 15:26:42 +02:00
*/
{ "RDB$RELATIONS", "RDB$EXTERNAL_FILE", DBB_cap_extern_file },
{ "RDB$SECURITY_CLASSES", "RDB$SECURITY_CLASS", DBB_cap_security },
{ "RDB$FILES", "RDB$FILE_NAME", DBB_cap_files },
{ "RDB$FUNCTIONS", "RDB$FUNCTION_NAME", DBB_cap_functions },
{ "RDB$TRIGGERS", "RDB$TRIGGER_BLR", DBB_cap_new_triggers },
{ "RDB$CONSTRAINTS", "RDB$CONSTRAINT_NAME", DBB_cap_single_trans },
{ "RDB$FILES", "RDB$SHADOW_NUMBER", DBB_cap_shadowing },
{ "RDB$TYPES", "RDB$TYPE_NAME", DBB_cap_types },
{ "RDB$FIELDS", "RDB$DIMENSIONS", DBB_cap_dimensions },
{ "RDB$FIELDS", "RDB$EXTERNAL_TYPE", DBB_cap_external_type },
{ "RDB$RELATION_FIELDS", "RDB$SYSTEM_FLAG", DBB_cap_rfr_sys_flag },
{ "RDB$FILTERS", "RDB$FUNCTION_NAME", DBB_cap_filters },
{ "RDB$INDICES", "RDB$INDEX_TYPE", DBB_cap_index_type },
{ 0, 0, 0 }
2001-05-23 15:26:42 +02:00
};
int MET_declare( DBB database, QLI_FLD variable, NAM field_name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T _ d e c l a r e
*
**************************************
*
* Functional description
* Find a global field referenced in a DECLARE.
*
**************************************/
if (!database)
database = QLI_databases;
for (; database; database = database->dbb_next) {
MET_meta_transaction(database, FALSE);
if (check_global_field(database, variable, field_name->nam_string))
return TRUE;
}
return FALSE;
}
void MET_define_field( DBB database, QLI_FLD field)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T _ d e f i n e _ f i e l d
*
**************************************
*
* Functional description
* Define a new global field.
*
**************************************/
database = setup_update(database);
if (check_global_field(database, NULL, field->fld_name->sym_string)) {
2001-05-23 15:26:42 +02:00
rollback_update(database);
ERRQ_print_error(233, field->fld_name->sym_string, NULL, NULL, NULL, NULL); // Msg233 global field %s already exists
2001-05-23 15:26:42 +02:00
}
define_global_field(database, field, field->fld_name);
MET_meta_commit(database);
}
void MET_define_index( SYN node)
{
/**************************************
*
* M E T _ d e f i n e _ i n d e x
*
**************************************
*
* Functional description
* Define a new index.
*
**************************************/
SYM symbol = (SYM) node->syn_arg[s_dfi_name];
QLI_REL relation = (QLI_REL) node->syn_arg[s_dfi_relation];
SYN fields = node->syn_arg[s_dfi_fields];
DBB database = setup_update(relation->rel_database);
2001-05-23 15:26:42 +02:00
if (relation->rel_flags & REL_view)
IBERROR(234); // Msg234 Can't define an index in a view
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE database->dbb_requests[REQ_def_index1])
X IN DB.RDB$INDICES WITH X.RDB$INDEX_NAME EQ symbol->sym_string
ERRQ_print_error(235, symbol->sym_string, NULL, NULL, NULL, NULL);
// Msg235 Index %s already exists
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
STORE(REQUEST_HANDLE database->dbb_requests[REQ_def_index2])
X IN DB.RDB$INDICES
strcpy(X.RDB$RELATION_NAME, relation->rel_symbol->sym_string);
strcpy(X.RDB$INDEX_NAME, symbol->sym_string);
X.RDB$UNIQUE_FLAG = (node->syn_flags & s_dfi_flag_unique);
X.RDB$INDEX_INACTIVE = (node->syn_flags & s_dfi_flag_inactive);
X.RDB$SEGMENT_COUNT = fields->syn_count;
X.RDB$INDEX_TYPE =
(node->syn_flags & s_dfi_flag_descending) ? TRUE : FALSE;
END_STORE
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
/* at this point force garbage collection of any index segments left over
from previous failures. The system transaction (which might notice them
later does NOT recognize rolled back stuff! Should someone have actually
left an orphanned segment around, kill that too.
*/
FOR(REQUEST_HANDLE database->dbb_requests[REQ_scan_index])
X IN DB.RDB$INDEX_SEGMENTS WITH X.RDB$INDEX_NAME = symbol->sym_string
ERASE X
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
END_FOR
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
NAM* ptr = (NAM*) fields->syn_arg;
for (int position = 0; position < fields->syn_count; ptr++, position++)
{
2001-05-23 15:26:42 +02:00
MET_fields(relation);
bool present = false;
for (QLI_FLD field = relation->rel_fields; field;
field = field->fld_next)
{
if (!(strcmp((*ptr)->nam_string, field->fld_name->sym_string))) {
present = true;
2001-05-23 15:26:42 +02:00
break;
}
}
2001-05-23 15:26:42 +02:00
if (!present) {
rollback_update(database);
ERRQ_print_error(236, (*ptr)->nam_string,
relation->rel_symbol->sym_string, NULL, NULL, NULL);
// Msg236 Field %s does not occur in relation %s
2001-05-23 15:26:42 +02:00
}
setup_update(database);
STORE(REQUEST_HANDLE database->dbb_requests[REQ_def_index3])
X IN DB.RDB$INDEX_SEGMENTS
strcpy(X.RDB$INDEX_NAME, symbol->sym_string);
strcpy(X.RDB$FIELD_NAME, (*ptr)->nam_string);
X.RDB$FIELD_POSITION = position;
END_STORE
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
}
MET_meta_commit(database);
}
void MET_define_relation( QLI_REL relation, QLI_REL source)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T _ d e f i n e _ r e l a t i o n
*
**************************************
*
* Functional description
* Define a new relation. There may
* be field definitions here or we may
* copy the field definitions from somebody
* else.
*
**************************************/
SYM symbol = relation->rel_symbol;
2001-05-23 15:26:42 +02:00
if (source) {
source->rel_database = setup_update(source->rel_database);
if (!(check_relation(source)))
ERRQ_print_error(483, source->rel_symbol->sym_string, NULL, NULL,
NULL, NULL); // Msg 483 Relation %s does not exist
2001-05-23 15:26:42 +02:00
}
DBB database = setup_update(relation->rel_database);
relation->rel_database = database;
2001-05-23 15:26:42 +02:00
if (check_relation(relation))
ERRQ_print_error(237, symbol->sym_string, NULL, NULL, NULL, NULL); // Msg237 Relation %s already exists
2001-05-23 15:26:42 +02:00
STORE(REQUEST_HANDLE database->dbb_requests[REQ_store_relation])
X IN DB.RDB$RELATIONS
2001-05-23 15:26:42 +02:00
strcpy(X.RDB$RELATION_NAME, symbol->sym_string);
END_STORE
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
if (source)
clone_fields(relation, source);
else {
USHORT position = 1;
for (QLI_FLD field = relation->rel_fields; field;
field = field->fld_next, position++)
{
2001-05-23 15:26:42 +02:00
add_field(relation, field, position);
}
}
2001-05-23 15:26:42 +02:00
MET_meta_commit(database);
relation = (QLI_REL) ALLOCP(type_rel);
2001-05-23 15:26:42 +02:00
relation->rel_next = database->dbb_relations;
database->dbb_relations = relation;
relation->rel_database = database;
// Go back and pick up relation id
2001-05-23 15:26:42 +02:00
setup_update(database);
FOR(REQUEST_HANDLE database->dbb_requests[REQ_relation_id])
X IN DB.RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ symbol->sym_string
relation->rel_id = X.RDB$RELATION_ID;
2001-05-23 15:26:42 +02:00
symbol = make_symbol(X.RDB$RELATION_NAME, sizeof(X.RDB$RELATION_NAME));
symbol->sym_type = SYM_relation;
symbol->sym_object = (BLK) relation;
relation->rel_symbol = symbol;
HSH_insert(symbol);
END_FOR
ON_ERROR
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
delete_fields(relation);
MET_fields(relation);
}
void MET_define_sql_relation( QLI_REL relation)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T _ d e f i n e _ s q l _ r e l a t i o n
*
**************************************
*
* Functional description
* Define a new SQL relation, using dynamic ddl.
*
**************************************/
SYM symbol = relation->rel_symbol;
DBB database = setup_update(relation->rel_database);
relation->rel_database = database;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE database->dbb_requests[REQ_relation_def])
X IN DB.RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ symbol->sym_string
ERRQ_print_error(237, symbol->sym_string, NULL, NULL, NULL, NULL);
// Msg237 Relation %s already exists
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
RLB rlb = NULL;
2001-05-23 15:26:42 +02:00
rlb = CHECK_RLB(rlb);
STUFF(gds_dyn_version_1);
STUFF(gds_dyn_begin);
STUFF(gds_dyn_def_rel);
2001-05-23 15:26:42 +02:00
STUFF_STRING(symbol->sym_string);
STUFF(gds_dyn_rel_sql_protection);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(1);
USHORT position = 1;
for (QLI_FLD field = relation->rel_fields; field;
2001-05-23 15:26:42 +02:00
field = field->fld_next, position++)
{
2001-05-23 15:26:42 +02:00
add_sql_field(relation, field, position, rlb);
}
2001-05-23 15:26:42 +02:00
STUFF(gds_dyn_end);
STUFF(gds_dyn_end);
STUFF(gds_dyn_eoc);
2001-05-23 15:26:42 +02:00
execute_dynamic_ddl(database, rlb);
MET_meta_commit(database);
relation = (QLI_REL) ALLOCP(type_rel);
2001-05-23 15:26:42 +02:00
relation->rel_next = database->dbb_relations;
database->dbb_relations = relation;
relation->rel_database = database;
// Go back and pick up relation id
2001-05-23 15:26:42 +02:00
setup_update(database);
FOR(REQUEST_HANDLE database->dbb_requests[REQ_relation_id])
X IN DB.RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ symbol->sym_string
relation->rel_id = X.RDB$RELATION_ID;
2001-05-23 15:26:42 +02:00
symbol =
make_symbol(X.RDB$RELATION_NAME, sizeof(X.RDB$RELATION_NAME));
symbol->sym_type = SYM_relation;
symbol->sym_object = (BLK) relation;
relation->rel_symbol = symbol;
HSH_insert(symbol);
END_FOR
ON_ERROR
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
delete_fields(relation);
MET_fields(relation);
}
void MET_delete_database( DBB dbb)
{
/**************************************
*
* M E T _ d e l e t e _ d a t a b a s e
*
**************************************
*
* Functional description
* Drop an existing database, and all its files,
* and finish any copies we have active.
*
**************************************/
/* generate a database parameter block to
2001-05-23 15:26:42 +02:00
include the user/password, if necessary */
TEXT* user;
USHORT user_length;
2001-05-23 15:26:42 +02:00
if (dbb->dbb_user) {
user = (TEXT *) dbb->dbb_user->con_data;
user_length = dbb->dbb_user->con_desc.dsc_length;
}
else {
user = QLI_default_user;
user_length = strlen(QLI_default_user);
}
TEXT* password;
USHORT password_length;
2001-05-23 15:26:42 +02:00
if (dbb->dbb_password) {
password = (TEXT *) dbb->dbb_password->con_data;
password_length = dbb->dbb_user->con_desc.dsc_length;
}
else {
password = QLI_default_password;
password_length = strlen(QLI_default_password);
}
UCHAR* p = global_parm_buffer;
UCHAR* const dpb = p;
*p++ = gds_dpb_version1;
2001-05-23 15:26:42 +02:00
if (user_length) {
*p++ = gds_dpb_user_name;
2001-05-23 15:26:42 +02:00
*p++ = user_length;
while (user_length--)
*p++ = *user++;
}
if (password_length) {
*p++ = gds_dpb_password;
2001-05-23 15:26:42 +02:00
*p++ = password_length;
while (password_length--)
*p++ = *password++;
}
USHORT dpb_length = p - global_parm_buffer;
2001-05-23 15:26:42 +02:00
if (dpb_length == 1)
dpb_length = 0;
ISC_STATUS_ARRAY status_vector;
2003-08-30 04:12:44 +02:00
if (gds__attach_database(status_vector, 0, dbb->dbb_filename,
&dbb->dbb_handle, dpb_length, (char*) dpb))
2001-05-23 15:26:42 +02:00
ERRQ_database_error(dbb, status_vector);
LLS log_stack = NULL, stack = NULL;
2001-05-23 15:26:42 +02:00
gds_trans = MET_transaction(nod_start_trans, dbb);
2001-05-23 15:26:42 +02:00
DB = dbb->dbb_handle;
FOR F IN DB.RDB$FILES SORTED BY F.RDB$FILE_START
STR astring = (STR) ALLOCDV(type_str, strlen(F.RDB$FILE_NAME));
strcpy(astring->str_data, F.RDB$FILE_NAME);
LLS_PUSH(astring, &stack);
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
ERRQ_database_error(dbb, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
// Get write ahead log information
2001-05-23 15:26:42 +02:00
TEXT db_info_buffer[512];
2003-08-30 04:12:44 +02:00
if (gds__database_info(status_vector, &DB, sizeof(db_log_info),
(char*) db_log_info, sizeof(db_info_buffer),
db_info_buffer))
2003-08-30 04:12:44 +02:00
ERRQ_database_error(dbb, status_vector);
2001-05-23 15:26:42 +02:00
// extract info from buffer
2001-05-23 15:26:42 +02:00
TEXT cur_log[512];
SLONG part_offset, log = 0;
wal_info((UCHAR*) db_info_buffer, &log, cur_log, &part_offset);
2001-05-23 15:26:42 +02:00
if (log)
get_log_names_serial(&log_stack);
MET_transaction(nod_commit, dbb);
2003-08-30 04:12:44 +02:00
if (gds__detach_database(gds_status, &dbb->dbb_handle))
gds__print_status(gds_status);
2001-05-23 15:26:42 +02:00
DBB next = NULL;
for (DBB database = QLI_databases; database; database = next) {
2001-05-23 15:26:42 +02:00
next = database->dbb_next;
if (!strcmp(database->dbb_filename, dbb->dbb_filename))
MET_finish(database);
}
if (log) {
TEXT db_name[512];
2001-05-23 15:26:42 +02:00
ISC_expand_filename(dbb->dbb_filename, 0, db_name);
get_log_names(dbb, db_name, &log_stack, cur_log, part_offset, 0, 1);
}
while (stack) {
STR sstring = (STR) LLS_POP(&stack);
if (unlink(sstring->str_data))
ERRQ_print_error(431, sstring->str_data, NULL, NULL, NULL, NULL);
// Msg431 Could not drop database file "%s"
2001-05-23 15:26:42 +02:00
}
while (log_stack) {
STR lstring = (STR) LLS_POP(&log_stack);
unlink(lstring->str_data); // do not check for error
2001-05-23 15:26:42 +02:00
}
if (unlink(dbb->dbb_filename))
ERRQ_print_error(431, dbb->dbb_filename, NULL, NULL, NULL, NULL);
// Msg431 Could not drop database file "%s"
2001-05-23 15:26:42 +02:00
}
void MET_delete_field( DBB database, NAM name)
{
/**************************************
*
* M E T _ d e l e t e _ f i e l d
*
**************************************
*
* Functional description
* Delete a global field.
*
**************************************/
database = setup_update(database);
USHORT count = 0;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE database->dbb_requests[REQ_check_fld])
RFR IN DB.RDB$RELATION_FIELDS
WITH RFR.RDB$FIELD_SOURCE EQ name->nam_string
REDUCED TO RFR.RDB$RELATION_NAME
2001-05-23 15:26:42 +02:00
if (!count)
ERRQ_msg_put(238, name->nam_string, NULL, NULL, NULL, NULL); // Msg238 Field %s is in use in the following relations:
2001-05-23 15:26:42 +02:00
ib_printf("\t%s\n", RFR.RDB$RELATION_NAME);
count++;
END_FOR
ON_ERROR
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
if (count)
ERRQ_print_error(239, name->nam_string, database->dbb_filename, NULL,
NULL, NULL); // Msg239 Field %s is in use in database %s
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE database->dbb_requests[REQ_erase_fld])
FLD IN DB.RDB$FIELDS WITH FLD.RDB$FIELD_NAME EQ name->nam_string
RLB rlb = NULL;
2001-05-23 15:26:42 +02:00
rlb = CHECK_RLB(rlb);
STUFF(gds_dyn_version_1);
STUFF(gds_dyn_delete_dimensions);
2001-05-23 15:26:42 +02:00
STUFF_STRING(FLD.RDB$FIELD_NAME);
STUFF(gds_dyn_end);
STUFF(gds_dyn_eoc);
2001-05-23 15:26:42 +02:00
execute_dynamic_ddl(database, rlb);
ERASE FLD
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
count++;
END_FOR
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
if (!count)
ERRQ_print_error(240, name->nam_string, database->dbb_filename, NULL,
NULL, NULL); // Msg240 Field %s is not defined in database %s
2001-05-23 15:26:42 +02:00
MET_meta_commit(database);
}
void MET_delete_index( DBB database, NAM name)
{
/**************************************
*
* M E T _ d e l e t e _ i n d e x
*
**************************************
*
* Functional description
* Delete an index.
*
**************************************/
database = setup_update(database);
USHORT count = 0;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE database->dbb_requests[REQ_erase_index])
IDX IN DB.RDB$INDICES WITH IDX.RDB$INDEX_NAME EQ name->nam_string
count++;
ERASE IDX
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
END_FOR
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
if (!count)
ERRQ_print_error(241, name->nam_string, database->dbb_filename, NULL,
NULL, NULL); // Msg241 Index %s is not defined in database %s
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE database->dbb_requests[REQ_erase_segments])
SEG IN DB.RDB$INDEX_SEGMENTS WITH SEG.RDB$INDEX_NAME EQ name->nam_string
ERASE SEG
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
END_FOR
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
MET_meta_commit(database);
}
void MET_delete_relation( QLI_REL relation)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T _ d e l e t e _ r e l a t i o n
*
**************************************
*
* Functional description
* Delete a relation.
*
**************************************/
// Pass the mess off to dynamic DDL and let it worry
2001-05-23 15:26:42 +02:00
SYM symbol = relation->rel_symbol;
RLB rlb = NULL;
2001-05-23 15:26:42 +02:00
rlb = CHECK_RLB(rlb);
STUFF(gds_dyn_version_1);
STUFF(gds_dyn_delete_rel);
2001-05-23 15:26:42 +02:00
STUFF_STRING(symbol->sym_string);
STUFF(gds_dyn_end);
STUFF(gds_dyn_eoc);
2001-05-23 15:26:42 +02:00
setup_update(relation->rel_database);
execute_dynamic_ddl(relation->rel_database, rlb);
MET_meta_commit(relation->rel_database);
// Unlink and release various blocks
2001-05-23 15:26:42 +02:00
purge_relation(relation);
}
int MET_dimensions( DBB database, TEXT * field_name)
{
/**************************************
*
* M E T _ d i m e n s i o n s
*
**************************************
*
* Functional description
* Determine if the field has any dimensions.
*
**************************************/
if (!(database->dbb_capabilities & DBB_cap_dimensions))
return 0;
USHORT dimensions = 0;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE database->dbb_requests[REQ_fld_dimensions])
F IN DB.RDB$FIELDS WITH F.RDB$FIELD_NAME = field_name
dimensions = F.RDB$DIMENSIONS;
END_FOR
ON_ERROR
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
return dimensions;
}
void MET_fields( QLI_REL relation)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T _ f i e l d s
*
**************************************
*
* Functional description
* Get all fields for a relation.
*
**************************************/
/* If we already have fetched the fields for the relation,
2001-05-23 15:26:42 +02:00
don't do it again. */
if (relation->rel_flags & REL_fields)
return;
DBB database = relation->rel_database;
2001-05-23 15:26:42 +02:00
MET_meta_transaction(database, FALSE);
relation->rel_flags |= REL_fields;
QLI_FLD* ptr = &relation->rel_fields;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE database->dbb_field_request)
RFR IN DB.RDB$RELATION_FIELDS CROSS
RFL IN DB.RDB$FIELDS WITH
RFR.RDB$FIELD_SOURCE EQ RFL.RDB$FIELD_NAME AND
RFR.RDB$RELATION_NAME EQ relation->rel_symbol->sym_string
SORTED BY RFR.RDB$FIELD_POSITION, RFR.RDB$FIELD_NAME;
if (RFR.RDB$FIELD_POSITION > relation->rel_max_field_pos)
relation->rel_max_field_pos = RFR.RDB$FIELD_POSITION;
QLI_FLD field = (QLI_FLD) ALLOCPV(type_fld, 0);
*ptr = field;
2001-05-23 15:26:42 +02:00
ptr = &field->fld_next;
field->fld_relation = relation;
SYM symbol = make_symbol(RFR.RDB$FIELD_NAME, sizeof(RFR.RDB$FIELD_NAME));
if (symbol) {
2001-05-23 15:26:42 +02:00
symbol->sym_object = (BLK) field;
symbol->sym_type = SYM_field;
field->fld_name = symbol;
}
if ((symbol = make_symbol(RFR.RDB$QUERY_NAME, sizeof(RFR.RDB$QUERY_NAME))) ||
(symbol = make_symbol(RFL.RDB$QUERY_NAME, sizeof(RFL.RDB$QUERY_NAME)))) {
symbol->sym_object = (BLK) field;
symbol->sym_type = SYM_field;
field->fld_query_name = symbol;
}
field->fld_scale = RFL.RDB$FIELD_SCALE;
field->fld_id = RFR.RDB$FIELD_ID;
if (RFL.RDB$SEGMENT_LENGTH.NULL)
field->fld_segment_length = 80;
else {
2001-05-23 15:26:42 +02:00
field->fld_segment_length =
((RFL.RDB$SEGMENT_LENGTH) < 256
&& (RFL.RDB$SEGMENT_LENGTH >
0)) ? RFL.RDB$SEGMENT_LENGTH : 255;
}
2001-05-23 15:26:42 +02:00
SLONG* blob = (SLONG*) & RFR.RDB$QUERY_HEADER;
2001-05-23 15:26:42 +02:00
if (!blob[0] && !blob[1])
blob = (SLONG *) & RFL.RDB$QUERY_HEADER;
if (blob[0] || blob[1])
field->fld_query_header = get_query_header(database, blob);
blob = (SLONG *) & RFL.RDB$COMPUTED_BLR;
if (blob[0] || blob[1])
field->fld_flags |= FLD_computed;
field->fld_dtype = MET_get_datatype(RFL.RDB$FIELD_TYPE);
field->fld_length =
field_length(field->fld_dtype, RFL.RDB$FIELD_LENGTH);
if (field->fld_dtype == dtype_varying)
field->fld_length += sizeof(SSHORT);
field->fld_sub_type = RFL.RDB$FIELD_SUB_TYPE;
field->fld_sub_type_missing = RFL.RDB$FIELD_SUB_TYPE.NULL;
if (!RFL.RDB$MISSING_VALUE.NULL)
field->fld_missing =
missing_value((SLONG*) &RFL.RDB$MISSING_VALUE, field->fld_name);
2001-05-23 15:26:42 +02:00
if (!(field->fld_edit_string =
make_string(RFR.RDB$EDIT_STRING, sizeof(RFR.RDB$EDIT_STRING))))
field->fld_edit_string =
make_string(RFL.RDB$EDIT_STRING, sizeof(RFL.RDB$EDIT_STRING));
field->fld_validation =
parse_blr_blob((SLONG*) &RFL.RDB$VALIDATION_BLR, field->fld_name);
2001-05-23 15:26:42 +02:00
if (MET_dimensions(database, RFL.RDB$FIELD_NAME) > 0)
field->fld_flags |= FLD_array;
END_FOR
ON_ERROR
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
}
void MET_finish( DBB dbb)
{
/**************************************
*
* M E T _ f i n i s h
*
**************************************
*
* Functional description
* Finish a database and release all associated blocks.
*
**************************************/
// Get rid of relation and field blocks.
2001-05-23 15:26:42 +02:00
QLI_REL relation;
2001-05-23 15:26:42 +02:00
while (relation = dbb->dbb_relations) {
purge_relation(relation);
}
// Get rid of any functions
2001-05-23 15:26:42 +02:00
FUN function;
2001-05-23 15:26:42 +02:00
while (function = dbb->dbb_functions) {
dbb->dbb_functions = function->fun_next;
HSH_remove(function->fun_symbol);
ALL_release((FRB) function->fun_symbol);
ALL_release((FRB) function);
2001-05-23 15:26:42 +02:00
}
// Finally, actually close down database connection.
2001-05-23 15:26:42 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
detach(status_vector, dbb);
if (dbb->dbb_symbol) {
HSH_remove(dbb->dbb_symbol);
ALL_release((FRB) dbb->dbb_symbol);
2001-05-23 15:26:42 +02:00
}
int count = 0;
for (DBB* ptr = &QLI_databases; *ptr; ptr = &(*ptr)->dbb_next)
2001-05-23 15:26:42 +02:00
{
if (*ptr == dbb)
{
*ptr = dbb->dbb_next;
ALL_release((FRB) dbb);
2001-05-23 15:26:42 +02:00
count++;
if (!*ptr) {
break;
}
}
}
if (!count)
BUGCHECK(231); // Msg231 database block not found for removal
2001-05-23 15:26:42 +02:00
if (status_vector[1])
ERRQ_database_error(NULL, status_vector);
2001-05-23 15:26:42 +02:00
}
int MET_get_datatype( USHORT blr_datatype)
{
/**************************************
*
* M E T _ g e t _ d a t a t y p e
*
**************************************
*
* Functional description
* Convert a blr datatype to a QLI dtype.
*
**************************************/
USHORT retvalue;
switch (blr_datatype)
{
case blr_text:
2001-05-23 15:26:42 +02:00
retvalue = dtype_text;
break;
case blr_varying:
2001-05-23 15:26:42 +02:00
retvalue = dtype_varying;
break;
case blr_cstring:
2001-05-23 15:26:42 +02:00
retvalue = dtype_cstring;
break;
case blr_short:
2001-05-23 15:26:42 +02:00
retvalue = dtype_short;
break;
case blr_long:
2001-05-23 15:26:42 +02:00
retvalue = dtype_long;
break;
case blr_quad:
2001-05-23 15:26:42 +02:00
retvalue = dtype_quad;
break;
case blr_float:
2001-05-23 15:26:42 +02:00
retvalue = dtype_real;
break;
case blr_double:
2001-05-23 15:26:42 +02:00
retvalue = dtype_double;
break;
case blr_timestamp:
2001-05-23 15:26:42 +02:00
retvalue = dtype_timestamp;
break;
case blr_sql_date:
2001-05-23 15:26:42 +02:00
retvalue = dtype_sql_date;
break;
case blr_sql_time:
2001-05-23 15:26:42 +02:00
retvalue = dtype_sql_time;
break;
case blr_blob:
2001-05-23 15:26:42 +02:00
retvalue = dtype_blob;
break;
case blr_int64:
retvalue = dtype_int64;
break;
default:
2001-05-23 15:26:42 +02:00
retvalue = dtype_null;
break;
}
2001-05-23 15:26:42 +02:00
return retvalue;
}
#ifdef DEV_BUILD
void MET_index_info(const SCHAR* relation_name,
const SCHAR* index_name,
SCHAR* buffer)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T _ i n d e x _ i n f o
*
**************************************
*
* Functional description
* Get info about a particular index.
*
**************************************/
FRBRD* request_handle = NULL;
2001-05-23 15:26:42 +02:00
SCHAR* b = buffer;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request_handle)
IDX IN DB.RDB$INDICES CROSS
SEG IN DB.RDB$INDEX_SEGMENTS OVER
RDB$INDEX_NAME WITH
IDX.RDB$INDEX_NAME EQ index_name AND
IDX.RDB$RELATION_NAME EQ relation_name
SORTED BY SEG.RDB$FIELD_POSITION
2001-05-23 15:26:42 +02:00
const SCHAR* p;
2001-05-23 15:26:42 +02:00
if (b == buffer) {
// CVC: warning: not dialect 3 aware.
2001-05-23 15:26:42 +02:00
for (p = IDX.RDB$INDEX_NAME; *p && *p != ' ';) {
*b++ = *p++;
}
*b++ = ' ';
*b++ = '(';
}
// CVC: warning: not dialect 3 aware.
2001-05-23 15:26:42 +02:00
for (p = SEG.RDB$FIELD_NAME; *p && *p != ' ';) {
*b++ = *p++;
}
*b++ = ' ';
END_FOR
ON_ERROR
ERRQ_database_error(NULL, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
if (request_handle)
2003-08-30 04:12:44 +02:00
if (gds__release_request(gds_status, &request_handle))
ERRQ_database_error(NULL, gds_status);
2001-05-23 15:26:42 +02:00
// back up over the last space and finish off
2001-05-23 15:26:42 +02:00
b--;
*b++ = ')';
*b++ = 0;
}
#endif
void MET_meta_commit( DBB database)
{
/**************************************
*
* M E T _ m e t a _ c o m m i t
*
**************************************
*
* Functional description
* Commit the meta data lookup & update
* transaction.
*
**************************************/
if (database->dbb_capabilities & DBB_cap_multi_trans)
{
ISC_STATUS_ARRAY status_vector;
2003-08-30 04:12:44 +02:00
if (gds__commit_transaction(status_vector, &database->dbb_meta_trans)) {
2001-05-23 15:26:42 +02:00
rollback_update(database);
ERRQ_database_error(database, status_vector);
}
}
2001-05-23 15:26:42 +02:00
}
void MET_meta_rollback( DBB database)
{
/**************************************
*
* M E T _ m e t a _ r o l l b a c k
*
**************************************
*
* Functional description
* Rollback the metadata transaction,
* if there is one.
*
**************************************/
if (database->dbb_capabilities & DBB_cap_multi_trans)
rollback_update(database);
}
FRBRD *MET_meta_transaction(DBB database, int update_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T _ m e t a _ t r a n s a c t i o n
*
**************************************
*
* Functional description
* Setup transaction for meta-data operation. Set up
* DB and gds_trans, and return meta-data transaction
2001-05-23 15:26:42 +02:00
* handle for yucks. If we're doing metadata updates,
* and lookups we'll use the metadat date transaction,
* unless this is an rdb database or gateway in which
2001-05-23 15:26:42 +02:00
* case, we'll use the only transacti.
*
2001-05-23 15:26:42 +02:00
* In any event, we will set up the met_transaction because
* it's widely used and somebody is going to forget to test
* that the database is multi_transaction before using it.
* This means that we have to be very careful about committing
* or rolling back, because this could affect user data.
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
if (!database)
IBERROR(243); // Msg243 no active database for operation
2001-05-23 15:26:42 +02:00
FRBRD* transaction = (database->dbb_capabilities & DBB_cap_multi_trans) ?
database->dbb_meta_trans : NULL;
2001-05-23 15:26:42 +02:00
DB = database->dbb_handle;
/* If we don't know whether or not the database can handle
multiple transactions, find out now */
if (!transaction &&
((database->dbb_capabilities & DBB_cap_multi_trans) ||
!(database->dbb_capabilities & DBB_cap_single_trans)))
{
2003-08-30 04:12:44 +02:00
if (gds__start_transaction(status_vector, &transaction, 1,
&database->dbb_handle, sizeof(tpb), tpb))
2001-05-23 15:26:42 +02:00
{
database->dbb_capabilities |= DBB_cap_single_trans;
}
else
{
database->dbb_capabilities |= DBB_cap_multi_trans;
}
}
// If we already have a meta-data transaction, there's more nothing to do
2001-05-23 15:26:42 +02:00
gds_trans = transaction;
2001-05-23 15:26:42 +02:00
// If we only support a single transaction, use the data transaction
2001-05-23 15:26:42 +02:00
if (!gds_trans && (database->dbb_capabilities & DBB_cap_single_trans))
2001-05-23 15:26:42 +02:00
{
if (update_flag)
IBERROR(244); // Msg244 Interactive metadata updates are not available on Rdb
if (!(gds_trans = database->dbb_transaction))
gds_trans = MET_transaction(nod_start_trans, database);
2001-05-23 15:26:42 +02:00
}
// otherwise make one more effort to start the transaction
2001-05-23 15:26:42 +02:00
else if (!gds_trans)
2001-05-23 15:26:42 +02:00
{
START_TRANSACTION
ON_ERROR
ERRQ_database_error(database, status_vector);
END_ERROR;
}
database->dbb_meta_trans = gds_trans;
return gds_trans;
2001-05-23 15:26:42 +02:00
}
void MET_modify_field( DBB database, QLI_FLD field)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T _ m o d i f y _ f i e l d
*
**************************************
*
* Functional description
* Modify an existing global field.
*
**************************************/
TEXT *p;
database = setup_update(database);
SYM field_name = field->fld_name;
SSHORT flag = 0;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE database->dbb_requests[REQ_modify_fld])
X IN DB.RDB$FIELDS WITH X.RDB$FIELD_NAME EQ field_name->sym_string
if (field->fld_dtype &&
(X.RDB$FIELD_TYPE == blr_blob || blr_dtypes[field->fld_dtype] == blr_blob) &&
X.RDB$FIELD_TYPE != blr_dtypes[field->fld_dtype])
{
flag = -1;
}
else
{
flag = 1;
MODIFY X USING
if (field->fld_dtype) {
X.RDB$FIELD_TYPE = blr_dtypes[field->fld_dtype];
X.RDB$FIELD_SCALE = field->fld_scale;
X.RDB$FIELD_LENGTH = (field->fld_dtype == dtype_varying) ?
field->fld_length -
sizeof(SSHORT) : field->fld_length;
}
if (!field->fld_sub_type_missing) {
X.RDB$FIELD_SUB_TYPE.NULL = FALSE;
X.RDB$FIELD_SUB_TYPE = field->fld_sub_type;
}
SYM asymbol = field->fld_query_name;
if (asymbol) {
2001-05-23 15:26:42 +02:00
X.RDB$QUERY_NAME.NULL = FALSE;
strcpy(X.RDB$QUERY_NAME, asymbol->sym_string);
2001-05-23 15:26:42 +02:00
}
if (field->fld_edit_string) {
X.RDB$EDIT_STRING.NULL = FALSE;
strcpy(X.RDB$EDIT_STRING, field->fld_edit_string);
}
END_MODIFY
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
}
END_FOR
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
if (flag <= 0)
{
rollback_update(database);
// Msg245 global field %s is not defined
// Msg468 Datatype of field %s may not be changed to or from blob
2001-05-23 15:26:42 +02:00
const USHORT nErr = flag ? 468 : 245;
ERRQ_print_error(flag, field_name->sym_string, NULL, NULL, NULL, NULL);
}
MET_meta_commit(database);
// Now go back and re-fetch fields for affected databases
2001-05-23 15:26:42 +02:00
setup_update(database);
FOR(REQUEST_HANDLE database->dbb_requests[REQ_update_fld])
X IN DB.RDB$RELATION_FIELDS WITH X.RDB$FIELD_SOURCE EQ
field_name->sym_string REDUCED TO X.RDB$RELATION_NAME
p = X.RDB$RELATION_NAME;
2001-05-23 15:26:42 +02:00
while (*p && *p != ' ') {
p++;
}
SYM symbol = HSH_lookup(X.RDB$RELATION_NAME, p - X.RDB$RELATION_NAME);
2001-05-23 15:26:42 +02:00
for (; symbol; symbol = symbol->sym_homonym)
{
QLI_REL relation;
2001-05-23 15:26:42 +02:00
if (symbol->sym_type == SYM_relation &&
(relation = (QLI_REL) symbol->sym_object) &&
2001-05-23 15:26:42 +02:00
relation->rel_database == database)
{
delete_fields(relation);
MET_fields(relation);
}
}
END_FOR
ON_ERROR
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
}
void MET_modify_index( SYN node)
{
/**************************************
*
* M E T _ m o d i f y _ i n d e x
*
**************************************
*
* Functional description
* Change the changeable options
* of an index.
*
**************************************/
NAM name = (NAM) node->syn_arg[s_mfi_name];
DBB database = (DBB) node->syn_arg[s_mfi_database];
2001-05-23 15:26:42 +02:00
database = setup_update(database);
USHORT count = 0;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE database->dbb_requests[REQ_mdf_index])
X IN DB.RDB$INDICES WITH X.RDB$INDEX_NAME = name->nam_string
MODIFY X USING
if (node->syn_flags & s_dfi_flag_selectivity)
X.RDB$UNIQUE_FLAG = (node->syn_flags & s_dfi_flag_unique);
if (node->syn_flags & s_dfi_flag_activity)
X.RDB$INDEX_INACTIVE =
(node->syn_flags & s_dfi_flag_inactive);
if (node->syn_flags & s_dfi_flag_order)
X.RDB$INDEX_TYPE =
(node->syn_flags & s_dfi_flag_descending) ? TRUE : FALSE;
if (node->syn_flags & s_dfi_flag_statistics)
X.RDB$STATISTICS = -1.0;
END_MODIFY
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
count++;
END_FOR
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
if (!count)
ERRQ_print_error(246, name->nam_string, database->dbb_filename, NULL,
NULL, NULL); // Msg246 Index %s does not exist
2001-05-23 15:26:42 +02:00
MET_meta_commit(database);
}
void MET_modify_relation( QLI_REL relation, QLI_FLD fields)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T _ m o d i f y _ r e l a t i o n
*
**************************************
*
* Functional description
* Modify an existing relation.
*
**************************************/
DBB database = setup_update(relation->rel_database);
relation->rel_database = database;
SYM relation_name = relation->rel_symbol;
2001-05-23 15:26:42 +02:00
for (QLI_FLD field = fields; field; field = field->fld_next)
{
2001-05-23 15:26:42 +02:00
if (field->fld_flags & FLD_drop) {
USHORT count = 0;
SYM field_name = field->fld_name;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE database->dbb_requests[REQ_modify_rel])
X IN DB.RDB$RELATION_FIELDS WITH
X.RDB$FIELD_NAME EQ field_name->sym_string AND
X.RDB$RELATION_NAME EQ relation_name->sym_string
2001-05-23 15:26:42 +02:00
count++;
ERASE X
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
END_FOR
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
if (!count) {
rollback_update(database);
ERRQ_print_error(247, field_name->sym_string, NULL, NULL,
NULL, NULL); // Msg247 field %s doesn't exist
2001-05-23 15:26:42 +02:00
}
}
else if (field->fld_flags & FLD_modify)
change_field(relation, field);
else
add_field(relation, field, 0);
}
2001-05-23 15:26:42 +02:00
MET_meta_commit(database);
setup_update(database);
delete_fields(relation);
MET_fields(relation);
}
void MET_ready( SYN node, USHORT create_flag)
{
/**************************************
*
* M E T _ r e a d y
*
**************************************
*
* Functional description
* Create or Ready one or more databases. If any
* fail, all fail. Fair enough?
*
**************************************/
UCHAR* p = global_parm_buffer;
DBB temp = (DBB) node->syn_arg[0];
2001-05-23 15:26:42 +02:00
/* Only a SQL CREATE DATABASE will have a pagesize parameter,
so only looking at the first pointer is justified. */
*p++ = gds_dpb_version1;
2001-05-23 15:26:42 +02:00
SSHORT length;
const TEXT* lc_ctype = QLI_charset;
if (lc_ctype && (length = strlen(lc_ctype))) {
*p++ = gds_dpb_lc_ctype;
2001-05-23 15:26:42 +02:00
*p++ = length;
while (*lc_ctype)
*p++ = *lc_ctype++;
}
if (QLI_trace) {
*p++ = gds_dpb_trace;
2001-05-23 15:26:42 +02:00
*p++ = 1;
*p++ = 1;
}
if (sw_buffers) {
*p++ = gds_dpb_num_buffers;
2001-05-23 15:26:42 +02:00
*p++ = 2;
*p++ = sw_buffers % 256;
*p++ = sw_buffers / 256;
}
if (temp->dbb_pagesize) {
*p++ = gds_dpb_page_size;
2001-05-23 15:26:42 +02:00
*p++ = 2;
*p++ = temp->dbb_pagesize % 256;
*p++ = temp->dbb_pagesize / 256;
}
/* get a username, if specified globally or on
the command line */
const TEXT* q;
2001-05-23 15:26:42 +02:00
if (temp->dbb_user) {
q = (TEXT *) temp->dbb_user->con_data;
length = temp->dbb_user->con_desc.dsc_length;
}
else {
q = QLI_default_user;
length = strlen(QLI_default_user);
}
if (length) {
*p++ = gds_dpb_user_name;
2001-05-23 15:26:42 +02:00
*p++ = length;
while (length--)
*p++ = *q++;
}
// get a password, if specified
2001-05-23 15:26:42 +02:00
if (temp->dbb_password) {
q = (TEXT *) temp->dbb_password->con_data;
length = temp->dbb_password->con_desc.dsc_length;
}
else {
q = QLI_default_password;
length = strlen(QLI_default_password);
}
if (length) {
*p++ = gds_dpb_password;
2001-05-23 15:26:42 +02:00
*p++ = length;
while (length--)
*p++ = *q++;
}
USHORT dpb_length = p - global_parm_buffer;
UCHAR* dpb;
2001-05-23 15:26:42 +02:00
if (dpb_length == 1) {
dpb = NULL;
dpb_length = 0;
}
else
dpb = global_parm_buffer;
2001-05-23 15:26:42 +02:00
SYN* const end = node->syn_arg + node->syn_count;
2001-05-23 15:26:42 +02:00
// Start by attaching all databases
ISC_STATUS_ARRAY status_vector;
SYN* ptr;
DBB dbb;
2001-05-23 15:26:42 +02:00
for (ptr = node->syn_arg; ptr < end; ptr++) {
dbb = (DBB) *ptr;
2001-05-23 15:26:42 +02:00
if (create_flag)
2003-08-30 04:12:44 +02:00
gds__create_database(status_vector, 0, dbb->dbb_filename,
&dbb->dbb_handle, dpb_length, (char*) dpb, 0);
2001-05-23 15:26:42 +02:00
else
2003-08-30 04:12:44 +02:00
gds__attach_database(status_vector, 0, dbb->dbb_filename,
&dbb->dbb_handle, dpb_length, (char*) dpb);
2001-05-23 15:26:42 +02:00
if (status_vector[1])
break;
}
// If any attach failed, cleanup and give up
2001-05-23 15:26:42 +02:00
if (ptr < end) {
for (SYN* ptr2 = node->syn_arg; ptr2 < ptr; ptr2++)
detach(gds_status, (DBB) *ptr2);
2001-05-23 15:26:42 +02:00
ERRQ_database_error(dbb, status_vector);
}
// Databases are up and running. Install each.
2001-05-23 15:26:42 +02:00
for (ptr = node->syn_arg; ptr < end; ptr++)
install((DBB) *ptr);
2001-05-23 15:26:42 +02:00
}
void MET_shutdown(void)
{
/**************************************
*
* M E T _ s h u t d o w n
*
**************************************
*
* Functional description
* Shut down all attached databases.
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
for (DBB dbb = QLI_databases; dbb; dbb = dbb->dbb_next)
2001-05-23 15:26:42 +02:00
if (detach(status_vector, dbb))
gds__print_status(status_vector);
}
void MET_sql_alter_table( QLI_REL relation, QLI_FLD fields)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T _ s q l _ a l t e r _ t a b l e
*
**************************************
*
* Functional description
* Alter table data based on a SQL metadata request
*
**************************************/
SYM symbol = relation->rel_symbol;
DBB database = setup_update(relation->rel_database);
relation->rel_database = database;
USHORT count = 0;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE database->dbb_requests[REQ_relation_def])
X IN DB.RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ symbol->sym_string
count++;
END_FOR
ON_ERROR
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
if (!count)
ERRQ_print_error(414, symbol->sym_string, NULL, NULL, NULL, NULL); // Msg237 Relation %s is lost
2001-05-23 15:26:42 +02:00
RLB rlb = NULL;
2001-05-23 15:26:42 +02:00
rlb = CHECK_RLB(rlb);
STUFF(gds_dyn_version_1);
STUFF(gds_dyn_begin);
STUFF(gds_dyn_mod_rel);
2001-05-23 15:26:42 +02:00
STUFF_STRING(symbol->sym_string);
for (QLI_FLD field = fields; field; field = field->fld_next) {
2001-05-23 15:26:42 +02:00
if (field->fld_flags & FLD_add)
add_sql_field(relation, field, 0, rlb);
else if (field->fld_flags & FLD_drop) {
STUFF(gds_dyn_delete_local_fld);
2001-05-23 15:26:42 +02:00
STUFF_STRING(field->fld_name->sym_string);
STUFF(gds_dyn_end);
2001-05-23 15:26:42 +02:00
}
}
STUFF(gds_dyn_end);
STUFF(gds_dyn_end);
STUFF(gds_dyn_eoc);
2001-05-23 15:26:42 +02:00
execute_dynamic_ddl(database, rlb);
MET_meta_commit(database);
setup_update(database);
delete_fields(relation);
MET_fields(relation);
}
void MET_sql_cr_view( SYN node)
{
/**************************************
*
* M E T _ s q l _ c r _ v i e w
*
**************************************
*
* Functional description
* Create a view from a SQL metadata request
*
**************************************/
QLI_REL relation = (QLI_REL) node->syn_arg[s_crv_name];
DBB database = setup_update(relation->rel_database);
relation->rel_database = database;
SYM symbol = relation->rel_symbol;
2001-05-23 15:26:42 +02:00
RLB rlb = NULL;
2001-05-23 15:26:42 +02:00
rlb = CHECK_RLB(rlb);
STUFF(gds_dyn_version_1);
STUFF(gds_dyn_begin);
2001-05-23 15:26:42 +02:00
STUFF(gds_dyn_def_view);
2001-05-23 15:26:42 +02:00
STUFF_STRING(symbol->sym_string);
// The meat of the blr generation will go here
2001-05-23 15:26:42 +02:00
STUFF(gds_dyn_end);
STUFF(gds_dyn_eoc);
2001-05-23 15:26:42 +02:00
execute_dynamic_ddl(database, rlb);
MET_meta_commit(database);
}
void MET_sql_grant( SYN node)
{
/**************************************
*
* M E T _ s q l _ g r a n t
*
**************************************
*
* Functional description
* Grant access privilege(s) on a SQL table
*
**************************************/
sql_grant_revoke(node, gds_dyn_grant);
2001-05-23 15:26:42 +02:00
}
void MET_sql_revoke( SYN node)
{
/**************************************
*
* M E T _ s q l _ r e v o k e
*
**************************************
*
* Functional description
* Revoke access privilege(s) on a SQL table
*
**************************************/
sql_grant_revoke(node, gds_dyn_revoke);
2001-05-23 15:26:42 +02:00
}
FRBRD *MET_transaction( NOD_T node_type, DBB database)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M E T _ t r a n s a c t i o n
*
**************************************
*
* Functional description
* Finish off a transaction with a commit, prepare, or rollback.
* For commit and rollback, start a new transaction.
*
* Multiple transaction coordination is handled
* by the caller. This is a singleminded routine.
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
switch (node_type) {
case nod_commit:
2003-08-30 04:12:44 +02:00
gds__commit_transaction(status_vector, &database->dbb_transaction);
2001-05-23 15:26:42 +02:00
break;
case nod_rollback:
2003-08-30 04:12:44 +02:00
gds__rollback_transaction(status_vector, &database->dbb_transaction);
2001-05-23 15:26:42 +02:00
break;
case nod_prepare:
2003-08-30 04:12:44 +02:00
gds__prepare_transaction(status_vector, &database->dbb_transaction);
2001-05-23 15:26:42 +02:00
break;
case nod_start_trans:
2003-08-30 04:12:44 +02:00
gds__start_transaction(status_vector, &database->dbb_transaction, 1,
&database->dbb_handle, sizeof(tpb), tpb);
2001-05-23 15:26:42 +02:00
database->dbb_flags &= ~DBB_updates & ~DBB_prepared;
break;
}
if (status_vector[1])
ERRQ_database_error(database, status_vector);
return database->dbb_transaction;
2001-05-23 15:26:42 +02:00
}
static void add_field( QLI_REL relation, QLI_FLD field, USHORT position)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* a d d _ f i e l d
*
**************************************
*
* Functional description
* Add a field to a relation. Do all sorts of sanity checks.
*
**************************************/
DBB database = relation->rel_database;
SYM relation_name = relation->rel_symbol;
SYM field_name = field->fld_name;
SYM global_field = field->fld_based;
if (!global_field)
2001-05-23 15:26:42 +02:00
global_field = field_name;
// Check to see if it already exits in relation
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE database->dbb_requests[REQ_rfr_def])
X IN DB.RDB$RELATION_FIELDS WITH
X.RDB$RELATION_NAME EQ relation_name->sym_string AND
X.RDB$FIELD_NAME EQ field_name->sym_string
rollback_update(relation->rel_database);
ERRQ_print_error(251, field_name->sym_string,
relation_name->sym_string, NULL, NULL, NULL); // Msg251 Field %s already exists in relation %s
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
// Check global field. Define it if it doesn't exist.
2001-05-23 15:26:42 +02:00
bool global_flag = false;
2001-05-23 15:26:42 +02:00
if (!check_global_field(database, field, global_field->sym_string)) {
2003-09-10 19:52:12 +02:00
global_flag = true;
2001-05-23 15:26:42 +02:00
define_global_field(database, field, global_field);
}
/* Finally, store into RFR. If we defined a global field, assume that
the query name and edit string will be inherited from there, otherwise
include them here */
STORE(REQUEST_HANDLE database->dbb_requests[REQ_store_rfr])
X IN DB.RDB$RELATION_FIELDS
strcpy(X.RDB$RELATION_NAME, relation_name->sym_string);
strcpy(X.RDB$FIELD_NAME, field_name->sym_string);
strcpy(X.RDB$FIELD_SOURCE, global_field->sym_string);
if (position) {
X.RDB$FIELD_POSITION.NULL = FALSE;
X.RDB$FIELD_POSITION = position;
}
else
X.RDB$FIELD_POSITION.NULL = TRUE;
SYM symbol;
2001-05-23 15:26:42 +02:00
if (!global_flag && (symbol = field->fld_query_name)) {
X.RDB$QUERY_NAME.NULL = FALSE;
strcpy(X.RDB$QUERY_NAME, symbol->sym_string);
}
else
X.RDB$QUERY_NAME.NULL = TRUE;
if (!global_flag && (field->fld_edit_string)) {
X.RDB$EDIT_STRING.NULL = FALSE;
strcpy(X.RDB$EDIT_STRING, field->fld_edit_string);
}
else
X.RDB$EDIT_STRING.NULL = TRUE;
END_STORE
ON_ERROR
rollback_update(relation->rel_database);
ERRQ_database_error(relation->rel_database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
}
static void add_sql_field( QLI_REL relation, QLI_FLD field, USHORT position, RLB rlb)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* a d d _ s q l _ f i e l d
*
**************************************
*
* Functional description
* Add a SQL field to a relation via dyn.
*
**************************************/
rlb = CHECK_RLB(rlb);
DBB database = relation->rel_database;
SYM relation_name = relation->rel_symbol;
SYM field_name = field->fld_name;
2001-05-23 15:26:42 +02:00
// Check to see if it already exits in relation
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE database->dbb_requests[REQ_rfr_def])
X IN DB.RDB$RELATION_FIELDS WITH
X.RDB$RELATION_NAME EQ relation_name->sym_string AND
X.RDB$FIELD_NAME EQ field_name->sym_string
rollback_update(relation->rel_database);
ERRQ_print_error(251, field_name->sym_string,
relation_name->sym_string, NULL, NULL, NULL); // Msg251 Field %s already exists in relation %s
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
STUFF(gds_dyn_def_sql_fld);
2001-05-23 15:26:42 +02:00
STUFF_STRING(field->fld_name->sym_string);
STUFF(gds_dyn_fld_type);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(blr_dtypes[field->fld_dtype]);
STUFF(gds_dyn_fld_length);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
const USHORT l = (field->fld_dtype == dtype_varying)
? field->fld_length - sizeof(SSHORT) : field->fld_length;
2001-05-23 15:26:42 +02:00
STUFF_WORD(l);
STUFF(gds_dyn_fld_scale);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(field->fld_scale);
if (position) {
STUFF(gds_dyn_fld_position);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(position);
}
rlb = CHECK_RLB(rlb);
if (field->fld_flags & FLD_not_null) {
STUFF(gds_dyn_fld_validation_blr);
2001-05-23 15:26:42 +02:00
STUFF_WORD(8);
STUFF(blr_version4);
STUFF(blr_not);
STUFF(blr_missing);
STUFF(blr_fid);
STUFF(0);
STUFF(0);
STUFF(0);
STUFF(blr_eoc);
}
STUFF(gds_dyn_end);
2001-05-23 15:26:42 +02:00
}
static int blob_copy( RLB rlb, QLI_REL source, SLONG * source_blob_id)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* b l o b _ c o p y
*
**************************************
*
* Functional description
* Copy information from one blob to a request
* language block to stick it into a new definition.
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
DBB source_dbb =
2001-05-23 15:26:42 +02:00
(source->rel_database) ? source->rel_database : QLI_databases;
DB = source_dbb->dbb_handle;
FRBRD* source_blob = NULL;
2001-05-23 15:26:42 +02:00
2003-08-30 04:12:44 +02:00
if (gds__open_blob(status_vector, &DB, &source_dbb->dbb_meta_trans,
&source_blob, (GDS__QUAD*) source_blob_id)) {
rollback_update((DBB) DB);
2001-05-23 15:26:42 +02:00
ERRQ_database_error(source_dbb, status_vector);
}
SLONG size, segment_count, max_segment;
gds__blob_size(&source_blob, (SLONG*) &size, &segment_count, &max_segment);
2001-05-23 15:26:42 +02:00
TEXT fixed_buffer[4096];
TEXT* buffer;
USHORT buffer_length;
2001-05-23 15:26:42 +02:00
if (max_segment < sizeof(fixed_buffer)) {
buffer_length = sizeof(fixed_buffer);
buffer = fixed_buffer;
}
else {
buffer_length = max_segment;
buffer = (TEXT *) gds__alloc((SLONG) buffer_length);
}
STUFF_WORD((USHORT) size);
USHORT length;
2003-08-30 04:12:44 +02:00
while (!gds__get_segment(status_vector, &source_blob, &length,
buffer_length, buffer))
{
2001-05-23 15:26:42 +02:00
while (rlb->rlb_limit - rlb->rlb_data < length)
rlb = GEN_rlb_extend(rlb);
const TEXT* p = buffer;
2001-05-23 15:26:42 +02:00
while (length--)
STUFF(*p++);
}
if (status_vector[1] != gds_segstr_eof) {
rollback_update((DBB) DB);
2001-05-23 15:26:42 +02:00
if (buffer != fixed_buffer)
gds__free(buffer);
ERRQ_database_error(source_dbb, status_vector);
}
if (buffer != fixed_buffer)
gds__free(buffer);
2003-08-30 04:12:44 +02:00
if (gds__close_blob(status_vector, &source_blob)) {
rollback_update((DBB) DB);
2001-05-23 15:26:42 +02:00
ERRQ_database_error(source_dbb, status_vector);
}
return TRUE;
}
static void change_field( QLI_REL relation, QLI_FLD field)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c h a n g e _ f i e l d
*
**************************************
*
* Functional description
* Change optional attributes of a field.
*
**************************************/
DBB database = relation->rel_database;
SYM relation_name = relation->rel_symbol;
SYM field_name = field->fld_name;
SYM global_field = field->fld_based;
2001-05-23 15:26:42 +02:00
if (field->fld_dtype) {
rollback_update(database);
ERRQ_print_error(252, NULL, NULL, NULL, NULL, NULL);
// Msg252 datatype can not be changed locally
2001-05-23 15:26:42 +02:00
}
if (global_field
&&
!(check_global_field(database, NULL, global_field->sym_string)))
{
2001-05-23 15:26:42 +02:00
rollback_update(database);
ERRQ_print_error(253, global_field->sym_string, NULL, NULL, NULL, NULL);
// Msg253 global field %s does not exist
2001-05-23 15:26:42 +02:00
}
// Modify RFR
USHORT count = 0;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE database->dbb_requests[REQ_mdf_rfr])
X IN DB.RDB$RELATION_FIELDS WITH
X.RDB$RELATION_NAME = relation_name->sym_string AND
X.RDB$FIELD_NAME = field_name->sym_string
2001-05-23 15:26:42 +02:00
count++;
MODIFY X USING
if (global_field)
strcpy(X.RDB$FIELD_SOURCE, global_field->sym_string);
SYM symbol = field->fld_query_name;
if (symbol)
2001-05-23 15:26:42 +02:00
strcpy(X.RDB$QUERY_NAME, symbol->sym_string);
if (field->fld_edit_string)
strcpy(X.RDB$EDIT_STRING, field->fld_edit_string);
END_MODIFY
ON_ERROR
rollback_update(relation->rel_database);
ERRQ_database_error(relation->rel_database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
END_FOR
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
if (!count) {
rollback_update(database);
ERRQ_print_error(254, field_name->sym_string,
relation_name->sym_string, NULL, NULL, NULL); // Msg254 field %s not found in relation %s
2001-05-23 15:26:42 +02:00
}
}
2003-09-10 19:52:12 +02:00
static bool check_global_field(DBB database,
QLI_FLD field,
TEXT * name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c h e c k _ g l o b a l _ f i e l d
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Given a name, check for the existence of a global field
* by that name. If a QLI_FLD block is supplied,
2001-05-23 15:26:42 +02:00
* check its characteristics against the global.
* If it is not fully defined, flesh it out from the global.
*
**************************************/
2003-09-10 19:52:12 +02:00
bool previously_defined = false;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE database->dbb_requests[REQ_field_def])
X IN DB.RDB$FIELDS WITH X.RDB$FIELD_NAME EQ name
2001-05-23 15:26:42 +02:00
if (field)
{
if (field->fld_dtype &&
(X.RDB$FIELD_TYPE != blr_dtypes[field->fld_dtype] ||
X.RDB$FIELD_LENGTH !=
((field->fld_dtype == dtype_varying) ? field->fld_length -
sizeof(SSHORT) : field->fld_length) ||
X.RDB$FIELD_SCALE != field->fld_scale))
{
rollback_update(database);
ERRQ_print_error(255, name, NULL, NULL, NULL, NULL); // Msg255 Datatype conflict with existing global field %s
2001-05-23 15:26:42 +02:00
}
field->fld_dtype = MET_get_datatype(X.RDB$FIELD_TYPE);
field->fld_length =
field_length(field->fld_dtype, X.RDB$FIELD_LENGTH);
if (field->fld_dtype == dtype_varying) {
field->fld_length += sizeof(SSHORT);
}
field->fld_scale = X.RDB$FIELD_SCALE;
field->fld_sub_type = X.RDB$FIELD_SUB_TYPE;
field->fld_sub_type_missing = X.RDB$FIELD_SUB_TYPE.NULL;
if (!field->fld_edit_string)
{
field->fld_edit_string =
make_string(X.RDB$EDIT_STRING, sizeof(X.RDB$EDIT_STRING));
}
if (!field->fld_query_name)
{
field->fld_query_name =
make_symbol(X.RDB$QUERY_NAME, sizeof(X.RDB$QUERY_NAME));
}
if (!field->fld_query_header)
{
SLONG* blob = (SLONG *) &X.RDB$QUERY_HEADER;
2001-05-23 15:26:42 +02:00
if (blob[0] || blob[1])
{
field->fld_query_header =
get_query_header(database, blob);
}
}
}
2003-09-10 19:52:12 +02:00
previously_defined = true;
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
return previously_defined;
}
2003-09-10 19:52:12 +02:00
static bool check_relation( QLI_REL relation)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c h e c k _ r e l a t i o n
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Check the existence of the named relation.
*
**************************************/
2003-09-10 19:52:12 +02:00
bool previously_defined = false;
FRBRD* spare = DB;
2001-05-23 15:26:42 +02:00
DB = relation->rel_database->dbb_handle;
FOR(REQUEST_HANDLE relation->rel_database->dbb_requests[REQ_relation_def]
TRANSACTION_HANDLE relation->rel_database->dbb_meta_trans)
X IN DB.RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ relation->rel_symbol->sym_string
2003-09-10 19:52:12 +02:00
previously_defined = true;
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
ERRQ_database_error(relation->rel_database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
DB = spare;
return previously_defined;
}
static int clone_fields( QLI_REL target, QLI_REL source)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c l o n e _ f i e l d s
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Copy the RFR records for one relation
* into another. The target database is already
* setup for updates. If there is a different source
* database, get it ready too. Then make sure that
* the source relation actually exists.
*
* If it's two different databases, create the global
* fields that are missing in the target (except those
* that support computed fields), then create the local
2001-05-23 15:26:42 +02:00
* fields and during that pass create the computed
* fields and the SQL fields.
*
**************************************/
FRBRD *req1, *req2;
FRBRD *t_trans, *s_trans;
2001-05-23 15:26:42 +02:00
req1 = req2 = NULL;
s_trans = t_trans = gds_trans;
2001-05-23 15:26:42 +02:00
DB = DB1 = target->rel_database->dbb_handle;
if (target->rel_database != source->rel_database) {
MET_meta_transaction(source->rel_database, FALSE);
s_trans = gds_trans;
2001-05-23 15:26:42 +02:00
}
if (target->rel_database != source->rel_database)
clone_global_fields(target, source);
RLB rlb = NULL;
2001-05-23 15:26:42 +02:00
rlb = CHECK_RLB(rlb);
STUFF(gds_dyn_version_1);
STUFF(gds_dyn_begin);
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE req1
TRANSACTION_HANDLE s_trans)
Y IN DB.RDB$RELATION_FIELDS
CROSS F IN DB.RDB$FIELDS
WITH Y.RDB$RELATION_NAME = source->rel_symbol->sym_string
AND Y.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME
// If SQL made this field, create a new global field for it
2001-05-23 15:26:42 +02:00
if (F.RDB$COMPUTED_BLR.NULL &&
(strncmp("RDB$", Y.RDB$FIELD_NAME, 4)) &&
(!(strncmp("RDB$", F.RDB$FIELD_NAME, 4))))
{
STUFF(gds_dyn_def_sql_fld);
2001-05-23 15:26:42 +02:00
STUFF_STRING(Y.RDB$FIELD_NAME);
STUFF(gds_dyn_fld_type);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(F.RDB$FIELD_TYPE);
STUFF(gds_dyn_fld_length);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(F.RDB$FIELD_LENGTH);
STUFF(gds_dyn_fld_scale);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(F.RDB$FIELD_SCALE);
if (!F.RDB$VALIDATION_BLR.NULL) {
STUFF(gds_dyn_fld_validation_blr);
blob_copy(rlb, source, (SLONG*) &F.RDB$VALIDATION_BLR);
2001-05-23 15:26:42 +02:00
}
}
else
{
STUFF(gds_dyn_def_local_fld);
2001-05-23 15:26:42 +02:00
STUFF_STRING(Y.RDB$FIELD_NAME);
STUFF(gds_dyn_fld_source);
2001-05-23 15:26:42 +02:00
STUFF_STRING(Y.RDB$FIELD_SOURCE);
}
STUFF(gds_dyn_rel_name);
2001-05-23 15:26:42 +02:00
STUFF_STRING(target->rel_symbol->sym_string);
if (!Y.RDB$FIELD_POSITION.NULL) {
STUFF(gds_dyn_fld_position);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(Y.RDB$FIELD_POSITION);
}
if (!Y.RDB$QUERY_NAME.NULL) {
STUFF(gds_dyn_fld_query_name);
2001-05-23 15:26:42 +02:00
STUFF_STRING(Y.RDB$QUERY_NAME);
}
if (!Y.RDB$EDIT_STRING.NULL) {
STUFF(gds_dyn_fld_edit_string);
2001-05-23 15:26:42 +02:00
STUFF_STRING(Y.RDB$EDIT_STRING);
}
if (!Y.RDB$UPDATE_FLAG.NULL) {
STUFF(gds_dyn_update_flag);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(Y.RDB$UPDATE_FLAG);
}
if (!Y.RDB$QUERY_HEADER.NULL) {
STUFF(gds_dyn_fld_query_header);
blob_copy(rlb, source, (SLONG*) &Y.RDB$QUERY_HEADER);
2001-05-23 15:26:42 +02:00
}
if (!Y.RDB$DESCRIPTION.NULL) {
STUFF(gds_dyn_description);
blob_copy(rlb, source, (SLONG*) &Y.RDB$DESCRIPTION);
2001-05-23 15:26:42 +02:00
}
if (!Y.RDB$DEFAULT_VALUE.NULL) {
STUFF(gds_dyn_fld_default_value);
blob_copy(rlb, source, (SLONG*) &Y.RDB$DEFAULT_VALUE);
2001-05-23 15:26:42 +02:00
}
if ((source->rel_database->dbb_capabilities & DBB_cap_rfr_sys_flag) &&
(target->rel_database->dbb_capabilities & DBB_cap_rfr_sys_flag))
FOR(REQUEST_HANDLE req2
TRANSACTION_HANDLE s_trans)
S_RFR IN DB.RDB$RELATION_FIELDS WITH
S_RFR.RDB$FIELD_NAME = Y.RDB$FIELD_NAME AND
S_RFR.RDB$RELATION_NAME = Y.RDB$RELATION_NAME
if (!S_RFR.RDB$SYSTEM_FLAG.NULL) {
STUFF(gds_dyn_system_flag);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(S_RFR.RDB$SYSTEM_FLAG);
}
END_FOR
ON_ERROR
rollback_update(target->rel_database);
ERRQ_database_error(source->rel_database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
if (!F.RDB$COMPUTED_BLR.NULL)
{
STUFF(gds_dyn_fld_computed_blr);
blob_copy(rlb, source, (SLONG*) &F.RDB$COMPUTED_BLR);
STUFF(gds_dyn_fld_computed_source);
blob_copy(rlb, source, (SLONG*) &F.RDB$COMPUTED_SOURCE);
2001-05-23 15:26:42 +02:00
STUFF(gds_dyn_fld_type);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(F.RDB$FIELD_TYPE);
STUFF(gds_dyn_fld_length);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(F.RDB$FIELD_LENGTH);
if (!F.RDB$FIELD_SCALE.NULL) {
STUFF(gds_dyn_fld_scale);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(F.RDB$FIELD_SCALE);
}
if (!F.RDB$FIELD_SUB_TYPE.NULL) {
STUFF(gds_dyn_fld_sub_type);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(F.RDB$FIELD_SUB_TYPE);
}
}
STUFF(gds_dyn_end);
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
rollback_update(source->rel_database);
ERRQ_database_error(source->rel_database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
STUFF(gds_dyn_end);
STUFF(gds_dyn_eoc);
2001-05-23 15:26:42 +02:00
execute_dynamic_ddl(target->rel_database, rlb);
if (req1)
2003-08-30 04:12:44 +02:00
if (gds__release_request(gds_status, &req1))
ERRQ_database_error(source->rel_database, gds_status);
2001-05-23 15:26:42 +02:00
if (req2)
2003-08-30 04:12:44 +02:00
if (gds__release_request(gds_status, &req2))
ERRQ_database_error(source->rel_database, gds_status);
2001-05-23 15:26:42 +02:00
return TRUE;
}
static int clone_global_fields( QLI_REL target, QLI_REL source)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c l o n e _ g l o b a l _ f i e l d s
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Copy the global field definitions required by a relation
* from one database into another. Both databases are
* setup correctly. (Set up the handles again just because
* we're compulsive.)
2001-05-23 15:26:42 +02:00
*
* In this routine, as in clone fields, be careful to probe
* for our extensions rather than just using them so we
* can copy relations from V2 and from Rdb.
*
* Don't clone fields that already exist and have the
* correct datatype and length.
*
* Don't clone computed fields since they will be cloned
* later with the local field definitions. Don't clone
* SQL defined fields for the same reason.
*
**************************************/
FRBRD *req1, *req2, *req3;
2001-05-23 15:26:42 +02:00
req1 = req2 = req3 = NULL;
FRBRD* s_trans = source->rel_database->dbb_meta_trans;
FRBRD* t_trans = target->rel_database->dbb_meta_trans;
2001-05-23 15:26:42 +02:00
DB = source->rel_database->dbb_handle;
DB1 = target->rel_database->dbb_handle;
RLB rlb = NULL;
bool first_field = true;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE req1
TRANSACTION_HANDLE s_trans)
RFR IN DB.RDB$RELATION_FIELDS CROSS
Y IN DB.RDB$FIELDS
WITH RFR.RDB$RELATION_NAME = source->rel_symbol->sym_string AND
Y.RDB$FIELD_NAME = RFR.RDB$FIELD_SOURCE REDUCED TO Y.RDB$FIELD_NAME
2001-05-23 15:26:42 +02:00
if (!Y.RDB$COMPUTED_BLR.NULL ||
((strncmp("RDB$",RFR.RDB$FIELD_NAME,4)) &&
(!(strncmp("RDB$", Y.RDB$FIELD_NAME,4)))))
continue;
bool predefined = false;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE req2 TRANSACTION_HANDLE t_trans)
A IN DB1.RDB$FIELDS WITH A.RDB$FIELD_NAME = Y.RDB$FIELD_NAME
if ((A.RDB$FIELD_TYPE != Y.RDB$FIELD_TYPE) ||
(A.RDB$FIELD_LENGTH != Y.RDB$FIELD_LENGTH) ||
(A.RDB$FIELD_SCALE.NULL != Y.RDB$FIELD_SCALE.NULL) ||
((!Y.RDB$FIELD_SCALE.NULL) &&
(A.RDB$FIELD_SCALE != Y.RDB$FIELD_SCALE)) ||
(A.RDB$FIELD_SUB_TYPE.NULL != Y.RDB$FIELD_SUB_TYPE.NULL)
|| ((!Y.RDB$FIELD_SUB_TYPE.NULL)
&& (A.RDB$FIELD_SUB_TYPE != Y.RDB$FIELD_SUB_TYPE)))
{
2001-05-23 15:26:42 +02:00
TEXT* name = (TEXT*) ALLQ_malloc((SLONG) sizeof(Y.RDB$FIELD_NAME));
strcpy(name, Y.RDB$FIELD_NAME);
rollback_update(target->rel_database);
// CVC: When is this memory deallocated?
ERRQ_error(413, name, NULL, NULL, NULL, NULL);
// conflicting previous definition
}
2001-05-23 15:26:42 +02:00
else
predefined = true;
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
ERRQ_database_error(target->rel_database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
if (predefined)
continue;
if (first_field) {
rlb = CHECK_RLB(rlb);
STUFF(gds_dyn_version_1);
STUFF(gds_dyn_begin);
first_field = false;
2001-05-23 15:26:42 +02:00
}
STUFF(gds_dyn_def_global_fld);
2001-05-23 15:26:42 +02:00
STUFF_STRING(Y.RDB$FIELD_NAME);
STUFF(gds_dyn_fld_type);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(Y.RDB$FIELD_TYPE);
STUFF(gds_dyn_fld_length);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(Y.RDB$FIELD_LENGTH);
if (!Y.RDB$FIELD_SCALE.NULL) {
STUFF(gds_dyn_fld_scale);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(Y.RDB$FIELD_SCALE);
}
if (!Y.RDB$FIELD_SUB_TYPE.NULL) {
STUFF(gds_dyn_fld_sub_type);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(Y.RDB$FIELD_SUB_TYPE);
}
if (!Y.RDB$SEGMENT_LENGTH.NULL) {
STUFF(gds_dyn_fld_segment_length);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(Y.RDB$SEGMENT_LENGTH);
}
if (!Y.RDB$SYSTEM_FLAG.NULL) {
STUFF(gds_dyn_system_flag);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(Y.RDB$SYSTEM_FLAG);
}
if (!Y.RDB$QUERY_NAME.NULL) {
STUFF(gds_dyn_fld_query_name);
2001-05-23 15:26:42 +02:00
STUFF_STRING(Y.RDB$QUERY_NAME);
}
if (!Y.RDB$EDIT_STRING.NULL) {
STUFF(gds_dyn_fld_edit_string);
2001-05-23 15:26:42 +02:00
STUFF_STRING(Y.RDB$EDIT_STRING);
}
if (!Y.RDB$MISSING_VALUE.NULL) {
STUFF(gds_dyn_fld_missing_value);
blob_copy(rlb, source, (SLONG*) &Y.RDB$MISSING_VALUE);
2001-05-23 15:26:42 +02:00
}
if (!Y.RDB$DEFAULT_VALUE.NULL) {
STUFF(gds_dyn_fld_default_value);
blob_copy(rlb, source, (SLONG*) &Y.RDB$DEFAULT_VALUE);
2001-05-23 15:26:42 +02:00
}
if (!Y.RDB$QUERY_HEADER.NULL) {
STUFF(gds_dyn_fld_query_header);
blob_copy(rlb, source, (SLONG*) &Y.RDB$QUERY_HEADER);
2001-05-23 15:26:42 +02:00
}
if (!Y.RDB$DESCRIPTION.NULL) {
STUFF(gds_dyn_description);
blob_copy(rlb, source, (SLONG*) &Y.RDB$DESCRIPTION);
2001-05-23 15:26:42 +02:00
}
if (!Y.RDB$VALIDATION_BLR.NULL) {
STUFF(gds_dyn_fld_validation_blr);
blob_copy(rlb, source, (SLONG*) &Y.RDB$VALIDATION_BLR);
2001-05-23 15:26:42 +02:00
}
if (!Y.RDB$VALIDATION_SOURCE.NULL) {
STUFF(gds_dyn_fld_validation_source);
blob_copy(rlb, source, (SLONG*) &Y.RDB$VALIDATION_SOURCE);
2001-05-23 15:26:42 +02:00
}
if ((target->rel_database->dbb_capabilities & DBB_cap_dimensions) &&
(source->rel_database->dbb_capabilities & DBB_cap_dimensions)) {
bool first_dimension = true;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE req3 TRANSACTION_HANDLE s_trans)
F IN DB.RDB$FIELDS CROSS
D IN DB.RDB$FIELD_DIMENSIONS
WITH F.RDB$FIELD_NAME = D.RDB$FIELD_NAME AND
F.RDB$FIELD_NAME = Y.RDB$FIELD_NAME
2001-05-23 15:26:42 +02:00
if (first_dimension) {
first_dimension = false;
STUFF(gds_dyn_fld_dimensions);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(F.RDB$DIMENSIONS);
}
2001-05-23 15:26:42 +02:00
STUFF(gds_dyn_def_dimension);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(D.RDB$DIMENSION);
if (!D.RDB$LOWER_BOUND.NULL) {
STUFF(gds_dyn_dim_lower);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(D.RDB$LOWER_BOUND);
}
if (!D.RDB$UPPER_BOUND.NULL) {
STUFF(gds_dyn_dim_upper);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(D.RDB$UPPER_BOUND);
}
STUFF(gds_dyn_end);
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
if (target->rel_database->dbb_meta_trans)
rollback_update(target->rel_database);
rollback_update((DBB) source->rel_database->dbb_meta_trans);
ERRQ_database_error(source->rel_database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
}
STUFF(gds_dyn_end);
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
rollback_update(source->rel_database);
if (target->rel_database->dbb_meta_trans)
rollback_update(target->rel_database);
ERRQ_database_error(source->rel_database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
if (rlb) {
STUFF(gds_dyn_end);
STUFF(gds_dyn_eoc);
2001-05-23 15:26:42 +02:00
execute_dynamic_ddl(target->rel_database, rlb);
}
if (req1)
2003-08-30 04:12:44 +02:00
if (gds__release_request(gds_status, &req1))
ERRQ_database_error(source->rel_database, gds_status);
2001-05-23 15:26:42 +02:00
if (req2)
2003-08-30 04:12:44 +02:00
if (gds__release_request(gds_status, &req2))
ERRQ_database_error(target->rel_database, gds_status);
2001-05-23 15:26:42 +02:00
if (req3)
2003-08-30 04:12:44 +02:00
if (gds__release_request(gds_status, &req3))
ERRQ_database_error(source->rel_database, gds_status);
2001-05-23 15:26:42 +02:00
return TRUE;
}
static void define_global_field( DBB database, QLI_FLD field, SYM name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e f i n e _ g l o b a l _ f i e l d
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
*
* Define a global field if we've got enough
* information.
*
**************************************/
if (!field->fld_dtype) {
rollback_update(database);
ERRQ_print_error(256, name->sym_string, NULL, NULL, NULL, NULL); // Msg256 No datatype specified for field %s
2001-05-23 15:26:42 +02:00
}
2001-05-23 15:26:42 +02:00
STORE(REQUEST_HANDLE database->dbb_requests[REQ_store_field])
X IN DB.RDB$FIELDS
2001-05-23 15:26:42 +02:00
strcpy(X.RDB$FIELD_NAME, name->sym_string);
X.RDB$FIELD_TYPE = blr_dtypes[field->fld_dtype];
X.RDB$FIELD_SCALE = field->fld_scale;
X.RDB$FIELD_LENGTH = (field->fld_dtype == dtype_varying) ?
field->fld_length - sizeof(SSHORT) : field->fld_length;
if (!field->fld_sub_type_missing) {
X.RDB$FIELD_SUB_TYPE.NULL = FALSE;
X.RDB$FIELD_SUB_TYPE = field->fld_sub_type;
}
else
X.RDB$FIELD_SUB_TYPE.NULL = TRUE;
SYM symbol = field->fld_query_name;
if (symbol) {
2001-05-23 15:26:42 +02:00
X.RDB$QUERY_NAME.NULL = FALSE;
strcpy(X.RDB$QUERY_NAME, symbol->sym_string);
}
else
X.RDB$QUERY_NAME.NULL = TRUE;
if (field->fld_edit_string) {
X.RDB$EDIT_STRING.NULL = FALSE;
strcpy(X.RDB$EDIT_STRING, field->fld_edit_string);
}
else
X.RDB$EDIT_STRING.NULL = TRUE;
END_STORE
ON_ERROR
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
}
static void delete_fields( QLI_REL relation)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e l e t e _ f i e l d s
*
**************************************
*
* Functional description
* Delete field definitions.
*
**************************************/
while (QLI_FLD field = relation->rel_fields) {
2001-05-23 15:26:42 +02:00
relation->rel_fields = field->fld_next;
ALL_release((FRB) field->fld_name);
2001-05-23 15:26:42 +02:00
if (field->fld_query_name)
ALL_release((FRB) field->fld_query_name);
ALL_release((FRB) field);
2001-05-23 15:26:42 +02:00
}
relation->rel_flags &= ~REL_fields;
}
2003-09-10 19:52:12 +02:00
static ISC_STATUS detach(ISC_STATUS * status_vector,
DBB dbb)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e t a c h
*
**************************************
*
* Functional description
* Shut down a database. Return the status of the
* first failing call, if any.
*
**************************************/
if (!dbb->dbb_handle)
2003-09-13 11:02:10 +02:00
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
ISC_STATUS_ARRAY alt_vector;
ISC_STATUS* status = status_vector;
2001-05-23 15:26:42 +02:00
if (dbb->dbb_transaction)
2003-08-30 04:12:44 +02:00
if (gds__commit_transaction(status, &dbb->dbb_transaction))
2001-05-23 15:26:42 +02:00
status = alt_vector;
if (dbb->dbb_proc_trans && (dbb->dbb_capabilities & DBB_cap_multi_trans))
2003-08-30 04:12:44 +02:00
if (gds__commit_transaction(status, &dbb->dbb_proc_trans))
2001-05-23 15:26:42 +02:00
status = alt_vector;
if (dbb->dbb_meta_trans && (dbb->dbb_capabilities & DBB_cap_multi_trans))
2003-08-30 04:12:44 +02:00
if (gds__commit_transaction(status, &dbb->dbb_meta_trans))
2001-05-23 15:26:42 +02:00
status = alt_vector;
2003-08-30 04:12:44 +02:00
gds__detach_database(status, &dbb->dbb_handle);
2001-05-23 15:26:42 +02:00
return status_vector[1];
}
2003-09-10 19:52:12 +02:00
static void execute_dynamic_ddl( DBB database, RLB rlb)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* e x e c u t e _ d y n a m i c _ d d l
*
**************************************
*
* Functional description
* Execute a ddl command, for better or for worse.
*
**************************************/
const USHORT length = (UCHAR *) rlb->rlb_data - (UCHAR *) rlb->rlb_base;
2001-05-23 15:26:42 +02:00
if (QLI_blr)
PRETTY_print_dyn((SCHAR*) rlb->rlb_base, (FPTR_INT) ib_printf, "%4d %s\n", 0);
2001-05-23 15:26:42 +02:00
2003-08-30 04:12:44 +02:00
if (gds__ddl(gds_status, &database->dbb_handle, &database->dbb_meta_trans,
length, (char*) rlb->rlb_base)) {
2001-05-23 15:26:42 +02:00
rollback_update(database);
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
}
RELEASE_RLB;
}
static int field_length( USHORT dtype, USHORT length)
{
/**************************************
*
* f i e l d _ l e n g t h
*
**************************************
*
* Functional description
* Return implementation specific length for field.
*
**************************************/
switch (dtype) {
case dtype_short:
return sizeof(SSHORT);
case dtype_long:
return sizeof(SLONG);
case dtype_real:
return sizeof(float);
case dtype_double:
return sizeof(double);
case dtype_sql_time:
case dtype_sql_date:
return sizeof(SLONG);
case dtype_timestamp:
case dtype_blob:
case dtype_quad:
return sizeof(GDS__QUAD);
}
return length;
}
static void get_database_type( DBB new_dbb)
{
/**************************************
*
* g e t _ d a t a b a s e _ t y p e
*
**************************************
*
* Functional description
* Ask what type of database this is.
2001-05-23 15:26:42 +02:00
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
UCHAR buffer[1024];
2001-05-23 15:26:42 +02:00
2003-08-30 04:12:44 +02:00
gds__database_info(status_vector, &new_dbb->dbb_handle, sizeof(db_info),
(char*) db_info, sizeof(buffer), (char*) buffer);
2001-05-23 15:26:42 +02:00
if (status_vector[1])
ERRQ_database_error(new_dbb, gds_status);
2001-05-23 15:26:42 +02:00
UCHAR* p = buffer;
2001-05-23 15:26:42 +02:00
while (*p != gds_info_end && p < buffer + sizeof(buffer)) {
UCHAR item = *p++;
USHORT l = gds__vax_integer(p, 2);
2001-05-23 15:26:42 +02:00
p += 2;
switch (item) {
case gds_info_implementation:
{
const UCHAR* q = p;
int count = *q++;
2001-05-23 15:26:42 +02:00
while (count--) {
new_dbb->dbb_type = *q++;
if (*q++ == gds_info_db_class_access)
2001-05-23 15:26:42 +02:00
break;
}
break;
}
2001-05-23 15:26:42 +02:00
default:
ERRQ_error(257, NULL, NULL, NULL, NULL, NULL);
// Msg257 database info call failed
2001-05-23 15:26:42 +02:00
}
p += l;
}
}
static void get_log_names(
DBB dbb,
SCHAR * db_name,
LLS * log_stack,
SCHAR * cur_log,
SLONG part_offset, SSHORT force, SSHORT skip_delete)
{
/**************************************
*
* g e t _ l o g _ n a m e s
*
**************************************
*
* Functional description
* Walk through list of log files and add to link list.
*
**************************************/
SCHAR next_log[512];
2003-09-10 19:52:12 +02:00
int log_count;
bool not_archived;
2001-05-23 15:26:42 +02:00
SLONG last_log_flag, next_offset;
SSHORT loop = 0;
2001-05-23 15:26:42 +02:00
// loop up to 10 times to allow the file to be archived
2001-05-23 15:26:42 +02:00
2003-09-10 19:52:12 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
loop++;
2003-09-10 19:52:12 +02:00
if (!WALF_get_linked_logs_info
(gds_status, db_name, cur_log, part_offset, &log_count, next_log,
2003-09-10 19:52:12 +02:00
&next_offset, &last_log_flag, &not_archived))
{
ERRQ_database_error(dbb, gds_status);
2003-09-10 19:52:12 +02:00
}
2001-05-23 15:26:42 +02:00
if ((!not_archived) || force)
break;
if (not_archived && skip_delete) {
*log_stack = NULL;
2001-05-23 15:26:42 +02:00
return;
}
if (loop >= 10)
ERRQ_print_error(431, dbb->dbb_filename, NULL, NULL, NULL, NULL);
}
STR string;
2001-05-23 15:26:42 +02:00
if (log_count) {
string = (STR) ALLOCDV(type_str, strlen(next_log));
LLS_PUSH(string, log_stack);
strcpy(string->str_data, next_log);
}
else {
string = (STR) ALLOCDV(type_str, strlen(cur_log));
LLS_PUSH(string, log_stack);
strcpy(string->str_data, cur_log);
}
SCHAR* cl = next_log;
SCHAR* nl = cur_log;
2001-05-23 15:26:42 +02:00
part_offset = next_offset;
SLONG log_seqno, log_length;
2001-05-23 15:26:42 +02:00
while (log_count) {
int ret_val = WALF_get_next_log_info(gds_status,
2001-05-23 15:26:42 +02:00
db_name,
cl, part_offset,
nl, &next_offset,
&log_seqno, &log_length,
&last_log_flag, 1);
if (ret_val == FB_FAILURE)
ERRQ_database_error(dbb, gds_status);
2001-05-23 15:26:42 +02:00
if (ret_val < 0)
break;
string = (STR) ALLOCDV(type_str, strlen(nl));
LLS_PUSH(string, log_stack);
strcpy(string->str_data, nl);
// switch files
2001-05-23 15:26:42 +02:00
if (cl == next_log) {
cl = cur_log;
nl = next_log;
}
else {
cl = next_log;
nl = cur_log;
}
part_offset = next_offset;
}
}
static void get_log_names_serial( LLS * log_stack)
{
/**************************************
*
* g e t _ l o g _ n a m e s _ s e r i a l
*
**************************************
*
* Functional description
* Walk through list of serial log files and add to link list.
*
**************************************/
SCHAR next_log[512];
// for round robin log files, some of the log files may not have been used
// when the database is dropped or log is dropped. Add them to the list
2001-05-23 15:26:42 +02:00
FOR L IN DB.RDB$LOG_FILES
if (L.RDB$FILE_FLAGS & LOG_serial)
continue;
ISC_expand_filename(L.RDB$FILE_NAME, 0, next_log);
STR string = (STR) ALLOCDV(type_str, strlen(next_log));
2001-05-23 15:26:42 +02:00
strcpy(string->str_data, next_log);
LLS_PUSH(string, log_stack);
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
END_ERROR;
}
static TEXT *get_query_header( DBB database, SLONG blob_id[2])
{
/**************************************
*
* g e t _ q u e r y _ h e a d e r
*
**************************************
*
* Functional description
* Pick up a query header for a field.
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
TEXT header[1024], buffer[1024];
FRBRD* blob = NULL;
2003-02-08 01:58:10 +01:00
2003-08-30 04:12:44 +02:00
if (gds__open_blob(status_vector, &database->dbb_handle,
&gds_trans, &blob, (GDS__QUAD*) blob_id))
{
2001-05-23 15:26:42 +02:00
ERRQ_database_error(database, status_vector);
}
2001-05-23 15:26:42 +02:00
TEXT* p = header;
2001-05-23 15:26:42 +02:00
// CVC: No bounds check here: it's assumed that 1024 is enough, but "p"
// might overflow "header" eventually.
2001-05-23 15:26:42 +02:00
for (;;) {
USHORT length;
ISC_STATUS status = gds__get_segment(status_vector, &blob, &length,
2003-08-30 04:12:44 +02:00
sizeof(buffer), buffer);
if (status && status != gds_segment)
2001-05-23 15:26:42 +02:00
break;
if (length && buffer[length - 1] == '\n')
--length;
buffer[length] = 0;
const TEXT* q = buffer;
2001-05-23 15:26:42 +02:00
if (*q == '"')
do {
2001-05-23 15:26:42 +02:00
*p++ = *q++;
} while (*q);
2001-05-23 15:26:42 +02:00
else {
*p++ = '"';
while (*q)
*p++ = *q++;
*p++ = '"';
}
}
2003-08-30 04:12:44 +02:00
if (gds__close_blob(status_vector, &blob))
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
*p = 0;
if (!strcmp(header, "\" \"")) {
header[0] = '-';
header[1] = 0;
p = header + 1;
}
const USHORT len = p - header;
if (len)
return make_string(header, len);
2001-05-23 15:26:42 +02:00
return NULL;
}
static void install( DBB old_dbb)
{
/**************************************
*
* i n s t a l l
*
**************************************
*
* Functional description
* Install a database. Scan relations, etc., make up relation
* blocks, etc, and copy the database block to someplace more
* permanent.
*
**************************************/
// Copy the database block to one out of the permanent pool
2001-05-23 15:26:42 +02:00
SSHORT l = old_dbb->dbb_filename_length;
DBB new_dbb = (DBB) ALLOCPV(type_dbb, l);
2001-05-23 15:26:42 +02:00
new_dbb->dbb_filename_length = l;
TEXT* p = new_dbb->dbb_filename;
const TEXT* q = old_dbb->dbb_filename;
do {
2001-05-23 15:26:42 +02:00
*p++ = *q++;
} while (--l);
2001-05-23 15:26:42 +02:00
DB = new_dbb->dbb_handle = old_dbb->dbb_handle;
new_dbb->dbb_capabilities = old_dbb->dbb_capabilities;
new_dbb->dbb_next = QLI_databases;
QLI_databases = new_dbb;
// If a name was given, make up a symbol for the database.
2001-05-23 15:26:42 +02:00
NAM name = (NAM) old_dbb->dbb_symbol;
if (name) {
SYM asymbol = make_symbol(name->nam_string, name->nam_length);
new_dbb->dbb_symbol = asymbol;
asymbol->sym_type = SYM_database;
asymbol->sym_object = (BLK) new_dbb;
HSH_insert(asymbol);
2001-05-23 15:26:42 +02:00
}
gds_trans = MET_transaction(nod_start_trans, new_dbb);
2001-05-23 15:26:42 +02:00
/* Find out whose database this is so later we don't ask Rdb/VMS
or its pals to do any unnatural acts. While we're at it get
general capabilities */
get_database_type(new_dbb);
set_capabilities(new_dbb);
/* Get all relations in database. For each relation make up a
relation block, make up a symbol block, and insert the symbol
2001-05-23 15:26:42 +02:00
into the hash table. */
FRBRD* request = NULL;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request) X IN DB.RDB$RELATIONS
SORTED BY DESCENDING X.RDB$RELATION_NAME
2001-05-23 15:26:42 +02:00
QLI_REL relation = (QLI_REL) ALLOCP(type_rel);
2001-05-23 15:26:42 +02:00
relation->rel_next = new_dbb->dbb_relations;
new_dbb->dbb_relations = relation;
relation->rel_database = new_dbb;
relation->rel_id = X.RDB$RELATION_ID;
SYM rsymbol = make_symbol(X.RDB$RELATION_NAME, sizeof(X.RDB$RELATION_NAME));
rsymbol->sym_type = SYM_relation;
rsymbol->sym_object = (BLK) relation;
relation->rel_symbol = rsymbol;
HSH_insert(rsymbol);
if (strcmp(rsymbol->sym_string, "QLI$PROCEDURES") == 0)
2001-05-23 15:26:42 +02:00
new_dbb->dbb_flags |= DBB_procedures;
if (relation->rel_system_flag = X.RDB$SYSTEM_FLAG)
relation->rel_flags |= REL_system;
if (!X.RDB$VIEW_BLR.NULL)
relation->rel_flags |= REL_view;
END_FOR
ON_ERROR
ERRQ_database_error(new_dbb, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
if (request)
2003-08-30 04:12:44 +02:00
if (gds__release_request(gds_status, &request))
ERRQ_database_error(new_dbb, gds_status);
2001-05-23 15:26:42 +02:00
// Pick up functions, if appropriate
2001-05-23 15:26:42 +02:00
if (new_dbb->dbb_capabilities & DBB_cap_functions) {
FRBRD* request2 = NULL;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request) X IN DB.RDB$FUNCTIONS
SYM fsymbol = make_symbol(X.RDB$FUNCTION_NAME, sizeof(X.RDB$FUNCTION_NAME));
if (!fsymbol)
2001-05-23 15:26:42 +02:00
continue;
FUN function = (FUN) ALLOCPV(type_fun, 0);
2001-05-23 15:26:42 +02:00
function->fun_next = new_dbb->dbb_functions;
new_dbb->dbb_functions = function;
function->fun_symbol = fsymbol;
2001-05-23 15:26:42 +02:00
function->fun_database = new_dbb;
FOR(REQUEST_HANDLE request2) Y IN DB.RDB$FUNCTION_ARGUMENTS WITH
Y.RDB$FUNCTION_NAME EQ X.RDB$FUNCTION_NAME AND
Y.RDB$ARGUMENT_POSITION EQ X.RDB$RETURN_ARGUMENT
function->fun_return.dsc_dtype = MET_get_datatype(Y.RDB$FIELD_TYPE);
2001-05-23 15:26:42 +02:00
function->fun_return.dsc_length =
field_length(function->fun_return.dsc_dtype,
Y.RDB$FIELD_LENGTH);
function->fun_return.dsc_scale = Y.RDB$FIELD_SCALE;
END_FOR
ON_ERROR
ERRQ_database_error(new_dbb, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
if (!function->fun_return.dsc_dtype) {
function->fun_return.dsc_dtype = dtype_text;
function->fun_return.dsc_length = 20;
}
fsymbol->sym_type = SYM_function;
fsymbol->sym_object = (BLK) function;
HSH_insert(fsymbol);
2001-05-23 15:26:42 +02:00
// Insert another symbol if there is a function query name
2001-05-23 15:26:42 +02:00
SYM symbol2 = make_symbol(X.RDB$QUERY_NAME, sizeof(X.RDB$QUERY_NAME));
if (symbol2) {
2001-05-23 15:26:42 +02:00
function->fun_query_name = symbol2;
symbol2->sym_type = SYM_function;
symbol2->sym_object = (BLK) function;
HSH_insert(symbol2);
}
END_FOR
ON_ERROR
ERRQ_database_error(new_dbb, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
if (request)
2003-08-30 04:12:44 +02:00
if (gds__release_request(gds_status, &request))
ERRQ_database_error(new_dbb, gds_status);
2001-05-23 15:26:42 +02:00
if (request2)
2003-08-30 04:12:44 +02:00
if (gds__release_request(gds_status, &request2))
ERRQ_database_error(new_dbb, gds_status);
2001-05-23 15:26:42 +02:00
}
}
static SYN make_node( NOD_T type, USHORT count)
{
/**************************************
*
* m a k e _ n o d e
*
**************************************
*
* Functional description
* Generate a syntax node.
*
**************************************/
SYN node = (SYN) ALLOCPV(type_syn, count);
2001-05-23 15:26:42 +02:00
node->syn_count = count;
node->syn_type = type;
return node;
}
static TEXT *make_string( TEXT * string, SSHORT length)
{
/**************************************
*
* m a k e _ s t r i n g
*
**************************************
*
* Functional description
* Make up a permanent string from a large string. Chop off
* trailing blanks. If there's nothing left, return NULL.
*
**************************************/
string[length] = 0;
if (!(length = truncate_string(string)))
return NULL;
STR str = (STR) ALLOCPV(type_str, length + 1);
TEXT* p = str->str_data;
do {
2001-05-23 15:26:42 +02:00
*p++ = *string++;
} while (--length);
2001-05-23 15:26:42 +02:00
*p = 0;
return str->str_data;
}
static SYM make_symbol( TEXT * string, SSHORT length)
{
/**************************************
*
* m a k e _ s y m b o l
*
**************************************
*
* Functional description
* Make up a symbol from a string. If the string is all blanks,
2001-05-23 15:26:42 +02:00
* don't make up a symbol. Phooey.
*
**************************************/
if (!(length = truncate_string(string)))
return NULL;
SYM symbol = (SYM) ALLOCPV(type_sym, length);
2001-05-23 15:26:42 +02:00
symbol->sym_type = SYM_relation;
symbol->sym_length = length;
TEXT* p = symbol->sym_name;
symbol->sym_string = p;
do {
2001-05-23 15:26:42 +02:00
*p++ = *string++;
} while (--length);
2001-05-23 15:26:42 +02:00
return symbol;
}
static CON missing_value( SLONG * blob_id, SYM symbol)
{
/**************************************
*
* m i s s i n g _ v a l u e
*
**************************************
*
* Functional description
* Get a missing value into a constant
* block for later reference.
2001-05-23 15:26:42 +02:00
*
**************************************/
SYN element = parse_blr_blob(blob_id, symbol);
2001-05-23 15:26:42 +02:00
if (element)
return ((CON) element->syn_arg[0]);
else
return NULL;
}
static SYN parse_blr( UCHAR ** ptr, SYM symbol)
{
/**************************************
*
* p a r s e _ b l r
*
**************************************
*
* Functional description
* Parse a BLR expression.
*
**************************************/
SYN *arg;
2001-05-23 15:26:42 +02:00
CON constant;
NOD_T operatr;
2001-05-23 15:26:42 +02:00
NAM name;
UCHAR *p;
SSHORT dtype, scale, length, l, op;
2001-05-23 15:26:42 +02:00
UCHAR* blr = *ptr;
SSHORT args = 2;
SYN node = NULL;
2001-05-23 15:26:42 +02:00
switch (op = BLR_BYTE) {
case blr_any:
case blr_unique:
case blr_eoc:
return NULL;
case blr_eql:
operatr = nod_eql;
2001-05-23 15:26:42 +02:00
break;
case blr_neq:
operatr = nod_neq;
2001-05-23 15:26:42 +02:00
break;
case blr_gtr:
operatr = nod_gtr;
2001-05-23 15:26:42 +02:00
break;
case blr_geq:
operatr = nod_geq;
2001-05-23 15:26:42 +02:00
break;
case blr_lss:
operatr = nod_lss;
2001-05-23 15:26:42 +02:00
break;
case blr_leq:
operatr = nod_leq;
2001-05-23 15:26:42 +02:00
break;
case blr_containing:
operatr = nod_containing;
2001-05-23 15:26:42 +02:00
break;
case blr_starting:
operatr = nod_starts;
2001-05-23 15:26:42 +02:00
break;
case blr_matching:
operatr = nod_matches;
2001-05-23 15:26:42 +02:00
break;
case blr_matching2:
operatr = nod_sleuth;
2001-05-23 15:26:42 +02:00
break;
case blr_like:
operatr = nod_like;
2001-05-23 15:26:42 +02:00
break;
case blr_and:
operatr = nod_and;
2001-05-23 15:26:42 +02:00
break;
case blr_or:
operatr = nod_or;
2001-05-23 15:26:42 +02:00
break;
case blr_add:
operatr = nod_add;
2001-05-23 15:26:42 +02:00
break;
case blr_subtract:
operatr = nod_subtract;
2001-05-23 15:26:42 +02:00
break;
case blr_multiply:
operatr = nod_multiply;
2001-05-23 15:26:42 +02:00
break;
case blr_divide:
operatr = nod_divide;
2001-05-23 15:26:42 +02:00
break;
case blr_upcase:
operatr = nod_upcase;
2001-05-23 15:26:42 +02:00
break;
case blr_null:
operatr = nod_null;
2001-05-23 15:26:42 +02:00
break;
case blr_between:
operatr = nod_between;
2001-05-23 15:26:42 +02:00
args = 3;
break;
case blr_not:
operatr = nod_not;
2001-05-23 15:26:42 +02:00
args = 1;
break;
case blr_negate:
operatr = nod_negate;
2001-05-23 15:26:42 +02:00
args = 1;
break;
case blr_missing:
operatr = nod_missing;
2001-05-23 15:26:42 +02:00
args = 1;
break;
case blr_fid:
BLR_BYTE;
blr += 2;
node = make_node(nod_field, 1);
name = (NAM) ALLOCPV(type_nam, symbol->sym_length);
node->syn_arg[0] = (SYN) name;
name->nam_length = symbol->sym_length;
strcpy(name->nam_string, symbol->sym_string);
break;
case blr_field:
BLR_BYTE;
length = BLR_BYTE;
node = make_node(nod_field, 1);
name = (NAM) ALLOCPV(type_nam, length);
node->syn_arg[0] = (SYN) name;
name->nam_length = length;
p = (UCHAR *) name->nam_string;
do {
2001-05-23 15:26:42 +02:00
*p++ = BLR_BYTE;
} while (--length);
2001-05-23 15:26:42 +02:00
break;
case blr_function:
length = BLR_BYTE;
node = make_node(nod_function, s_fun_count);
node->syn_arg[s_fun_function] = (SYN) HSH_lookup((SCHAR*) blr, length);
2001-05-23 15:26:42 +02:00
blr += length;
args = BLR_BYTE;
node->syn_arg[s_fun_args] = make_node(nod_list, args);
arg = node->syn_arg[s_fun_args]->syn_arg;
while (--args >= 0) {
if (!(*arg++ = parse_blr(&blr, symbol)))
return NULL;
}
break;
case blr_literal:
scale = 0;
switch (BLR_BYTE) {
case blr_text:
dtype = dtype_text;
length = l = gds__vax_integer(blr, 2);
blr += 2;
break;
case blr_text2:
dtype = dtype_text;
scale = gds__vax_integer(blr, 2);
blr += 2;
length = l = gds__vax_integer(blr, 2);
blr += 2;
break;
case blr_varying:
dtype = dtype_varying;
length = l = gds__vax_integer(blr, 2) + sizeof(USHORT);
blr += 2;
break;
case blr_varying2:
dtype = dtype_varying;
scale = gds__vax_integer(blr, 2);
blr += 2;
length = l = gds__vax_integer(blr, 2) + sizeof(USHORT);
blr += 2;
break;
case blr_short:
dtype = dtype_short;
l = 2;
length = sizeof(SSHORT);
scale = (int) BLR_BYTE;
break;
case blr_long:
dtype = dtype_long;
length = sizeof(SLONG);
l = 4;
scale = (int) BLR_BYTE;
break;
case blr_quad:
dtype = dtype_quad;
l = 8;
length = sizeof(GDS__QUAD);
scale = (int) BLR_BYTE;
break;
case blr_int64:
dtype = dtype_int64;
l = 8;
length = sizeof(SINT64);
scale = (int) BLR_BYTE;
break;
2001-05-23 15:26:42 +02:00
case blr_timestamp:
dtype = dtype_timestamp;
l = 8;
length = sizeof(GDS__QUAD);
break;
case blr_sql_date:
dtype = dtype_sql_date;
l = 4;
length = sizeof(SLONG);
break;
case blr_sql_time:
dtype = dtype_sql_time;
l = 4;
length = sizeof(ULONG);
break;
}
constant = (CON) ALLOCPV(type_con, length);
constant->con_desc.dsc_dtype = dtype;
constant->con_desc.dsc_scale = scale;
constant->con_desc.dsc_length = length;
constant->con_desc.dsc_address = p = constant->con_data;
if (dtype == dtype_text)
while (l--)
*p++ = BLR_BYTE;
else if (dtype == dtype_short) {
*(SSHORT *) p = gds__vax_integer(blr, l);
blr += l;
}
else if (dtype == dtype_long) {
*(SLONG *) p = gds__vax_integer(blr, l);
blr += l;
}
node = make_node(nod_constant, 1);
node->syn_count = 0;
node->syn_arg[0] = (SYN) constant;
break;
default:
ERRQ_print_error(258, (TEXT *) op, NULL, NULL, NULL, NULL); // Msg258 don't understand BLR operatr %d
2001-05-23 15:26:42 +02:00
}
if (!node) {
node = make_node(operatr, args);
2001-05-23 15:26:42 +02:00
arg = node->syn_arg;
while (--args >= 0)
if (!(*arg++ = parse_blr(&blr, symbol)))
return NULL;
}
*ptr = blr;
return node;
}
static SYN parse_blr_blob( SLONG * blob_id, SYM symbol)
{
/**************************************
*
* p a r s e _ b l r _ b l o b
*
**************************************
*
* Functional description
* Gobble up a BLR blob, if possible.
2001-05-23 15:26:42 +02:00
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
if (!blob_id[0] && !blob_id[1])
return NULL;
FRBRD* handle = NULL;
2001-05-23 15:26:42 +02:00
if (gds__open_blob(status_vector, &DB, &gds_trans, &handle,
(GDS__QUAD*) blob_id))
2003-08-30 04:12:44 +02:00
return NULL;
2001-05-23 15:26:42 +02:00
UCHAR buffer[1024];
UCHAR* ptr = buffer;
2001-05-23 15:26:42 +02:00
for (;;) {
USHORT length = buffer + sizeof(buffer) - ptr;
if (!length)
2001-05-23 15:26:42 +02:00
break;
if (gds__get_segment(status_vector, &handle, &length, length,
(char*) ptr))
2003-08-30 04:12:44 +02:00
break;
2001-05-23 15:26:42 +02:00
ptr += length;
}
2003-08-30 04:12:44 +02:00
if (gds__close_blob(status_vector, &handle))
2001-05-23 15:26:42 +02:00
return NULL;
if (ptr == buffer)
return NULL;
ptr = buffer;
if (*ptr++ != blr_version4)
return NULL;
SYN node = parse_blr(&ptr, symbol);
2001-05-23 15:26:42 +02:00
if (*ptr != blr_eoc)
return NULL;
return node;
}
static void purge_relation(QLI_REL relation)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p u r g e _ r e l a t i o n
*
**************************************
*
* Functional description
* Purge a relation out of internal data structures.
*
**************************************/
SYM symbol = relation->rel_symbol;
DBB database = relation->rel_database;
2001-05-23 15:26:42 +02:00
HSH_remove(symbol);
for (QLI_REL* ptr = &database->dbb_relations; *ptr; ptr = &(*ptr)->rel_next)
{
2001-05-23 15:26:42 +02:00
if (*ptr == relation) {
*ptr = relation->rel_next;
break;
}
}
QLI_FLD field;
2001-05-23 15:26:42 +02:00
while (field = relation->rel_fields) {
relation->rel_fields = field->fld_next;
ALLQ_release((FRB) field->fld_name);
2001-05-23 15:26:42 +02:00
if (symbol = field->fld_query_name) {
ALLQ_release((FRB) symbol);
2001-05-23 15:26:42 +02:00
}
ALLQ_release((FRB) field);
2001-05-23 15:26:42 +02:00
}
ALL_release((FRB) relation);
2001-05-23 15:26:42 +02:00
}
static void put_dyn_string( RLB rlb, const TEXT* string)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p u t _ d y n _ s t r i n g
*
**************************************
*
* Functional description
* Move a string to a dynamic DDL command block.
*
**************************************/
const SSHORT l = strlen(string);
2001-05-23 15:26:42 +02:00
while ((SSHORT) (rlb->rlb_limit - rlb->rlb_data) < l) {
rlb = GEN_rlb_extend(rlb);
}
STUFF_WORD(l);
while (*string) {
STUFF(*string++);
}
CHECK_RLB(rlb);
}
static void rollback_update( DBB database)
{
/**************************************
*
* r o l l b a c k _ u p d a t e
*
**************************************
*
* Functional description
* Roll back a meta-data update.
*
**************************************/
if (gds_trans == database->dbb_meta_trans &&
2001-05-23 15:26:42 +02:00
(database->dbb_capabilities & DBB_cap_multi_trans))
{
ISC_STATUS_ARRAY alt_vector;
2003-08-30 04:12:44 +02:00
gds__rollback_transaction(alt_vector, &database->dbb_meta_trans);
// Note: No message given if rollback fails
}
2001-05-23 15:26:42 +02:00
gds_trans = NULL;
2001-05-23 15:26:42 +02:00
}
static void set_capabilities( DBB database)
{
/**************************************
*
* s e t _ c a p a b i l i t i e s
*
**************************************
*
* Functional description
* Probe the database to determine
* what metadata capabilities it has.
* The table, rfr_table, in the static
* data declarations has the relation
* and field names, together with the
* capabilities bits.
*
**************************************/
FRBRD* req = NULL;
2001-05-23 15:26:42 +02:00
// Look for desireable fields in system relations
2001-05-23 15:26:42 +02:00
for (const rfr_tab_t* rel_field_table = rfr_table; rel_field_table->relation;
rel_field_table++)
{
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE req) x IN DB.RDB$RELATION_FIELDS
WITH x.RDB$RELATION_NAME = rel_field_table->relation
AND x.RDB$FIELD_NAME = rel_field_table->field
database->dbb_capabilities |= rel_field_table->bit_mask;
END_FOR
ON_ERROR
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
}
if (req)
2003-08-30 04:12:44 +02:00
if (gds__release_request(gds_status, &req))
ERRQ_database_error(database, gds_status);
2001-05-23 15:26:42 +02:00
}
static DBB setup_update( DBB database)
{
/**************************************
*
* s e t u p _ u p d a t e
*
**************************************
*
* Functional description
* Get ready to do a meta data update.
* If no database was specified, use the
* most recently readied one.
2001-05-23 15:26:42 +02:00
*
**************************************/
if (!database)
database = QLI_databases;
MET_meta_transaction(database, TRUE);
return database;
}
static void sql_grant_revoke( SYN node, USHORT type)
{
/*****************************************************
*
* s q l _ g r a n t _ r e v o k e
*
*****************************************************
*
* Build a DYN string for a SQL GRANT or REVOKE statement
*
*****************************************************/
const USHORT privileges = (USHORT) node->syn_arg[s_grant_privileges];
QLI_REL relation = (QLI_REL) node->syn_arg[s_grant_relation];
DBB database = setup_update(relation->rel_database);
relation->rel_database = database;
const TEXT* relation_name = relation->rel_symbol->sym_string;
2001-05-23 15:26:42 +02:00
RLB rlb = NULL;
2001-05-23 15:26:42 +02:00
rlb = CHECK_RLB(rlb);
STUFF(gds_dyn_version_1);
STUFF(gds_dyn_begin);
2001-05-23 15:26:42 +02:00
// For each user create a separate grant string
// For each specified field create a separate grant string
2001-05-23 15:26:42 +02:00
SYN names = node->syn_arg[s_grant_users];
SYN fields = node->syn_arg[s_grant_fields];
2001-05-23 15:26:42 +02:00
NAM *name, *end;
2001-05-23 15:26:42 +02:00
for (name = (NAM *) names->syn_arg, end = name + names->syn_count;
name < end; name++)
{
2001-05-23 15:26:42 +02:00
if (fields->syn_count) {
NAM* field = (NAM *) fields->syn_arg;
NAM* const end_field = field + fields->syn_count;
for (; field < end_field; field++)
{
2001-05-23 15:26:42 +02:00
stuff_priv(rlb, type, relation_name, privileges,
(*name)->nam_string, (*field)->nam_string);
}
2001-05-23 15:26:42 +02:00
}
else
stuff_priv(rlb, type, relation_name, privileges,
(*name)->nam_string, NULL);
}
2001-05-23 15:26:42 +02:00
STUFF(gds_dyn_end);
STUFF(gds_dyn_eoc);
2001-05-23 15:26:42 +02:00
execute_dynamic_ddl(database, rlb);
MET_meta_commit(database);
}
static int truncate_string( TEXT * string)
{
/**************************************
*
* t r u n c a t e _ s t r i n g
*
**************************************
*
* Functional description
* Convert a blank filled string to
* a null terminated string without
* trailing blanks. Because some
* strings contain embedded blanks
* (e.g. query headers & edit strings)
* truncate from the back forward.
* Return the number of characters found,
* not including the terminating null.
*
**************************************/
TEXT *p;
for (p = string; *p; p++);
for (p--; (p >= string) && (*p == ' '); p--);
*++p = 0;
return (p - string);
}
static void stuff_priv(
RLB rlb,
USHORT type,
const TEXT* relation,
USHORT privileges, const TEXT* user, const TEXT* field)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s t u f f _ p r i v
*
**************************************
*
* Functional description
* Stuff a privilege for grant/revoke.
*
**************************************/
rlb = CHECK_RLB(rlb);
STUFF(type);
// Stuff privileges first
2001-05-23 15:26:42 +02:00
USHORT priv_count = 0;
2001-05-23 15:26:42 +02:00
if (privileges & PRV_select)
priv_count++;
if (privileges & PRV_insert)
priv_count++;
if (privileges & PRV_delete)
priv_count++;
if (privileges & PRV_update)
priv_count++;
STUFF_WORD(priv_count);
if (privileges & PRV_select)
STUFF('S');
if (privileges & PRV_insert)
STUFF('I');
if (privileges & PRV_delete)
STUFF('D');
if (privileges & PRV_update)
STUFF('U');
STUFF(gds_dyn_rel_name);
2001-05-23 15:26:42 +02:00
STUFF_STRING(relation);
STUFF(gds_dyn_grant_user);
2001-05-23 15:26:42 +02:00
STUFF_STRING(user);
if (field) {
STUFF(gds_dyn_fld_name);
2001-05-23 15:26:42 +02:00
STUFF_STRING(field);
}
if (privileges & PRV_grant_option) {
STUFF(gds_dyn_grant_options);
2001-05-23 15:26:42 +02:00
STUFF_WORD(2);
STUFF_WORD(TRUE);
}
STUFF(gds_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void wal_info(
UCHAR * db_info_buffer,
SLONG * log, SCHAR * cur_log, SLONG * part_offset)
{
/**************************************
*
* w a l _ i n f o
*
**************************************
*
* Functional description
* Extract wal name and log offset
*
**************************************/
*log = 0;
*part_offset = 0;
cur_log[0] = 0;
UCHAR* p = db_info_buffer;
UCHAR item;
UCHAR* d;
while ((item = *p++) != gds_info_end) {
SLONG length = gds__vax_integer(p, 2);
2001-05-23 15:26:42 +02:00
p += 2;
switch (item) {
case gds_info_logfile:
2001-05-23 15:26:42 +02:00
*log = gds__vax_integer(p, length);
p += length;
break;
case gds_info_cur_logfile_name:
2001-05-23 15:26:42 +02:00
d = p;
p += length;
length = *d++;
memcpy(cur_log, d, length);
cur_log[length] = 0;
break;
case gds_info_cur_log_part_offset:
2001-05-23 15:26:42 +02:00
*part_offset = gds__vax_integer(p, length);
p += length;
break;
default:
;
}
}
}