2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Command Oriented Query Language
|
2003-09-15 14:30:28 +02:00
|
|
|
* 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): ______________________________________.
|
|
|
|
*/
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "firebird.h"
|
2004-04-29 00:36:29 +02:00
|
|
|
#include <stdio.h>
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include "../qli/dtr.h"
|
|
|
|
#include "../qli/compile.h"
|
|
|
|
#include "../qli/exe.h"
|
2006-01-07 01:31:37 +01:00
|
|
|
//#include "../jrd/license.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/flags.h"
|
2003-11-08 17:40:17 +01:00
|
|
|
#include "../jrd/ibase.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#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"
|
2004-09-26 09:48:29 +02:00
|
|
|
#include "../common/utils_proto.h"
|
2004-12-09 20:19:47 +01:00
|
|
|
#include "../common/classes/ClumpletWriter.h"
|
2007-04-06 12:10:10 +02:00
|
|
|
#include "../common/classes/UserBlob.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-03-28 06:20:36 +02:00
|
|
|
using MsgFormat::SafeArg;
|
|
|
|
|
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
DATABASE DB = FILENAME "yachts.lnk";
|
|
|
|
DATABASE DB1 = FILENAME "yachts.lnk";
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void add_field(qli_rel*, qli_fld*, USHORT);
|
|
|
|
static void add_sql_field(qli_rel*, qli_fld*, USHORT, qli_rlb*);
|
2007-04-06 12:10:10 +02:00
|
|
|
static void blob_copy(qli_rlb*, qli_rel*, ISC_QUAD&);
|
2004-02-02 12:02:12 +01:00
|
|
|
static void change_field(qli_rel*, qli_fld*);
|
|
|
|
static bool check_global_field(DBB, qli_fld*, const TEXT*);
|
|
|
|
static bool check_relation(qli_rel*);
|
2004-03-07 08:58:55 +01:00
|
|
|
static void clone_fields(qli_rel*, qli_rel*);
|
|
|
|
static void clone_global_fields(qli_rel*, qli_rel*);
|
2004-02-02 12:02:12 +01:00
|
|
|
static void define_global_field(DBB, qli_fld*, qli_symbol*);
|
|
|
|
static void delete_fields(qli_rel*);
|
2003-04-10 12:16:09 +02:00
|
|
|
static ISC_STATUS detach(ISC_STATUS *, DBB);
|
2004-02-02 12:02:12 +01:00
|
|
|
static void execute_dynamic_ddl(DBB, qli_rlb*);
|
2001-05-23 15:26:42 +02:00
|
|
|
static int field_length(USHORT, USHORT);
|
|
|
|
static void get_database_type(DBB);
|
2007-04-06 12:10:10 +02:00
|
|
|
static TEXT *get_query_header(DBB, ISC_QUAD&);
|
2006-08-31 10:01:24 +02:00
|
|
|
static void install(dbb*);
|
2004-03-07 08:58:55 +01:00
|
|
|
static qli_syntax* make_node(NOD_T, USHORT);
|
2004-02-20 07:43:27 +01:00
|
|
|
static TEXT *make_string(TEXT*, SSHORT);
|
2004-02-02 12:02:12 +01:00
|
|
|
static qli_symbol* make_symbol(TEXT *, SSHORT);
|
2007-04-06 12:10:10 +02:00
|
|
|
static qli_const* missing_value(ISC_QUAD&, qli_symbol*);
|
2004-03-07 08:58:55 +01:00
|
|
|
static qli_syntax* parse_blr(UCHAR **, qli_symbol*);
|
2007-04-06 12:10:10 +02:00
|
|
|
static qli_syntax* parse_blr_blob(ISC_QUAD&, qli_symbol*);
|
2004-02-02 12:02:12 +01:00
|
|
|
static void purge_relation(qli_rel*);
|
|
|
|
static void put_dyn_string(qli_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);
|
2004-03-07 08:58:55 +01:00
|
|
|
static void sql_grant_revoke(qli_syntax*, USHORT);
|
2004-02-02 12:02:12 +01:00
|
|
|
static void stuff_priv(qli_rlb*, USHORT, const TEXT*, USHORT, const TEXT*, const TEXT*);
|
2004-02-20 07:43:27 +01:00
|
|
|
static int truncate_string(TEXT*);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
static const UCHAR tpb[] = { isc_tpb_version1, isc_tpb_write };
|
|
|
|
static const UCHAR db_info[] = { isc_info_implementation, isc_info_end };
|
2003-09-25 13:49:12 +02:00
|
|
|
static UCHAR global_parm_buffer[256];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/*
|
2003-11-08 17:40:17 +01:00
|
|
|
static const UCHAR dpb_trace [] = { isc_dpb_version1, isc_dpb_trace, 1, 1 };
|
|
|
|
static const UCHAR dpb_num_buffers [ ] = { isc_dpb_version1, isc_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++
|
|
|
|
|
2004-02-20 07:43:27 +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,
|
2002-12-13 15:12:54 +01:00
|
|
|
blr_blob,
|
|
|
|
0,
|
|
|
|
blr_int64
|
2001-05-23 15:26:42 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
/*
|
|
|
|
table used to determine capabilities, checking for specific
|
|
|
|
fields in system relations
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
struct rfr_tab_t {
|
2004-10-07 11:19:25 +02:00
|
|
|
const TEXT* relation;
|
|
|
|
const TEXT* field;
|
2001-05-23 15:26:42 +02:00
|
|
|
int bit_mask;
|
2003-09-25 13:49:12 +02:00
|
|
|
};
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
static const rfr_tab_t rfr_table[] =
|
|
|
|
{
|
2003-02-18 08:42:52 +01:00
|
|
|
{ "RDB$INDICES", "RDB$INDEX_INACTIVE", DBB_cap_idx_inactive },
|
2003-09-25 13:49:12 +02:00
|
|
|
/* OBSOLETE - 1996-Aug-06 David Schnepper
|
2003-02-18 08:42:52 +01:00
|
|
|
{ "RDB$RELATIONS", "RDB$STORE_TRIGGER", DBB_cap_triggers },
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
2003-02-18 08:42:52 +01: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
|
|
|
};
|
|
|
|
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
bool MET_declare( DBB database, qli_fld* variable, const 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) {
|
2004-02-20 07:43:27 +01:00
|
|
|
MET_meta_transaction(database, false);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (check_global_field(database, variable, field_name->nam_string))
|
2004-02-20 07:43:27 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
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);
|
|
|
|
|
2003-08-28 12:55:19 +02:00
|
|
|
if (check_global_field(database, NULL, field->fld_name->sym_string)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
rollback_update(database);
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(233, field->fld_name->sym_string);
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
void MET_define_index( qli_syntax* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ d e f i n e _ i n d e x
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Define a new index.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* symbol = (qli_symbol*) node->syn_arg[s_dfi_name];
|
|
|
|
qli_rel* relation = (qli_rel*) node->syn_arg[s_dfi_relation];
|
2004-03-07 08:58:55 +01:00
|
|
|
qli_syntax* fields = node->syn_arg[s_dfi_fields];
|
2003-09-25 13:49:12 +02:00
|
|
|
DBB database = setup_update(relation->rel_database);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (relation->rel_flags & REL_view)
|
2003-09-25 13:49:12 +02:00
|
|
|
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
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(235, symbol->sym_string);
|
2003-09-25 13:49:12 +02:00
|
|
|
// Msg235 Index %s already exists
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR
|
|
|
|
ON_ERROR
|
2001-07-12 08:32:05 +02:00
|
|
|
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);
|
2001-07-12 08:32:05 +02:00
|
|
|
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);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
END_FOR
|
|
|
|
ON_ERROR
|
|
|
|
rollback_update(database);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
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);
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
bool present = false;
|
2004-02-02 12:02:12 +01:00
|
|
|
for (qli_fld* field = relation->rel_fields; field;
|
2003-09-25 13:49:12 +02:00
|
|
|
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;
|
|
|
|
}
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!present) {
|
|
|
|
rollback_update(database);
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(236, SafeArg() << (*ptr)->nam_string <<
|
|
|
|
relation->rel_symbol->sym_string);
|
2003-09-25 13:49:12 +02:00
|
|
|
// 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);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
MET_meta_commit(database);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* 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)))
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(483, source->rel_symbol->sym_string);
|
|
|
|
// Msg 483 Relation %s does not exist
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-09-25 13:49:12 +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))
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(237, symbol->sym_string); // Msg237 Relation %s already exists
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
STORE(REQUEST_HANDLE database->dbb_requests[REQ_store_relation])
|
2003-09-25 13:49:12 +02:00
|
|
|
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);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
if (source)
|
|
|
|
clone_fields(relation, source);
|
2003-09-25 13:49:12 +02:00
|
|
|
else {
|
|
|
|
USHORT position = 1;
|
2004-02-02 12:02:12 +01:00
|
|
|
for (qli_fld* field = relation->rel_fields; field;
|
2003-09-25 13:49:12 +02:00
|
|
|
field = field->fld_next, position++)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
add_field(relation, field, position);
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
MET_meta_commit(database);
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
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;
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// 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
|
2003-09-25 13:49:12 +02:00
|
|
|
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
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
delete_fields(relation);
|
|
|
|
MET_fields(relation);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* symbol = relation->rel_symbol;
|
2003-09-25 13:49:12 +02:00
|
|
|
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
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(237, symbol->sym_string);
|
2003-09-25 13:49:12 +02:00
|
|
|
// Msg237 Relation %s already exists
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR
|
|
|
|
ON_ERROR
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_rlb* rlb = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
rlb = CHECK_RLB(rlb);
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_version_1);
|
|
|
|
STUFF(isc_dyn_begin);
|
|
|
|
STUFF(isc_dyn_def_rel);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(symbol->sym_string);
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_rel_sql_protection);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_WORD(2);
|
|
|
|
STUFF_WORD(1);
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
USHORT position = 1;
|
2004-02-02 12:02:12 +01:00
|
|
|
for (qli_fld* field = relation->rel_fields; field;
|
2001-05-23 15:26:42 +02:00
|
|
|
field = field->fld_next, position++)
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
add_sql_field(relation, field, position, rlb);
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_end);
|
|
|
|
STUFF(isc_dyn_end);
|
|
|
|
STUFF(isc_dyn_eoc);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
execute_dynamic_ddl(database, rlb);
|
|
|
|
MET_meta_commit(database);
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
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;
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// 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
|
2003-09-25 13:49:12 +02:00
|
|
|
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
|
2001-07-12 08:32:05 +02:00
|
|
|
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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-09-25 13:49:12 +02:00
|
|
|
|
|
|
|
/* generate a database parameter block to
|
2001-05-23 15:26:42 +02:00
|
|
|
include the user/password, if necessary */
|
|
|
|
|
2004-11-08 06:38:42 +01:00
|
|
|
const TEXT* user;
|
2003-09-25 13:49:12 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2004-05-29 07:03:08 +02:00
|
|
|
const TEXT* password;
|
2003-09-25 13:49:12 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
Firebird::ClumpletWriter dpb(Firebird::ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (user_length) {
|
2004-12-09 20:19:47 +01:00
|
|
|
dpb.insertString(isc_dpb_user_name, user, user_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
if (password_length) {
|
2004-12-09 20:19:47 +01:00
|
|
|
dpb.insertString(isc_dpb_password, password, password_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_attach_database(status_vector, 0, dbb->dbb_filename,
|
2004-12-09 20:19:47 +01:00
|
|
|
&dbb->dbb_handle, dpb.getBufferLength(),
|
|
|
|
reinterpret_cast<const char*>(dpb.getBuffer())))
|
2001-05-23 15:26:42 +02:00
|
|
|
ERRQ_database_error(dbb, status_vector);
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_lls* stack = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-12 08:32:05 +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
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_str* astring = (qli_str*) ALLOCDV(type_str, strlen(F.RDB$FILE_NAME));
|
2003-09-25 13:49:12 +02:00
|
|
|
strcpy(astring->str_data, F.RDB$FILE_NAME);
|
2004-05-16 03:42:11 +02:00
|
|
|
ALLQ_push((blk*) astring, &stack);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR
|
|
|
|
ON_ERROR
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(dbb, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
MET_transaction(nod_commit, dbb);
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_detach_database(gds_status, &dbb->dbb_handle))
|
|
|
|
isc_print_status(gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +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);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (stack) {
|
2004-05-16 03:42:11 +02:00
|
|
|
qli_str* sstring = (qli_str*) ALLQ_pop(&stack);
|
2003-09-25 13:49:12 +02:00
|
|
|
if (unlink(sstring->str_data))
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(431, sstring->str_data);
|
2003-09-25 13:49:12 +02:00
|
|
|
// Msg431 Could not drop database file "%s"
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (unlink(dbb->dbb_filename))
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(431, dbb->dbb_filename);
|
2003-09-25 13:49:12 +02:00
|
|
|
// 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);
|
2003-09-25 13:49:12 +02:00
|
|
|
USHORT count = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE database->dbb_requests[REQ_check_fld])
|
2003-09-25 13:49:12 +02:00
|
|
|
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)
|
2007-04-01 02:35:59 +02:00
|
|
|
ERRQ_msg_put(238, name->nam_string); // Msg238 Field %s is in use in the following relations:
|
2004-04-29 00:36:29 +02:00
|
|
|
printf("\t%s\n", RFR.RDB$RELATION_NAME);
|
2001-05-23 15:26:42 +02:00
|
|
|
count++;
|
|
|
|
END_FOR
|
|
|
|
ON_ERROR
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
if (count)
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(239, SafeArg() << name->nam_string << database->dbb_filename);
|
|
|
|
// 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
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_rlb* rlb = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
rlb = CHECK_RLB(rlb);
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_version_1);
|
|
|
|
STUFF(isc_dyn_delete_dimensions);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(FLD.RDB$FIELD_NAME);
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_end);
|
|
|
|
STUFF(isc_dyn_eoc);
|
2001-05-23 15:26:42 +02:00
|
|
|
execute_dynamic_ddl(database, rlb);
|
|
|
|
ERASE FLD
|
|
|
|
ON_ERROR
|
|
|
|
rollback_update(database);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
count++;
|
|
|
|
END_FOR
|
|
|
|
ON_ERROR
|
|
|
|
rollback_update(database);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
if (!count)
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(240, SafeArg() << name->nam_string << database->dbb_filename);
|
|
|
|
// 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);
|
2003-09-25 13:49:12 +02:00
|
|
|
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);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
END_FOR
|
|
|
|
ON_ERROR
|
|
|
|
rollback_update(database);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
if (!count)
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(241, SafeArg() << name->nam_string << database->dbb_filename);
|
|
|
|
// 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);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
END_FOR
|
|
|
|
ON_ERROR
|
|
|
|
rollback_update(database);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
MET_meta_commit(database);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-09-25 13:49:12 +02:00
|
|
|
// Pass the mess off to dynamic DDL and let it worry
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* symbol = relation->rel_symbol;
|
|
|
|
qli_rlb* rlb = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
rlb = CHECK_RLB(rlb);
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_version_1);
|
|
|
|
STUFF(isc_dyn_delete_rel);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(symbol->sym_string);
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_end);
|
|
|
|
STUFF(isc_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);
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Unlink and release various blocks
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
purge_relation(relation);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
int MET_dimensions( DBB database, const TEXT* field_name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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;
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
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
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
return dimensions;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
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.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
/* 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;
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
DBB database = relation->rel_database;
|
2004-02-20 07:43:27 +01:00
|
|
|
MET_meta_transaction(database, false);
|
2001-05-23 15:26:42 +02:00
|
|
|
relation->rel_flags |= REL_fields;
|
2004-02-02 12:02:12 +01:00
|
|
|
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;
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_fld* field = (qli_fld*) ALLOCPV(type_fld, 0);
|
2003-09-25 13:49:12 +02:00
|
|
|
*ptr = field;
|
2001-05-23 15:26:42 +02:00
|
|
|
ptr = &field->fld_next;
|
|
|
|
field->fld_relation = relation;
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* symbol = make_symbol(RFR.RDB$FIELD_NAME, sizeof(RFR.RDB$FIELD_NAME));
|
2003-09-25 13:49:12 +02:00
|
|
|
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))) ||
|
2004-02-20 07:43:27 +01:00
|
|
|
(symbol = make_symbol(RFL.RDB$QUERY_NAME, sizeof(RFL.RDB$QUERY_NAME))))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
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;
|
2003-09-25 13:49:12 +02:00
|
|
|
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;
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
ISC_QUAD* blob = & RFR.RDB$QUERY_HEADER;
|
2007-04-06 12:10:10 +02:00
|
|
|
if (UserBlob::blobIsNull(*blob))
|
2004-02-20 07:43:27 +01:00
|
|
|
blob = & RFL.RDB$QUERY_HEADER;
|
2007-04-06 12:10:10 +02:00
|
|
|
if (!UserBlob::blobIsNull(*blob))
|
|
|
|
field->fld_query_header = get_query_header(database, *blob);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
blob = & RFL.RDB$COMPUTED_BLR;
|
2007-04-06 12:10:10 +02:00
|
|
|
if (!UserBlob::blobIsNull(*blob))
|
2001-05-23 15:26:42 +02:00
|
|
|
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 =
|
2007-04-06 12:10:10 +02:00
|
|
|
missing_value(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 =
|
2007-04-06 12:10:10 +02:00
|
|
|
parse_blr_blob(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
|
2001-07-12 08:32:05 +02:00
|
|
|
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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-09-25 13:49:12 +02:00
|
|
|
// Get rid of relation and field blocks.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_rel* relation;
|
2001-05-23 15:26:42 +02:00
|
|
|
while (relation = dbb->dbb_relations) {
|
|
|
|
purge_relation(relation);
|
|
|
|
}
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Get rid of any functions
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_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);
|
2004-05-16 03:42:11 +02:00
|
|
|
ALLQ_release((FRB) function->fun_symbol);
|
|
|
|
ALLQ_release((FRB) function);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Finally, actually close down database connection.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +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);
|
2004-05-16 03:42:11 +02:00
|
|
|
ALLQ_release((FRB) dbb->dbb_symbol);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-09-25 13:49:12 +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;
|
2004-05-16 03:42:11 +02:00
|
|
|
ALLQ_release((FRB) dbb);
|
2001-05-23 15:26:42 +02:00
|
|
|
count++;
|
|
|
|
if (!*ptr) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!count)
|
2004-05-16 03:42:11 +02:00
|
|
|
ERRQ_bugcheck(231); // Msg231 database block not found for removal
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (status_vector[1])
|
2003-08-28 12:55:19 +02:00
|
|
|
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;
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
switch (blr_datatype)
|
|
|
|
{
|
|
|
|
case blr_text:
|
2001-05-23 15:26:42 +02:00
|
|
|
retvalue = dtype_text;
|
2003-09-25 13:49:12 +02:00
|
|
|
break;
|
|
|
|
case blr_varying:
|
2001-05-23 15:26:42 +02:00
|
|
|
retvalue = dtype_varying;
|
2003-09-25 13:49:12 +02:00
|
|
|
break;
|
|
|
|
case blr_cstring:
|
2001-05-23 15:26:42 +02:00
|
|
|
retvalue = dtype_cstring;
|
2003-09-25 13:49:12 +02:00
|
|
|
break;
|
|
|
|
case blr_short:
|
2001-05-23 15:26:42 +02:00
|
|
|
retvalue = dtype_short;
|
2003-09-25 13:49:12 +02:00
|
|
|
break;
|
|
|
|
case blr_long:
|
2001-05-23 15:26:42 +02:00
|
|
|
retvalue = dtype_long;
|
2003-09-25 13:49:12 +02:00
|
|
|
break;
|
|
|
|
case blr_quad:
|
2001-05-23 15:26:42 +02:00
|
|
|
retvalue = dtype_quad;
|
2003-09-25 13:49:12 +02:00
|
|
|
break;
|
|
|
|
case blr_float:
|
2001-05-23 15:26:42 +02:00
|
|
|
retvalue = dtype_real;
|
2003-09-25 13:49:12 +02:00
|
|
|
break;
|
|
|
|
case blr_double:
|
2001-05-23 15:26:42 +02:00
|
|
|
retvalue = dtype_double;
|
2003-09-25 13:49:12 +02:00
|
|
|
break;
|
|
|
|
case blr_timestamp:
|
2001-05-23 15:26:42 +02:00
|
|
|
retvalue = dtype_timestamp;
|
2003-09-25 13:49:12 +02:00
|
|
|
break;
|
|
|
|
case blr_sql_date:
|
2001-05-23 15:26:42 +02:00
|
|
|
retvalue = dtype_sql_date;
|
2003-09-25 13:49:12 +02:00
|
|
|
break;
|
|
|
|
case blr_sql_time:
|
2001-05-23 15:26:42 +02:00
|
|
|
retvalue = dtype_sql_time;
|
2003-09-25 13:49:12 +02:00
|
|
|
break;
|
|
|
|
case blr_blob:
|
2001-05-23 15:26:42 +02:00
|
|
|
retvalue = dtype_blob;
|
2003-09-25 13:49:12 +02:00
|
|
|
break;
|
|
|
|
case blr_int64:
|
2002-12-13 15:12:54 +01:00
|
|
|
retvalue = dtype_int64;
|
2003-09-25 13:49:12 +02:00
|
|
|
break;
|
|
|
|
default:
|
2003-12-22 11:00:59 +01:00
|
|
|
retvalue = dtype_unknown;
|
2003-09-25 13:49:12 +02:00
|
|
|
break;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return retvalue;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEV_BUILD
|
2003-09-15 14:30:28 +02:00
|
|
|
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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE request_handle = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-15 14:30:28 +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
|
2003-09-25 13:49:12 +02:00
|
|
|
SORTED BY SEG.RDB$FIELD_POSITION
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
const SCHAR* p;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (b == buffer) {
|
2003-09-25 13:49:12 +02:00
|
|
|
// 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++ = '(';
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
|
|
|
// 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
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(NULL, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
if (request_handle)
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_release_request(gds_status, &request_handle))
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(NULL, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +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)
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_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);
|
|
|
|
}
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE MET_meta_transaction(DBB database, bool 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
|
2001-07-12 08:32:05 +02:00
|
|
|
* 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,
|
2003-09-25 13:49:12 +02:00
|
|
|
* 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.
|
2003-09-25 13:49:12 +02:00
|
|
|
*
|
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)
|
2003-09-25 13:49:12 +02:00
|
|
|
IBERROR(243); // Msg243 no active database for operation
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE transaction = (database->dbb_capabilities & DBB_cap_multi_trans) ?
|
|
|
|
database->dbb_meta_trans : 0;
|
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-11-08 17:40:17 +01:00
|
|
|
if (isc_start_transaction(status_vector, &transaction, 1,
|
2003-08-30 04:12:44 +02:00
|
|
|
&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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// If we already have a meta-data transaction, there's more nothing to do
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
gds_trans = transaction;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// If we only support a single transaction, use the data transaction
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
if (!gds_trans && (database->dbb_capabilities & DBB_cap_single_trans))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
if (update_flag)
|
2003-09-25 13:49:12 +02:00
|
|
|
IBERROR(244); // Msg244 Interactive metadata updates are not available on Rdb
|
2001-07-12 08:32:05 +02:00
|
|
|
if (!(gds_trans = database->dbb_transaction))
|
|
|
|
gds_trans = MET_transaction(nod_start_trans, database);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// otherwise make one more effort to start the transaction
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-12 08:32:05 +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;
|
|
|
|
}
|
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
database->dbb_meta_trans = gds_trans;
|
2002-12-17 15:58:23 +01:00
|
|
|
return gds_trans;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01: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.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
database = setup_update(database);
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* field_name = field->fld_name;
|
2003-09-25 13:49:12 +02:00
|
|
|
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;
|
|
|
|
}
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* asymbol = field->fld_query_name;
|
2003-09-25 13:49:12 +02:00
|
|
|
if (asymbol) {
|
2001-05-23 15:26:42 +02:00
|
|
|
X.RDB$QUERY_NAME.NULL = FALSE;
|
2003-09-25 13:49:12 +02:00
|
|
|
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);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
}
|
|
|
|
END_FOR
|
|
|
|
ON_ERROR
|
|
|
|
rollback_update(database);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
if (flag <= 0)
|
|
|
|
{
|
|
|
|
rollback_update(database);
|
2003-09-25 13:49:12 +02:00
|
|
|
// 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;
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(flag, field_name->sym_string);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
MET_meta_commit(database);
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// 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
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
const TEXT* p = X.RDB$RELATION_NAME;
|
2001-05-23 15:26:42 +02:00
|
|
|
while (*p && *p != ' ') {
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* 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)
|
|
|
|
{
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_rel* relation;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (symbol->sym_type == SYM_relation &&
|
2004-02-02 12:02:12 +01:00
|
|
|
(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
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
void MET_modify_index( qli_syntax* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ m o d i f y _ i n d e x
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Change the changeable options
|
|
|
|
* of an index.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-09-25 13:49:12 +02:00
|
|
|
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);
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
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);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
count++;
|
|
|
|
END_FOR
|
|
|
|
ON_ERROR
|
|
|
|
rollback_update(database);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
if (!count)
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(246, SafeArg() << name->nam_string << database->dbb_filename);
|
|
|
|
// Msg246 Index %s does not exist
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
MET_meta_commit(database);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-09-25 13:49:12 +02:00
|
|
|
DBB database = setup_update(relation->rel_database);
|
|
|
|
relation->rel_database = database;
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* relation_name = relation->rel_symbol;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
for (qli_fld* field = fields; field; field = field->fld_next)
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (field->fld_flags & FLD_drop) {
|
2003-09-25 13:49:12 +02:00
|
|
|
USHORT count = 0;
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* 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
|
2003-09-25 13:49:12 +02:00
|
|
|
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);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
END_FOR
|
|
|
|
ON_ERROR
|
|
|
|
rollback_update(database);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
if (!count) {
|
|
|
|
rollback_update(database);
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(247, field_name->sym_string); // 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);
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
MET_meta_commit(database);
|
|
|
|
setup_update(database);
|
|
|
|
delete_fields(relation);
|
|
|
|
MET_fields(relation);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
void MET_ready( qli_syntax* node, USHORT create_flag)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ r e a d y
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Create or Ready one or more databases. If any
|
|
|
|
* fail, all fail. Fair enough?
|
|
|
|
*
|
|
|
|
**************************************/
|
2005-11-27 21:53:09 +01:00
|
|
|
Firebird::ClumpletWriter dpb(Firebird::ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
|
2004-12-09 20:19:47 +01:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
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. */
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
SSHORT length;
|
|
|
|
const TEXT* lc_ctype = QLI_charset;
|
|
|
|
if (lc_ctype && (length = strlen(lc_ctype))) {
|
2004-12-09 20:19:47 +01:00
|
|
|
dpb.insertString(isc_dpb_lc_ctype, lc_ctype, length);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (QLI_trace) {
|
2004-12-09 20:19:47 +01:00
|
|
|
dpb.insertByte(isc_dpb_trace, 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sw_buffers) {
|
2004-12-09 20:19:47 +01:00
|
|
|
dpb.insertInt(isc_dpb_num_buffers, ULONG(sw_buffers));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (temp->dbb_pagesize) {
|
2004-12-09 20:19:47 +01:00
|
|
|
dpb.insertInt(isc_dpb_page_size, ULONG(temp->dbb_pagesize));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-12-09 20:19:47 +01:00
|
|
|
// get a username, if specified globally or on the command line
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
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) {
|
2004-12-09 20:19:47 +01:00
|
|
|
dpb.insertString(isc_dpb_user_name, q, length);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// 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) {
|
2004-12-09 20:19:47 +01:00
|
|
|
dpb.insertString(isc_dpb_password, q, length);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2006-12-08 19:38:15 +01:00
|
|
|
#ifdef TRUSTED_AUTH
|
|
|
|
if (QLI_trusted) {
|
|
|
|
dpb.insertTag(isc_dpb_trusted_auth);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
const qli_syntax* const* const end = node->syn_arg + node->syn_count;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Start by attaching all databases
|
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2004-03-07 08:58:55 +01:00
|
|
|
qli_syntax** ptr;
|
|
|
|
DBB dbb = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
for (ptr = node->syn_arg; ptr < end; ptr++) {
|
2003-09-25 13:49:12 +02:00
|
|
|
dbb = (DBB) *ptr;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (create_flag)
|
2003-11-08 17:40:17 +01:00
|
|
|
isc_create_database(status_vector, 0, dbb->dbb_filename,
|
2004-12-09 20:19:47 +01:00
|
|
|
&dbb->dbb_handle, dpb.getBufferLength(),
|
|
|
|
reinterpret_cast<const char*>(dpb.getBuffer()), 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
2003-11-08 17:40:17 +01:00
|
|
|
isc_attach_database(status_vector, 0, dbb->dbb_filename,
|
2004-12-09 20:19:47 +01:00
|
|
|
&dbb->dbb_handle, dpb.getBufferLength(),
|
|
|
|
reinterpret_cast<const char*>(dpb.getBuffer()));
|
2001-05-23 15:26:42 +02:00
|
|
|
if (status_vector[1])
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// If any attach failed, cleanup and give up
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (ptr < end) {
|
2004-03-07 08:58:55 +01:00
|
|
|
for (qli_syntax** ptr2 = node->syn_arg; ptr2 < ptr; ptr2++)
|
2001-07-12 08:32:05 +02:00
|
|
|
detach(gds_status, (DBB) *ptr2);
|
2001-05-23 15:26:42 +02:00
|
|
|
ERRQ_database_error(dbb, status_vector);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Databases are up and running. Install each.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
for (ptr = node->syn_arg; ptr < end; ptr++)
|
2001-07-12 08:32:05 +02:00
|
|
|
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
|
|
|
|
2003-09-25 13:49:12 +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))
|
2003-11-08 17:40:17 +01:00
|
|
|
isc_print_status(status_vector);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
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
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* symbol = relation->rel_symbol;
|
2003-09-25 13:49:12 +02:00
|
|
|
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
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
if (!count)
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(414, symbol->sym_string); // Msg237 Relation %s is lost
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_rlb* rlb = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
rlb = CHECK_RLB(rlb);
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_version_1);
|
|
|
|
STUFF(isc_dyn_begin);
|
|
|
|
STUFF(isc_dyn_mod_rel);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(symbol->sym_string);
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
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) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_delete_local_fld);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(field->fld_name->sym_string);
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_end);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_end);
|
|
|
|
STUFF(isc_dyn_end);
|
|
|
|
STUFF(isc_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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
void MET_sql_cr_view( qli_syntax* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ s q l _ c r _ v i e w
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Create a view from a SQL metadata request
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_rel* relation = (qli_rel*) node->syn_arg[s_crv_name];
|
2003-09-25 13:49:12 +02:00
|
|
|
DBB database = setup_update(relation->rel_database);
|
|
|
|
relation->rel_database = database;
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* symbol = relation->rel_symbol;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_rlb* rlb = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
rlb = CHECK_RLB(rlb);
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_version_1);
|
|
|
|
STUFF(isc_dyn_begin);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_def_view);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(symbol->sym_string);
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// The meat of the blr generation will go here
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_end);
|
|
|
|
STUFF(isc_dyn_eoc);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
execute_dynamic_ddl(database, rlb);
|
|
|
|
MET_meta_commit(database);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
void MET_sql_grant( qli_syntax* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ s q l _ g r a n t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Grant access privilege(s) on a SQL table
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
sql_grant_revoke(node, isc_dyn_grant);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
void MET_sql_revoke( qli_syntax* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M E T _ s q l _ r e v o k e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Revoke access privilege(s) on a SQL table
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
sql_grant_revoke(node, isc_dyn_revoke);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE 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-11-08 17:40:17 +01:00
|
|
|
isc_commit_transaction(status_vector, &database->dbb_transaction);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_rollback:
|
2003-11-08 17:40:17 +01:00
|
|
|
isc_rollback_transaction(status_vector, &database->dbb_transaction);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_prepare:
|
2003-11-08 17:40:17 +01:00
|
|
|
isc_prepare_transaction(status_vector, &database->dbb_transaction);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_start_trans:
|
2003-11-08 17:40:17 +01:00
|
|
|
isc_start_transaction(status_vector, &database->dbb_transaction, 1,
|
2003-08-30 04:12:44 +02:00
|
|
|
&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);
|
|
|
|
|
2002-12-17 15:58:23 +01:00
|
|
|
return database->dbb_transaction;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01: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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-09-25 13:49:12 +02:00
|
|
|
DBB database = relation->rel_database;
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* relation_name = relation->rel_symbol;
|
|
|
|
qli_symbol* field_name = field->fld_name;
|
|
|
|
qli_symbol* global_field = field->fld_based;
|
2003-09-25 13:49:12 +02:00
|
|
|
if (!global_field)
|
2001-05-23 15:26:42 +02:00
|
|
|
global_field = field_name;
|
|
|
|
|
2003-09-25 13:49:12 +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);
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(251, SafeArg() << field_name->sym_string <<
|
|
|
|
relation_name->sym_string);
|
2004-02-02 12:02:12 +01:00
|
|
|
// Msg251 Field %s already exists in relation %s
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR
|
|
|
|
ON_ERROR
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Check global field. Define it if it doesn't exist.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +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;
|
2004-02-02 12:02:12 +01:00
|
|
|
const qli_symbol* 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);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(relation->rel_database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void add_sql_field( qli_rel* relation, qli_fld* field, USHORT position,
|
|
|
|
qli_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);
|
2003-09-25 13:49:12 +02:00
|
|
|
DBB database = relation->rel_database;
|
2004-02-02 12:02:12 +01:00
|
|
|
const qli_symbol* relation_name = relation->rel_symbol;
|
|
|
|
const qli_symbol* field_name = field->fld_name;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-09-03 07:52:02 +02:00
|
|
|
// Check to see if it already exists 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);
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(251, SafeArg() << field_name->sym_string <<
|
|
|
|
relation_name->sym_string);
|
|
|
|
// Msg251 Field %s already exists in relation %s
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR
|
|
|
|
ON_ERROR
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_def_sql_fld);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(field->fld_name->sym_string);
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_type);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_WORD(2);
|
|
|
|
STUFF_WORD(blr_dtypes[field->fld_dtype]);
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_WORD(2);
|
2003-09-25 13:49:12 +02:00
|
|
|
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);
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_scale);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_WORD(2);
|
|
|
|
STUFF_WORD(field->fld_scale);
|
|
|
|
|
2005-09-03 07:52:02 +02:00
|
|
|
if (DTYPE_IS_EXACT(field->fld_dtype))
|
|
|
|
{
|
|
|
|
STUFF(isc_dyn_fld_precision);
|
|
|
|
STUFF_WORD(2);
|
|
|
|
STUFF_WORD(field->fld_precision);
|
|
|
|
STUFF(isc_dyn_fld_sub_type);
|
|
|
|
STUFF_WORD(2);
|
|
|
|
STUFF_WORD(field->fld_sub_type);
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (position) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_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) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_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);
|
|
|
|
}
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_end);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
static void blob_copy( qli_rlb* rlb, qli_rel* source, ISC_QUAD& 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
|
|
|
|
2003-09-25 13:49:12 +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;
|
2007-04-06 12:10:10 +02:00
|
|
|
UserBlob source_blob(status_vector);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
if (!source_blob.open(DB, source_dbb->dbb_meta_trans, source_blob_id))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2006-01-16 11:01:27 +01:00
|
|
|
rollback_update(source_dbb);
|
2001-05-23 15:26:42 +02:00
|
|
|
ERRQ_database_error(source_dbb, status_vector);
|
|
|
|
}
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
SLONG size, segment_count, max_segment;
|
2007-04-10 12:04:00 +02:00
|
|
|
if (!getBlobSize(source_blob, &size, &segment_count, &max_segment))
|
2007-04-06 12:10:10 +02:00
|
|
|
{
|
|
|
|
rollback_update(source_dbb);
|
|
|
|
ERRQ_database_error(source_dbb, status_vector);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
TEXT fixed_buffer[4096];
|
|
|
|
TEXT* buffer;
|
|
|
|
USHORT buffer_length;
|
2004-03-14 06:51:54 +01:00
|
|
|
if (max_segment < static_cast<SLONG>(sizeof(fixed_buffer))) {
|
2001-05-23 15:26:42 +02:00
|
|
|
buffer_length = sizeof(fixed_buffer);
|
|
|
|
buffer = fixed_buffer;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
buffer_length = max_segment;
|
|
|
|
buffer = (TEXT *) gds__alloc((SLONG) buffer_length);
|
|
|
|
}
|
|
|
|
|
|
|
|
STUFF_WORD((USHORT) size);
|
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
size_t length;
|
|
|
|
while (source_blob.getSegment(buffer_length, buffer, length) && !source_blob.getCode())
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
2007-04-11 18:05:40 +02:00
|
|
|
while (rlb->rlb_data + length > rlb->rlb_limit)
|
2001-05-23 15:26:42 +02:00
|
|
|
rlb = GEN_rlb_extend(rlb);
|
2003-09-25 13:49:12 +02:00
|
|
|
const TEXT* p = buffer;
|
2001-05-23 15:26:42 +02:00
|
|
|
while (length--)
|
|
|
|
STUFF(*p++);
|
|
|
|
}
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
if (status_vector[1] != isc_segstr_eof) {
|
2006-01-16 11:01:27 +01:00
|
|
|
rollback_update(source_dbb);
|
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);
|
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
if (!source_blob.close()) {
|
2006-01-16 11:01:27 +01:00
|
|
|
rollback_update(source_dbb);
|
2001-05-23 15:26:42 +02:00
|
|
|
ERRQ_database_error(source_dbb, status_vector);
|
|
|
|
}
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
//return TRUE;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-09-25 13:49:12 +02:00
|
|
|
DBB database = relation->rel_database;
|
2004-02-02 12:02:12 +01:00
|
|
|
const qli_symbol* relation_name = relation->rel_symbol;
|
|
|
|
const qli_symbol* field_name = field->fld_name;
|
|
|
|
const qli_symbol* global_field = field->fld_based;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (field->fld_dtype) {
|
|
|
|
rollback_update(database);
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(252);
|
2003-09-25 13:49:12 +02:00
|
|
|
// Msg252 datatype can not be changed locally
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (global_field
|
|
|
|
&&
|
2003-09-25 13:49:12 +02:00
|
|
|
!(check_global_field(database, NULL, global_field->sym_string)))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
rollback_update(database);
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(253, global_field->sym_string);
|
2003-09-25 13:49:12 +02:00
|
|
|
// Msg253 global field %s does not exist
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-09-25 13:49:12 +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
|
2003-09-25 13:49:12 +02:00
|
|
|
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);
|
2004-02-02 12:02:12 +01:00
|
|
|
const qli_symbol* symbol = field->fld_query_name;
|
2003-09-25 13:49:12 +02:00
|
|
|
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);
|
2001-07-12 08:32:05 +02:00
|
|
|
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);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
if (!count) {
|
|
|
|
rollback_update(database);
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(254, SafeArg() << field_name->sym_string << relation_name->sym_string);
|
2004-02-20 07:43:27 +01:00
|
|
|
// 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,
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_fld* field,
|
|
|
|
const TEXT* name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2003-09-25 13:49:12 +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
|
2004-02-02 12:02:12 +01:00
|
|
|
* 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])
|
2003-09-25 13:49:12 +02:00
|
|
|
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] ||
|
2004-03-14 06:51:54 +01:00
|
|
|
X.RDB$FIELD_LENGTH != static_cast<SLONG>(
|
|
|
|
((field->fld_dtype == dtype_varying) ? field->fld_length -
|
|
|
|
sizeof(SSHORT) : field->fld_length)) ||
|
2001-05-23 15:26:42 +02:00
|
|
|
X.RDB$FIELD_SCALE != field->fld_scale))
|
|
|
|
{
|
|
|
|
rollback_update(database);
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(255, name);
|
|
|
|
// 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)
|
|
|
|
{
|
2007-04-06 12:10:10 +02:00
|
|
|
ISC_QUAD& blob = X.RDB$QUERY_HEADER;
|
|
|
|
if (!UserBlob::blobIsNull(blob))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
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
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
return previously_defined;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static bool check_relation( qli_rel* relation)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2003-09-25 13:49:12 +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;
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE 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)
|
2003-09-25 13:49:12 +02:00
|
|
|
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
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(relation->rel_database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
DB = spare;
|
|
|
|
return previously_defined;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
static void clone_fields( qli_rel* target, qli_rel* source)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2003-09-25 13:49:12 +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
|
2003-09-25 13:49:12 +02:00
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE req1, req2;
|
|
|
|
FB_API_HANDLE t_trans, s_trans;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 01:06:37 +02:00
|
|
|
req1 = req2 = 0;
|
2002-12-17 15:58:23 +01:00
|
|
|
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) {
|
2004-02-20 07:43:27 +01:00
|
|
|
MET_meta_transaction(source->rel_database, false);
|
2002-12-17 15:58:23 +01:00
|
|
|
s_trans = gds_trans;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (target->rel_database != source->rel_database)
|
|
|
|
clone_global_fields(target, source);
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_rlb* rlb = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
rlb = CHECK_RLB(rlb);
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_version_1);
|
|
|
|
STUFF(isc_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
|
2003-09-25 13:49:12 +02:00
|
|
|
// 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 &&
|
2006-08-31 10:01:24 +02:00
|
|
|
!fb_utils::implicit_domain(Y.RDB$FIELD_NAME) &&
|
|
|
|
fb_utils::implicit_domain(F.RDB$FIELD_NAME))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_def_sql_fld);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(Y.RDB$FIELD_NAME);
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_type);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_WORD(2);
|
|
|
|
STUFF_WORD(F.RDB$FIELD_TYPE);
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_WORD(2);
|
|
|
|
STUFF_WORD(F.RDB$FIELD_LENGTH);
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_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) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_validation_blr);
|
2007-04-06 12:10:10 +02:00
|
|
|
blob_copy(rlb, source, F.RDB$VALIDATION_BLR);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_def_local_fld);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(Y.RDB$FIELD_NAME);
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_source);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(Y.RDB$FIELD_SOURCE);
|
|
|
|
}
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_rel_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(target->rel_symbol->sym_string);
|
|
|
|
|
|
|
|
if (!Y.RDB$FIELD_POSITION.NULL) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_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) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_query_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(Y.RDB$QUERY_NAME);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Y.RDB$EDIT_STRING.NULL) {
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_edit_string);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(Y.RDB$EDIT_STRING);
|
|
|
|
}
|
|
|
|
if (!Y.RDB$UPDATE_FLAG.NULL) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_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) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_query_header);
|
2007-04-06 12:10:10 +02:00
|
|
|
blob_copy(rlb, source, Y.RDB$QUERY_HEADER);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Y.RDB$DESCRIPTION.NULL) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_description);
|
2007-04-06 12:10:10 +02:00
|
|
|
blob_copy(rlb, source, Y.RDB$DESCRIPTION);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Y.RDB$DEFAULT_VALUE.NULL) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_default_value);
|
2007-04-06 12:10:10 +02:00
|
|
|
blob_copy(rlb, source, 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) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_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);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(source->rel_database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
if (!F.RDB$COMPUTED_BLR.NULL)
|
|
|
|
{
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_computed_blr);
|
2007-04-06 12:10:10 +02:00
|
|
|
blob_copy(rlb, source, F.RDB$COMPUTED_BLR);
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_computed_source);
|
2007-04-06 12:10:10 +02:00
|
|
|
blob_copy(rlb, source, F.RDB$COMPUTED_SOURCE);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_type);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_WORD(2);
|
|
|
|
STUFF_WORD(F.RDB$FIELD_TYPE);
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_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) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_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) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_sub_type);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_WORD(2);
|
|
|
|
STUFF_WORD(F.RDB$FIELD_SUB_TYPE);
|
|
|
|
}
|
|
|
|
}
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_end);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR
|
|
|
|
ON_ERROR
|
|
|
|
rollback_update(source->rel_database);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(source->rel_database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_end);
|
|
|
|
STUFF(isc_dyn_eoc);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
execute_dynamic_ddl(target->rel_database, rlb);
|
|
|
|
|
|
|
|
if (req1)
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_release_request(gds_status, &req1))
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(source->rel_database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (req2)
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_release_request(gds_status, &req2))
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(source->rel_database, gds_status);
|
2004-03-07 08:58:55 +01:00
|
|
|
//return TRUE;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
static void clone_global_fields( qli_rel* target, qli_rel* source)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2003-09-25 13:49:12 +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
|
2003-09-25 13:49:12 +02:00
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE req1, req2, req3;
|
|
|
|
req1 = req2 = req3 = 0;
|
2003-09-25 13:49:12 +02:00
|
|
|
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE s_trans = source->rel_database->dbb_meta_trans;
|
|
|
|
FB_API_HANDLE 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;
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_rlb* rlb = NULL;
|
2003-09-25 13:49:12 +02:00
|
|
|
bool first_field = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE req1
|
|
|
|
TRANSACTION_HANDLE s_trans)
|
2004-11-24 10:22:07 +01:00
|
|
|
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
|
|
|
|
if (!Y.RDB$COMPUTED_BLR.NULL ||
|
2006-08-31 10:01:24 +02:00
|
|
|
(!fb_utils::implicit_domain(RFR.RDB$FIELD_NAME) &&
|
|
|
|
fb_utils::implicit_domain(Y.RDB$FIELD_NAME)))
|
2004-11-24 10:22:07 +01:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-11-24 10:22:07 +01:00
|
|
|
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
|
2004-11-24 10:22:07 +01:00
|
|
|
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)))
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-11-24 10:22:07 +01:00
|
|
|
TEXT* name = (TEXT*) ALLQ_malloc((SLONG) sizeof(Y.RDB$FIELD_NAME));
|
2003-09-25 13:49:12 +02:00
|
|
|
strcpy(name, Y.RDB$FIELD_NAME);
|
|
|
|
rollback_update(target->rel_database);
|
|
|
|
// CVC: When is this memory deallocated?
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_error(413, name);
|
2003-09-25 13:49:12 +02:00
|
|
|
// conflicting previous definition
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
2003-09-25 13:49:12 +02:00
|
|
|
predefined = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR
|
|
|
|
ON_ERROR
|
2001-07-12 08:32:05 +02:00
|
|
|
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);
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_version_1);
|
|
|
|
STUFF(isc_dyn_begin);
|
2003-09-25 13:49:12 +02:00
|
|
|
first_field = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_def_global_fld);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(Y.RDB$FIELD_NAME);
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_type);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_WORD(2);
|
|
|
|
STUFF_WORD(Y.RDB$FIELD_TYPE);
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_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) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_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) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_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) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_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) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_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) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_query_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(Y.RDB$QUERY_NAME);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Y.RDB$EDIT_STRING.NULL) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_edit_string);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(Y.RDB$EDIT_STRING);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Y.RDB$MISSING_VALUE.NULL) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_missing_value);
|
2007-04-06 12:10:10 +02:00
|
|
|
blob_copy(rlb, source, Y.RDB$MISSING_VALUE);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Y.RDB$DEFAULT_VALUE.NULL) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_default_value);
|
2007-04-06 12:10:10 +02:00
|
|
|
blob_copy(rlb, source, Y.RDB$DEFAULT_VALUE);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Y.RDB$QUERY_HEADER.NULL) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_query_header);
|
2007-04-06 12:10:10 +02:00
|
|
|
blob_copy(rlb, source, Y.RDB$QUERY_HEADER);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Y.RDB$DESCRIPTION.NULL) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_description);
|
2007-04-06 12:10:10 +02:00
|
|
|
blob_copy(rlb, source, Y.RDB$DESCRIPTION);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Y.RDB$VALIDATION_BLR.NULL) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_validation_blr);
|
2007-04-06 12:10:10 +02:00
|
|
|
blob_copy(rlb, source, Y.RDB$VALIDATION_BLR);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Y.RDB$VALIDATION_SOURCE.NULL) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_validation_source);
|
2007-04-06 12:10:10 +02:00
|
|
|
blob_copy(rlb, source, Y.RDB$VALIDATION_SOURCE);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((target->rel_database->dbb_capabilities & DBB_cap_dimensions) &&
|
2004-02-20 07:43:27 +01:00
|
|
|
(source->rel_database->dbb_capabilities & DBB_cap_dimensions))
|
|
|
|
{
|
2003-09-25 13:49:12 +02:00
|
|
|
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
|
2003-09-25 13:49:12 +02:00
|
|
|
F.RDB$FIELD_NAME = Y.RDB$FIELD_NAME
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-11-24 10:22:07 +01:00
|
|
|
if (first_dimension) {
|
2003-09-25 13:49:12 +02:00
|
|
|
first_dimension = false;
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_dimensions);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_WORD(2);
|
|
|
|
STUFF_WORD(F.RDB$DIMENSIONS);
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-11-24 10:22:07 +01:00
|
|
|
STUFF(isc_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) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_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) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_dim_upper);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_WORD(2);
|
|
|
|
STUFF_WORD(D.RDB$UPPER_BOUND);
|
|
|
|
}
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_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);
|
2006-01-16 17:46:40 +01:00
|
|
|
rollback_update(source->rel_database);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(source->rel_database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
}
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_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);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(source->rel_database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
if (rlb) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_end);
|
|
|
|
STUFF(isc_dyn_eoc);
|
2001-05-23 15:26:42 +02:00
|
|
|
execute_dynamic_ddl(target->rel_database, rlb);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (req1)
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_release_request(gds_status, &req1))
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(source->rel_database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (req2)
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_release_request(gds_status, &req2))
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(target->rel_database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (req3)
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_release_request(gds_status, &req3))
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(source->rel_database, gds_status);
|
2004-03-07 08:58:55 +01:00
|
|
|
//return TRUE;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void define_global_field( DBB database, qli_fld* field, qli_symbol* name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2003-09-25 13:49:12 +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);
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(256, name->sym_string); // Msg256 No datatype specified for field %s
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-09-25 13:49:12 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
STORE(REQUEST_HANDLE database->dbb_requests[REQ_store_field])
|
2003-09-25 13:49:12 +02:00
|
|
|
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;
|
2004-02-02 12:02:12 +01:00
|
|
|
const qli_symbol* symbol = field->fld_query_name;
|
2003-09-25 13:49:12 +02:00
|
|
|
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);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-02 12:02:12 +01:00
|
|
|
while (qli_fld* field = relation->rel_fields) {
|
2001-05-23 15:26:42 +02:00
|
|
|
relation->rel_fields = field->fld_next;
|
2004-05-16 03:42:11 +02:00
|
|
|
ALLQ_release((FRB) field->fld_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (field->fld_query_name)
|
2004-05-16 03:42:11 +02:00
|
|
|
ALLQ_release((FRB) field->fld_query_name);
|
|
|
|
ALLQ_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
|
|
|
|
2003-09-25 13:49:12 +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-11-08 17:40:17 +01:00
|
|
|
if (isc_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-11-08 17:40:17 +01:00
|
|
|
if (isc_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-11-08 17:40:17 +01:00
|
|
|
if (isc_commit_transaction(status, &dbb->dbb_meta_trans))
|
2001-05-23 15:26:42 +02:00
|
|
|
status = alt_vector;
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
isc_detach_database(status, &dbb->dbb_handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return status_vector[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void execute_dynamic_ddl( DBB database, qli_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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-09-25 13:49:12 +02:00
|
|
|
const USHORT length = (UCHAR *) rlb->rlb_data - (UCHAR *) rlb->rlb_base;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (QLI_blr)
|
2003-09-28 23:36:05 +02:00
|
|
|
PRETTY_print_dyn(rlb->rlb_base, NULL, NULL, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_ddl(gds_status, &database->dbb_handle, &database->dbb_meta_trans,
|
2004-02-20 07:43:27 +01:00
|
|
|
length, (const char*) rlb->rlb_base))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
rollback_update(database);
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-05-16 03:42:11 +02:00
|
|
|
GEN_rlb_release (rlb);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
2004-06-03 16:00:59 +02:00
|
|
|
case dtype_int64:
|
|
|
|
return sizeof(SINT64);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case dtype_sql_time:
|
|
|
|
case dtype_sql_date:
|
|
|
|
return sizeof(SLONG);
|
|
|
|
|
|
|
|
case dtype_timestamp:
|
|
|
|
case dtype_blob:
|
|
|
|
case dtype_quad:
|
2003-11-11 13:19:20 +01:00
|
|
|
return sizeof(ISC_QUAD);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2003-09-25 13:49:12 +02:00
|
|
|
* 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;
|
2003-09-25 13:49:12 +02:00
|
|
|
UCHAR buffer[1024];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
isc_database_info(status_vector, &new_dbb->dbb_handle, sizeof(db_info),
|
2003-10-29 11:53:47 +01:00
|
|
|
reinterpret_cast<const char*>(db_info),
|
|
|
|
sizeof(buffer), (char*) buffer);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (status_vector[1])
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(new_dbb, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
UCHAR* p = buffer;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
while (*p != isc_info_end && p < buffer + sizeof(buffer)) {
|
2003-09-25 13:49:12 +02:00
|
|
|
UCHAR item = *p++;
|
2003-11-16 02:52:44 +01:00
|
|
|
USHORT l = gds__vax_integer(p, 2);
|
2001-05-23 15:26:42 +02:00
|
|
|
p += 2;
|
|
|
|
switch (item) {
|
2003-11-08 17:40:17 +01:00
|
|
|
case isc_info_implementation:
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
|
|
|
const UCHAR* q = p;
|
|
|
|
int count = *q++;
|
2001-05-23 15:26:42 +02:00
|
|
|
while (count--) {
|
|
|
|
new_dbb->dbb_type = *q++;
|
2003-11-08 17:40:17 +01:00
|
|
|
if (*q++ == isc_info_db_class_access)
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
default:
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_error(257);
|
2003-09-25 13:49:12 +02:00
|
|
|
// Msg257 database info call failed
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
p += l;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
static TEXT *get_query_header( DBB database, ISC_QUAD& blob_id)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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;
|
2003-09-25 13:49:12 +02:00
|
|
|
TEXT header[1024], buffer[1024];
|
2007-04-06 12:10:10 +02:00
|
|
|
UserBlob blob(status_vector);
|
2003-02-08 01:58:10 +01:00
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
if (!blob.open(database->dbb_handle, gds_trans, blob_id))
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
ERRQ_database_error(database, status_vector);
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
TEXT* p = header;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +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 (;;) {
|
2007-04-06 12:10:10 +02:00
|
|
|
size_t length;
|
|
|
|
if (!blob.getSegment(sizeof(buffer), buffer, length))
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
if (length && buffer[length - 1] == '\n')
|
|
|
|
--length;
|
|
|
|
buffer[length] = 0;
|
2003-09-25 13:49:12 +02:00
|
|
|
const TEXT* q = buffer;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*q == '"')
|
2003-09-25 13:49:12 +02:00
|
|
|
do {
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = *q++;
|
2003-09-25 13:49:12 +02:00
|
|
|
} while (*q);
|
2001-05-23 15:26:42 +02:00
|
|
|
else {
|
|
|
|
*p++ = '"';
|
|
|
|
while (*q)
|
|
|
|
*p++ = *q++;
|
|
|
|
*p++ = '"';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
if (!blob.close())
|
2001-07-12 08:32:05 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
const USHORT len = p - header;
|
|
|
|
if (len)
|
|
|
|
return make_string(header, len);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-31 10:01:24 +02:00
|
|
|
static void install( dbb* old_dbb)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Copy the database block to one out of the permanent pool
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +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;
|
2006-08-31 10:01:24 +02:00
|
|
|
memcpy(new_dbb->dbb_filename, old_dbb->dbb_filename, 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;
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// If a name was given, make up a symbol for the database.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-08-31 10:01:24 +02:00
|
|
|
nam* name = (nam*) old_dbb->dbb_symbol;
|
2003-09-25 13:49:12 +02:00
|
|
|
if (name) {
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* asymbol = make_symbol(name->nam_string, name->nam_length);
|
2003-09-25 13:49:12 +02:00
|
|
|
new_dbb->dbb_symbol = asymbol;
|
|
|
|
asymbol->sym_type = SYM_database;
|
|
|
|
asymbol->sym_object = (BLK) new_dbb;
|
2005-08-19 08:07:12 +02:00
|
|
|
HSH_insert(asymbol, true);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2001-07-12 08:32:05 +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
|
2003-09-25 13:49:12 +02:00
|
|
|
relation block, make up a symbol block, and insert the symbol
|
2001-05-23 15:26:42 +02:00
|
|
|
into the hash table. */
|
|
|
|
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE request = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +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
|
|
|
|
2004-02-02 12:02:12 +01: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;
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* rsymbol = make_symbol(X.RDB$RELATION_NAME, sizeof(X.RDB$RELATION_NAME));
|
2003-09-25 13:49:12 +02:00
|
|
|
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
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(new_dbb, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
|
|
|
|
if (request)
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_release_request(gds_status, &request))
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(new_dbb, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Pick up functions, if appropriate
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (new_dbb->dbb_capabilities & DBB_cap_functions) {
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE request2 = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
FOR(REQUEST_HANDLE request) X IN DB.RDB$FUNCTIONS
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* fsymbol = make_symbol(X.RDB$FUNCTION_NAME, sizeof(X.RDB$FUNCTION_NAME));
|
2003-09-25 13:49:12 +02:00
|
|
|
if (!fsymbol)
|
2001-05-23 15:26:42 +02:00
|
|
|
continue;
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_fun* function = (qli_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;
|
2003-09-25 13:49:12 +02:00
|
|
|
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
|
2003-09-25 13:49:12 +02:00
|
|
|
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
|
2001-07-12 08:32:05 +02:00
|
|
|
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;
|
|
|
|
}
|
2003-09-25 13:49:12 +02:00
|
|
|
fsymbol->sym_type = SYM_function;
|
|
|
|
fsymbol->sym_object = (BLK) function;
|
|
|
|
HSH_insert(fsymbol);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Insert another symbol if there is a function query name
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* symbol2 = make_symbol(X.RDB$QUERY_NAME, sizeof(X.RDB$QUERY_NAME));
|
2003-09-25 13:49:12 +02:00
|
|
|
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;
|
2005-08-19 08:07:12 +02:00
|
|
|
HSH_insert(symbol2, true);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
END_FOR
|
|
|
|
ON_ERROR
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(new_dbb, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
if (request)
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_release_request(gds_status, &request))
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(new_dbb, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (request2)
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_release_request(gds_status, &request2))
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(new_dbb, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
static qli_syntax* make_node( NOD_T type, USHORT count)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m a k e _ n o d e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Generate a syntax node.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-03-07 08:58:55 +01:00
|
|
|
qli_syntax* node = (qli_syntax*) ALLOCPV(type_syn, count);
|
2001-05-23 15:26:42 +02:00
|
|
|
node->syn_count = count;
|
|
|
|
node->syn_type = type;
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
static TEXT *make_string( TEXT* string, SSHORT length)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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;
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_str* str = (qli_str*) ALLOCPV(type_str, length + 1);
|
2003-09-25 13:49:12 +02:00
|
|
|
TEXT* p = str->str_data;
|
|
|
|
do {
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = *string++;
|
2003-09-25 13:49:12 +02:00
|
|
|
} while (--length);
|
2001-05-23 15:26:42 +02:00
|
|
|
*p = 0;
|
|
|
|
|
|
|
|
return str->str_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
static qli_symbol* make_symbol( TEXT* string, SSHORT length)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m a k e _ s y m b o l
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2003-09-25 13:49:12 +02:00
|
|
|
* 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;
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* symbol = (qli_symbol*) ALLOCPV(type_sym, length);
|
2001-05-23 15:26:42 +02:00
|
|
|
symbol->sym_type = SYM_relation;
|
|
|
|
symbol->sym_length = length;
|
2003-09-25 13:49:12 +02:00
|
|
|
TEXT* p = symbol->sym_name;
|
|
|
|
symbol->sym_string = p;
|
|
|
|
do {
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = *string++;
|
2003-09-25 13:49:12 +02:00
|
|
|
} while (--length);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return symbol;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
static qli_const* missing_value( ISC_QUAD& blob_id, qli_symbol* symbol)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m i s s i n g _ v a l u e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get a missing value into a constant
|
2003-09-25 13:49:12 +02:00
|
|
|
* block for later reference.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
2004-03-07 08:58:55 +01:00
|
|
|
qli_syntax* element = parse_blr_blob(blob_id, symbol);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (element)
|
2004-02-02 12:02:12 +01:00
|
|
|
return ((qli_const*) element->syn_arg[0]);
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
static qli_syntax* parse_blr( UCHAR ** ptr, qli_symbol* symbol)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* p a r s e _ b l r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Parse a BLR expression.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-03-07 08:58:55 +01:00
|
|
|
qli_syntax* *arg;
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_const* constant;
|
2001-07-12 08:32:05 +02:00
|
|
|
NOD_T operatr;
|
2001-05-23 15:26:42 +02:00
|
|
|
NAM name;
|
2003-09-25 13:49:12 +02:00
|
|
|
UCHAR *p;
|
|
|
|
SSHORT dtype, scale, length, l, op;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
UCHAR* blr = *ptr;
|
|
|
|
SSHORT args = 2;
|
2004-03-07 08:58:55 +01:00
|
|
|
qli_syntax* 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:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_eql;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_neq:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_neq;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_gtr:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_gtr;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_geq:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_geq;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_lss:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_lss;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_leq:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_leq;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_containing:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_containing;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_starting:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_starts;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_matching:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_matches;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_matching2:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_sleuth;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_like:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_like;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_and:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_and;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_or:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_or;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_add:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_add;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_subtract:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_subtract;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_multiply:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_multiply;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_divide:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_divide;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case blr_upcase:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_upcase;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2005-05-28 00:45:31 +02:00
|
|
|
case blr_lowcase:
|
|
|
|
operatr = nod_lowcase;
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
case blr_null:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_null;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_between:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_between;
|
2001-05-23 15:26:42 +02:00
|
|
|
args = 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_not:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_not;
|
2001-05-23 15:26:42 +02:00
|
|
|
args = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_negate:
|
2001-07-12 08:32:05 +02:00
|
|
|
operatr = nod_negate;
|
2001-05-23 15:26:42 +02:00
|
|
|
args = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_missing:
|
2001-07-12 08:32:05 +02:00
|
|
|
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);
|
2004-03-07 08:58:55 +01:00
|
|
|
node->syn_arg[0] = (qli_syntax*) name;
|
2001-05-23 15:26:42 +02:00
|
|
|
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);
|
2004-03-07 08:58:55 +01:00
|
|
|
node->syn_arg[0] = (qli_syntax*) name;
|
2001-05-23 15:26:42 +02:00
|
|
|
name->nam_length = length;
|
|
|
|
p = (UCHAR *) name->nam_string;
|
2003-09-25 13:49:12 +02:00
|
|
|
do {
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = BLR_BYTE;
|
2003-09-25 13:49:12 +02:00
|
|
|
} 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);
|
2004-03-07 08:58:55 +01:00
|
|
|
node->syn_arg[s_fun_function] = (qli_syntax*) 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;
|
2003-11-16 02:52:44 +01:00
|
|
|
length = l = gds__vax_integer(blr, 2);
|
2001-05-23 15:26:42 +02:00
|
|
|
blr += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_text2:
|
|
|
|
dtype = dtype_text;
|
2003-11-16 02:52:44 +01:00
|
|
|
scale = gds__vax_integer(blr, 2);
|
2001-05-23 15:26:42 +02:00
|
|
|
blr += 2;
|
2003-11-16 02:52:44 +01:00
|
|
|
length = l = gds__vax_integer(blr, 2);
|
2001-05-23 15:26:42 +02:00
|
|
|
blr += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_varying:
|
|
|
|
dtype = dtype_varying;
|
2003-11-16 02:52:44 +01:00
|
|
|
length = l = gds__vax_integer(blr, 2) + sizeof(USHORT);
|
2001-05-23 15:26:42 +02:00
|
|
|
blr += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_varying2:
|
|
|
|
dtype = dtype_varying;
|
2003-11-16 02:52:44 +01:00
|
|
|
scale = gds__vax_integer(blr, 2);
|
2001-05-23 15:26:42 +02:00
|
|
|
blr += 2;
|
2003-11-16 02:52:44 +01:00
|
|
|
length = l = gds__vax_integer(blr, 2) + sizeof(USHORT);
|
2001-05-23 15:26:42 +02:00
|
|
|
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;
|
2003-11-11 13:19:20 +01:00
|
|
|
length = sizeof(ISC_QUAD);
|
2001-05-23 15:26:42 +02:00
|
|
|
scale = (int) BLR_BYTE;
|
|
|
|
break;
|
|
|
|
|
2002-12-13 15:12:54 +01:00
|
|
|
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;
|
2003-11-11 13:19:20 +01:00
|
|
|
length = sizeof(ISC_QUAD);
|
2001-05-23 15:26:42 +02:00
|
|
|
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;
|
|
|
|
}
|
2004-02-02 12:02:12 +01:00
|
|
|
constant = (qli_const*) ALLOCPV(type_con, length);
|
2001-05-23 15:26:42 +02:00
|
|
|
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) {
|
2003-11-16 02:52:44 +01:00
|
|
|
*(SSHORT *) p = gds__vax_integer(blr, l);
|
2001-05-23 15:26:42 +02:00
|
|
|
blr += l;
|
|
|
|
}
|
|
|
|
else if (dtype == dtype_long) {
|
2003-11-16 02:52:44 +01:00
|
|
|
*(SLONG *) p = gds__vax_integer(blr, l);
|
2001-05-23 15:26:42 +02:00
|
|
|
blr += l;
|
|
|
|
}
|
|
|
|
node = make_node(nod_constant, 1);
|
|
|
|
node->syn_count = 0;
|
2004-03-07 08:58:55 +01:00
|
|
|
node->syn_arg[0] = (qli_syntax*) constant;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(258, SafeArg() << op); // Msg258 don't understand BLR operatr %d
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!node) {
|
2001-07-12 08:32:05 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
static qli_syntax* parse_blr_blob(ISC_QUAD& blob_id, qli_symbol* symbol)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* p a r s e _ b l r _ b l o b
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2003-09-25 13:49:12 +02:00
|
|
|
* 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
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
if (UserBlob::blobIsNull(blob_id))
|
2001-05-23 15:26:42 +02:00
|
|
|
return NULL;
|
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
UserBlob handle(status_vector);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
if (!handle.open(DB, gds_trans, blob_id))
|
2003-08-30 04:12:44 +02:00
|
|
|
return NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
UCHAR buffer[1024];
|
|
|
|
UCHAR* ptr = buffer;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
for (;;) {
|
2007-04-06 12:10:10 +02:00
|
|
|
size_t length = buffer + sizeof(buffer) - ptr;
|
2003-09-25 13:49:12 +02:00
|
|
|
if (!length)
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2007-04-06 12:10:10 +02:00
|
|
|
// The old code considered getting a portion of a segment a bug.
|
|
|
|
// Anyway, 1024 is not much to contain the BLR stream, even for validation.
|
|
|
|
if (!handle.getSegment(length, ptr, length) || handle.getCode())
|
2003-08-30 04:12:44 +02:00
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
ptr += length;
|
|
|
|
}
|
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
if (!handle.close())
|
2001-05-23 15:26:42 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (ptr == buffer)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ptr = buffer;
|
|
|
|
|
|
|
|
if (*ptr++ != blr_version4)
|
|
|
|
return NULL;
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
qli_syntax* node = parse_blr(&ptr, symbol);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (*ptr != blr_eoc)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_symbol* symbol = relation->rel_symbol;
|
2003-09-25 13:49:12 +02:00
|
|
|
DBB database = relation->rel_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
HSH_remove(symbol);
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
for (qli_rel** ptr = &database->dbb_relations; *ptr; ptr = &(*ptr)->rel_next)
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*ptr == relation) {
|
|
|
|
*ptr = relation->rel_next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_fld* field;
|
2001-05-23 15:26:42 +02:00
|
|
|
while (field = relation->rel_fields) {
|
|
|
|
relation->rel_fields = field->fld_next;
|
2001-07-12 08:32:05 +02:00
|
|
|
ALLQ_release((FRB) field->fld_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (symbol = field->fld_query_name) {
|
2001-07-12 08:32:05 +02:00
|
|
|
ALLQ_release((FRB) symbol);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2001-07-12 08:32:05 +02:00
|
|
|
ALLQ_release((FRB) field);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-05-16 03:42:11 +02:00
|
|
|
ALLQ_release((FRB) relation);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void put_dyn_string( qli_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.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2001-07-12 08:32:05 +02:00
|
|
|
if (gds_trans == database->dbb_meta_trans &&
|
2001-05-23 15:26:42 +02:00
|
|
|
(database->dbb_capabilities & DBB_cap_multi_trans))
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
|
|
|
ISC_STATUS_ARRAY alt_vector;
|
2003-11-08 17:40:17 +01:00
|
|
|
isc_rollback_transaction(alt_vector, &database->dbb_meta_trans);
|
2003-09-25 13:49:12 +02:00
|
|
|
// Note: No message given if rollback fails
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 01:06:37 +02:00
|
|
|
gds_trans = 0;
|
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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE req = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Look for desireable fields in system relations
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +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
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (req)
|
2007-04-06 12:10:10 +02:00
|
|
|
{
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_release_request(gds_status, &req))
|
2001-07-12 08:32:05 +02:00
|
|
|
ERRQ_database_error(database, gds_status);
|
2007-04-06 12:10:10 +02:00
|
|
|
}
|
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
|
2003-09-25 13:49:12 +02:00
|
|
|
* most recently readied one.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
if (!database)
|
|
|
|
database = QLI_databases;
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
MET_meta_transaction(database, true);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return database;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
static void sql_grant_revoke( qli_syntax* node, USHORT type)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/*****************************************************
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*
|
|
|
|
*****************************************************/
|
2004-03-14 06:51:54 +01:00
|
|
|
const USHORT privileges = (IPTR) node->syn_arg[s_grant_privileges];
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_rel* relation = (qli_rel*) node->syn_arg[s_grant_relation];
|
2003-09-25 13:49:12 +02:00
|
|
|
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
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_rlb* rlb = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
rlb = CHECK_RLB(rlb);
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_version_1);
|
|
|
|
STUFF(isc_dyn_begin);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +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
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
qli_syntax* names = node->syn_arg[s_grant_users];
|
|
|
|
qli_syntax* fields = node->syn_arg[s_grant_fields];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
NAM* name = (NAM*) names->syn_arg;
|
|
|
|
for (NAM* const end = name + names->syn_count;
|
2001-05-23 15:26:42 +02:00
|
|
|
name < end; name++)
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (fields->syn_count) {
|
2003-09-25 13:49:12 +02:00
|
|
|
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);
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
stuff_priv(rlb, type, relation_name, privileges,
|
2003-08-28 12:55:19 +02:00
|
|
|
(*name)->nam_string, NULL);
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_end);
|
|
|
|
STUFF(isc_dyn_eoc);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
execute_dynamic_ddl(database, rlb);
|
|
|
|
MET_meta_commit(database);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
static int truncate_string( TEXT* string)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-09-26 09:48:29 +02:00
|
|
|
const int len = fb_utils::name_length(string);
|
|
|
|
string[len] = 0;
|
|
|
|
return len;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void stuff_priv(
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_rlb* rlb,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT type,
|
2003-09-25 13:49:12 +02:00
|
|
|
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);
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Stuff privileges first
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +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');
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_rel_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(relation);
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_grant_user);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(user);
|
|
|
|
|
|
|
|
if (field) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_fld_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_STRING(field);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (privileges & PRV_grant_option) {
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_grant_options);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF_WORD(2);
|
|
|
|
STUFF_WORD(TRUE);
|
|
|
|
}
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
STUFF(isc_dyn_end);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|