8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-27 20:03:03 +01:00
firebird-mirror/src/dsql/ddl.cpp

6352 lines
176 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: Dynamic SQL runtime support
2003-10-05 08:33:56 +02:00
* MODULE: ddl.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Utilities for generating ddl
*
* 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): ______________________________________.
*
* $Id: ddl.cpp,v 1.115 2004-10-03 04:48:37 robocop Exp $
2001-05-23 15:26:42 +02:00
* 2001.5.20 Claudio Valderrama: Stop null pointer that leads to a crash,
* caused by incomplete yacc syntax that allows ALTER DOMAIN dom SET;
*
* 2001.07.06 Sean Leyne - Code Cleanup, removed "#ifdef READONLY_DATABASE"
* conditionals, as the engine now fully supports
* readonly databases.
2001-12-24 03:51:06 +01:00
* December 2001 Mike Nordell - Attempt to make it C++
2002-06-29 08:56:51 +02:00
*
* 2001.5.20 Claudio Valderrama: Stop null pointer that leads to a crash,
* caused by incomplete yacc syntax that allows ALTER DOMAIN dom SET;
* 2001.5.29 Claudio Valderrama: Check for view v/s relation in DROP
* command will stop a user that uses DROP VIEW and drops a table by
* accident and vice-versa.
* 2001.5.30 Claudio Valderrama: alter column should use 1..N for the
* position argument since the call comes from SQL DDL.
* 2001.6.27 Claudio Valderrama: DDL_resolve_intl_type() was adding 2 to the
* length of varchars instead of just checking that len+2<=MAX_COLUMN_SIZE.
* It required a minor change to put_field() where it was decremented, too.
* 2001.6.27 Claudio Valderrama: Finally stop users from invoking the same option
* several times when altering a domain. Specially dangerous with text data types.
* Ex: alter domain d type char(5) type varchar(5) default 'x' default 'y';
* Bear in mind that if DYN functions are addressed directly, this protection
* becomes a moot point.
* 2001.6.30 Claudio Valderrama: revert changes from 2001.6.26 because the code
* is called from several places and there are more functions, even in metd.c,
* playing the same nonsense game with the field's length, so it needs more
* careful examination. For now, the new checks in DYN_MOD should catch most anomalies.
* 2001.7.3 Claudio Valderrama: fix Firebird Bug #223059 with mismatch between number
* of declared fields for a VIEW and effective fields in the SELECT statement.
* 2001.07.22 Claudio Valderrama: minor fixes and improvements.
* 2001.08.18 Claudio Valderrama: RECREATE PROCEDURE.
* 2001.10.01 Claudio Valderrama: modify_privilege() should recognize that a ROLE can
* now be made an explicit grantee.
* 2001.10.08 Claudio Valderrama: implement frb_sysflag enum values for autogenerated
* non-system triggers so DFW can recognize them easily.
* 2001.10.26 Claudio Valderrama: added a call to the new METD_drop_function()
* in DDL_execute() so the metadata cache for udfs can be refreshed.
* 2001.12.06 Claudio Valderrama: DDL_resolve_intl_type should calculate field length
* 2002.08.04 Claudio Valderrama: allow declaring and defining variables at the same time
* 2002.08.04 Dmitry Yemanov: ALTER VIEW
* 2002.08.31 Dmitry Yemanov: allowed user-defined index names for PK/FK/UK constraints
* 2002.09.01 Dmitry Yemanov: RECREATE VIEW
* 2002.09.12 Nickolay Samofatov: fixed cached metadata errors
* 2004.01.16 Vlad Horsun: added support for default parameters and
* EXECUTE BLOCK statement
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2004-04-29 00:00:03 +02:00
#include <stdio.h>
2001-05-23 15:26:42 +02:00
#include <string.h>
#include "../dsql/dsql.h"
2003-11-08 00:27:24 +01:00
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/thd.h"
#include "../jrd/intl.h"
#include "../jrd/flags.h"
#include "../jrd/constants.h"
#include "../dsql/alld_proto.h"
#include "../dsql/errd_proto.h"
#include "../dsql/ddl_proto.h"
#include "../dsql/gen_proto.h"
#include "../dsql/make_proto.h"
#include "../dsql/metd_proto.h"
#include "../dsql/pass1_proto.h"
#include "../jrd/sch_proto.h"
#include "../jrd/thread_proto.h"
#include "../jrd/gds_proto.h"
2001-05-23 15:26:42 +02:00
#ifdef DSQL_DEBUG
2001-05-23 15:26:42 +02:00
#include "../gpre/prett_proto.h"
#endif
2003-09-28 02:36:28 +02:00
const int BLOB_BUFFER_SIZE = 4096; // to read in blr blob for default values
2001-05-23 15:26:42 +02:00
2002-06-29 08:56:51 +02:00
static void assign_field_length(dsql_fld*, USHORT);
static bool is_array_or_blob(const dsql_nod*);
static void check_constraint(dsql_req*, dsql_nod*, bool);
2003-09-13 12:26:47 +02:00
static void check_one_call(USHORT*, SSHORT, const TEXT*);
static void create_view_triggers(dsql_req*, dsql_nod*, dsql_nod*);
static void define_computed(dsql_req*, dsql_nod*, dsql_fld*, dsql_nod*);
static void define_constraint_trigger(dsql_req*, dsql_nod*);
static void define_database(dsql_req*);
static void define_del_cascade_trg(dsql_req*, const dsql_nod*, const dsql_nod*,
const dsql_nod*, const char*, const char*);
//static void define_del_default_trg(dsql_req*, dsql_nod*, dsql_nod*, dsql_nod*, TEXT*, TEXT*);
static void define_dimensions(dsql_req*, const dsql_fld*);
static void define_domain(dsql_req*);
static void define_exception(dsql_req*, NOD_TYPE);
2003-11-10 10:16:38 +01:00
static void define_field(dsql_req*, dsql_nod*, SSHORT, const dsql_str*);
static void define_filter(dsql_req*);
2004-09-08 14:01:30 +02:00
static SSHORT getBlobFilterSubType(dsql_req* request, const dsql_nod* node);
static void define_generator(dsql_req*);
static void define_role(dsql_req*);
static void define_index(dsql_req*);
#ifdef NOT_USED_OR_REPLACED
static dsql_nod* define_insert_action(dsql_req*);
#endif
static void define_procedure(dsql_req*, NOD_TYPE);
static void define_rel_constraint(dsql_req*, dsql_nod*);
static void define_relation(dsql_req*);
static void define_set_null_trg(dsql_req*, const dsql_nod*, const dsql_nod*,
const dsql_nod*, const char*, const char*, bool);
static void define_set_default_trg(dsql_req*, const dsql_nod*, const dsql_nod*,
const dsql_nod*, const char*, const char*, bool);
static void define_shadow(dsql_req*);
static void define_trigger(dsql_req*, dsql_nod*);
static void define_udf(dsql_req*);
static void define_update_action(dsql_req*, dsql_nod**, dsql_nod**);
static void define_upd_cascade_trg(dsql_req*, const dsql_nod*, const dsql_nod*,
const dsql_nod*, const char*, const char*);
static void define_view(dsql_req*, NOD_TYPE);
static void define_view_trigger(dsql_req*, dsql_nod*, dsql_nod*, dsql_nod*);
static void delete_procedure(dsql_req*, dsql_nod*, bool);
static void delete_relation_view(dsql_req*, dsql_nod*, bool);
static void foreign_key(dsql_req*, dsql_nod*, const char* index_name);
static void generate_dyn(dsql_req*, dsql_nod*);
static void grant_revoke(dsql_req*);
static void make_index(dsql_req*, const dsql_nod*, const dsql_nod*,
const dsql_nod*, const char*, const char*);
static void make_index_trg_ref_int(dsql_req*, dsql_nod*, dsql_nod*, dsql_nod*,
2003-10-16 10:51:06 +02:00
const char*, const char*);
static void modify_database(dsql_req*);
static void modify_domain(dsql_req*);
2003-11-10 10:16:38 +01:00
static void modify_field(dsql_req*, dsql_nod*, SSHORT, const dsql_str*);
static void modify_index(dsql_req*);
static void modify_privilege(dsql_req*, NOD_TYPE, SSHORT, const UCHAR*,
2003-11-10 10:16:38 +01:00
const dsql_nod*, const dsql_nod*, const dsql_str*);
static SCHAR modify_privileges(dsql_req*, NOD_TYPE, SSHORT, const dsql_nod*,
const dsql_nod*, const dsql_nod*);
static void modify_relation(dsql_req*);
2004-02-02 12:02:12 +01:00
static dsql_par* parameter_reverse_order(dsql_par* parameter, dsql_par* prev);
static void process_role_nm_list(dsql_req*, SSHORT, dsql_nod*, dsql_nod*, NOD_TYPE);
static void put_descriptor(dsql_req*, const dsc*);
static void put_dtype(dsql_req*, const dsql_fld*, bool);
static void put_field(dsql_req*, dsql_fld*, bool);
2004-02-02 12:02:12 +01:00
static void put_local_variable(dsql_req*, dsql_var*, dsql_nod*);
static void put_local_variables(dsql_req*, dsql_nod*, SSHORT);
static void put_msg_field(dsql_req*, dsql_fld*);
static dsql_nod* replace_field_names(dsql_nod*, dsql_nod*, dsql_nod*, bool);
static void reset_context_stack(dsql_req*);
static void save_field(dsql_req*, const SCHAR*);
2003-11-10 10:16:38 +01:00
static void save_relation(dsql_req*, const dsql_str*);
static void set_statistics(dsql_req*);
static void stuff_default_blr(dsql_req*, const TEXT*, USHORT);
static void stuff_matching_blr(dsql_req*, const dsql_nod*, const dsql_nod*);
static void stuff_trg_firing_cond(dsql_req*, const dsql_nod*);
static void set_nod_value_attributes(dsql_nod*, const dsql_fld*);
2001-05-23 15:26:42 +02:00
#ifdef BLKCHK
#undef BLKCHK
#endif
#ifdef DEV_BUILD
2003-10-16 10:51:06 +02:00
static inline void BLKCHK(const void* p, const USHORT type)
2001-12-24 03:51:06 +01:00
{
if (p && MemoryPool::blk_type(p) != type) {
ERRD_bugcheck("Invalid block type");
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
#else
2003-10-16 10:51:06 +02:00
static inline void BLKCHK(const void* p, const USHORT type)
{
2003-09-28 02:36:28 +02:00
}
2001-05-23 15:26:42 +02:00
#endif
2003-09-28 02:36:28 +02:00
enum trigger_type {
PRE_STORE_TRIGGER = 1,
POST_STORE_TRIGGER = 2,
PRE_MODIFY_TRIGGER = 3,
POST_MODIFY_TRIGGER = 4,
PRE_ERASE_TRIGGER = 5,
POST_ERASE_TRIGGER = 6
};
2001-05-23 15:26:42 +02:00
2003-09-28 02:36:28 +02:00
const int DEFAULT_BUFFER = 2048;
2001-05-23 15:26:42 +02:00
2003-09-28 02:36:28 +02:00
const int DEFAULT_BLOB_SEGMENT_SIZE = 80; // bytes
2001-05-23 15:26:42 +02:00
2003-02-13 10:33:26 +01:00
static const USHORT blr_dtypes[] = {
2001-05-23 15:26:42 +02:00
0,
blr_text, // dtype_text
blr_cstring, // dtype_cstring
blr_varying, // dtype_varying
2001-05-23 15:26:42 +02:00
0,
0,
0, // dtype_packed
0, // dtype_byte
blr_short, // dtype_short
blr_long, // dtype_long
blr_quad, // dtype_quad
blr_float, // dtype_real
blr_double, // dtype_double
blr_double, // dtype_d_float
blr_sql_date, // dtype_sql_date
blr_sql_time, // dtype_sql_time
blr_timestamp, // dtype_timestamp
blr_blob, // dtype_blob
blr_short, // dtype_array
blr_int64 // dtype_int64
2001-05-23 15:26:42 +02:00
};
2003-02-13 10:33:26 +01:00
static const UCHAR nonnull_validation_blr[] = {
2001-05-23 15:26:42 +02:00
blr_version5,
blr_not,
blr_missing,
blr_fid, 0, 0, 0,
blr_eoc
};
2003-10-16 10:51:06 +02:00
static inline bool hasOldContext(const int value)
{
2003-10-16 10:51:06 +02:00
const int val1 = ((value + 1) >> 1) & 3;
const int val2 = ((value + 1) >> 3) & 3;
const int val3 = ((value + 1) >> 5) & 3;
return (val1 && val1 != 1) || (val2 && val2 != 1) || (val3 && val3 != 1);
}
2003-10-16 10:51:06 +02:00
static inline bool hasNewContext(const int value)
{
2003-10-16 10:51:06 +02:00
const int val1 = ((value + 1) >> 1) & 3;
const int val2 = ((value + 1) >> 3) & 3;
const int val3 = ((value + 1) >> 5) & 3;
return (val1 && val1 != 3) || (val2 && val2 != 3) || (val3 && val3 != 3);
}
void DDL_execute(dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* D D L _ e x e c u t e
*
**************************************
*
* Functional description
* Call access method layered service DYN
* to interpret dyn string and perform
2001-05-23 15:26:42 +02:00
* metadata updates.
*
**************************************/
tsql* tdsql = DSQL_get_thread_data();
2001-05-23 15:26:42 +02:00
#ifdef DSQL_DEBUG
if (DSQL_debug & 4) {
dsql_trace("Output DYN string for DDL:");
PRETTY_print_dyn(request->req_blr_data.begin(),
gds__trace_printer, NULL, 0);
}
2001-05-23 15:26:42 +02:00
#endif
const USHORT length = request->req_blr_data.getCount();
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
const ISC_STATUS s =
isc_ddl(tdsql->tsql_status, &request->req_dbb->dbb_database_handle,
&request->req_trans, length,
2004-05-09 07:48:33 +02:00
(const char*)(request->req_blr_data.begin()));
2001-05-23 15:26:42 +02:00
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// for delete & modify, get rid of the cached relation metadata
2001-05-23 15:26:42 +02:00
2003-11-10 10:16:38 +01:00
const dsql_str* string = NULL;
const dsql_nod* relation_node;
switch (request->req_ddl_node->nod_type)
{
case nod_mod_relation:
case nod_redef_relation:
relation_node = request->req_ddl_node->nod_arg[e_alt_name];
2003-11-10 10:16:38 +01:00
string = (dsql_str*) relation_node->nod_arg[e_rln_name];
break;
2003-03-03 20:10:23 +01:00
case nod_mod_view:
case nod_replace_view:
2003-03-03 20:10:23 +01:00
case nod_redef_view:
case nod_del_relation:
case nod_del_view:
2003-11-10 10:16:38 +01:00
string = (dsql_str*) request->req_ddl_node->nod_arg[e_alt_name];
break;
}
if (string) {
METD_drop_relation(request, string);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
// for delete & modify, get rid of the cached procedure metadata
2001-05-23 15:26:42 +02:00
2003-10-16 10:51:06 +02:00
const NOD_TYPE temp_type = request->req_ddl_node->nod_type;
if ((temp_type == nod_mod_procedure) ||
(temp_type == nod_del_procedure) ||
(temp_type == nod_replace_procedure) ||
(temp_type == nod_redef_procedure))
{
2003-11-10 10:16:38 +01:00
string = (dsql_str*) request->req_ddl_node->nod_arg[e_prc_name];
2001-05-23 15:26:42 +02:00
METD_drop_procedure(request, string);
}
// Signal UDF for obsolescence
2002-06-29 08:56:51 +02:00
2003-10-16 10:51:06 +02:00
if (temp_type == nod_del_udf) {
2003-11-10 10:16:38 +01:00
string = (dsql_str*) request->req_ddl_node->nod_arg[e_udf_name];
METD_drop_function (request, string);
}
2002-06-29 08:56:51 +02:00
2001-12-24 03:51:06 +01:00
if (s) {
Firebird::status_exception::raise(tdsql->tsql_status);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
void DDL_generate(dsql_req* request, dsql_nod* node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* D D L _ g e n e r a t e
*
**************************************
*
* Functional description
* Generate the DYN string for a
* metadata update. Done during the
* prepare phase.
*
**************************************/
if (request->req_dbb->dbb_flags & DBB_read_only) {
ERRD_post(isc_read_only_database, 0);
return;
}
2001-12-24 03:51:06 +01:00
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_version_1);
2001-05-23 15:26:42 +02:00
generate_dyn(request, node);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_eoc);
2001-05-23 15:26:42 +02:00
}
//
// Determine whether ids or names should be referenced
// when generating blr for fields and relations.
//
bool DDL_ids(const dsql_req* request)
2001-05-23 15:26:42 +02:00
{
const dsql_nod* ddl_node = request->req_ddl_node;
2001-12-24 03:51:06 +01:00
if (!ddl_node) {
return true;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
switch (ddl_node->nod_type)
{
case nod_def_view:
2003-03-15 09:14:54 +01:00
case nod_redef_view:
case nod_mod_view:
case nod_replace_view:
case nod_def_constraint:
case nod_def_trigger:
case nod_mod_trigger:
case nod_replace_trigger:
case nod_def_procedure:
case nod_def_computed:
case nod_mod_procedure:
case nod_replace_procedure:
case nod_redef_procedure:
return false;
default:
return true;
}
2001-05-23 15:26:42 +02:00
}
//
// Emit blr that describes a descriptor.
2003-10-01 20:11:23 +02:00
// Note that this depends on the same stuff variant
2003-10-05 08:33:56 +02:00
// as used in gen.cpp
//
void DDL_put_field_dtype(dsql_req* request, const dsql_fld* field, bool use_subtype)
2001-05-23 15:26:42 +02:00
{
put_dtype(request, field, use_subtype);
}
//
// See the next function for description. This is only a
2003-10-05 08:33:56 +02:00
// wrapper that sets the last parameter to false to indicate
// we are creating a field, not modifying one.
//
2003-11-10 10:16:38 +01:00
void DDL_resolve_intl_type(dsql_req* request, dsql_fld* field, const dsql_str* collation_name)
2001-05-23 15:26:42 +02:00
{
DDL_resolve_intl_type2 (request, field, collation_name, false);
2002-06-29 08:56:51 +02:00
}
void DDL_resolve_intl_type2(dsql_req* request,
dsql_fld* field,
2003-11-10 10:16:38 +01:00
const dsql_str* collation_name,
bool modifying)
2002-06-29 08:56:51 +02:00
{
/**************************************
*
* D D L _ r e s o l v e _ i n t l _ t y p e 2
*
**************************************
*
* Function
2001-05-23 15:26:42 +02:00
* If the field is defined with a character set or collation,
* resolve the names to a subtype now.
*
* Also resolve the field length & whatnot.
*
2002-06-29 08:56:51 +02:00
* If the field is being created, it will pick the db-wide charset
* and collation if not specified. If the field is being modified,
* since we don't allow changes to those attributes, we'll go and
* calculate the correct old lenth from the field itself so DYN
* can validate the change properly.
*
2001-05-23 15:26:42 +02:00
* For International text fields, this is a good time to calculate
* their actual size - when declared they were declared in
* lengths of CHARACTERs, not BYTES.
*
**************************************/
2001-12-24 03:51:06 +01:00
if ((field->fld_dtype > dtype_any_text) && field->fld_dtype != dtype_blob)
{
2001-05-23 15:26:42 +02:00
if (field->fld_character_set || collation_name ||
field->fld_flags & FLD_national)
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -204,
isc_arg_gds, isc_dsql_datatype_err,
isc_arg_gds, isc_collation_requires_text, 0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
return;
}
if (field->fld_dtype == dtype_blob)
{
if (field->fld_sub_type_name)
{
2001-12-24 03:51:06 +01:00
SSHORT blob_sub_type;
2001-05-23 15:26:42 +02:00
if (!METD_get_type(request,
2003-11-10 10:16:38 +01:00
reinterpret_cast<const dsql_str*>(field->fld_sub_type_name),
"RDB$FIELD_SUB_TYPE",
2001-05-23 15:26:42 +02:00
&blob_sub_type))
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -204, isc_arg_gds,
isc_dsql_datatype_err, isc_arg_gds,
isc_dsql_blob_type_unknown, isc_arg_string,
((dsql_str*) field->fld_sub_type_name)->str_data, 0);
2001-05-23 15:26:42 +02:00
}
field->fld_sub_type = blob_sub_type;
}
if (field->fld_character_set && (field->fld_sub_type == isc_blob_untyped))
2001-05-23 15:26:42 +02:00
{
field->fld_sub_type = isc_blob_text;
2001-05-23 15:26:42 +02:00
}
if (field->fld_character_set && (field->fld_sub_type != isc_blob_text))
2001-05-23 15:26:42 +02:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -204, isc_arg_gds,
isc_dsql_datatype_err, isc_arg_gds,
isc_collation_requires_text, 0);
2001-05-23 15:26:42 +02:00
}
if (collation_name)
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -204, isc_arg_gds,
isc_dsql_datatype_err, isc_arg_gds,
isc_collation_requires_text, 0);
2001-05-23 15:26:42 +02:00
}
if (field->fld_sub_type != isc_blob_text) {
2001-05-23 15:26:42 +02:00
return;
}
}
if (field->fld_character_set_id != 0 && !collation_name) {
2001-12-24 03:51:06 +01:00
// This field has already been resolved once, and the collation
// hasn't changed. Therefore, no need to do it again.
2001-05-23 15:26:42 +02:00
return;
}
2002-06-29 08:56:51 +02:00
if (modifying)
{
const dsql_rel* relation = request->req_relation;
const dsql_fld* afield = field->fld_next;
USHORT bpc = 0;
2002-06-29 08:56:51 +02:00
while (afield) {
// The first test is redundant.
2002-06-29 08:56:51 +02:00
if (afield != field && afield->fld_relation
2003-10-16 10:51:06 +02:00
&& !strcmp (afield->fld_name, field->fld_name))
{
2003-11-04 00:59:24 +01:00
fb_assert(afield->fld_relation == relation || !relation);
2002-06-29 08:56:51 +02:00
break;
}
afield = afield->fld_next;
}
if (afield) {
field->fld_character_set_id = afield->fld_character_set_id;
bpc = METD_get_charset_bpc (request, field->fld_character_set_id);
field->fld_collation_id = afield->fld_collation_id;
field->fld_ttype = afield->fld_ttype;
if (afield->fld_flags & FLD_national) {
field->fld_flags |= FLD_national;
}
else {
field->fld_flags &= ~FLD_national;
}
assign_field_length (field, bpc);
return;
}
}
if (!(field->fld_character_set || field->fld_character_set_id || // set if a domain
2001-12-24 03:51:06 +01:00
(field->fld_flags & FLD_national)))
{
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// Attach the database default character set, if not otherwise specified
2001-05-23 15:26:42 +02:00
2003-11-10 10:16:38 +01:00
const dsql_str* dfl_charset = METD_get_default_charset(request);
2001-12-24 03:51:06 +01:00
if (dfl_charset)
{
field->fld_character_set = (dsql_nod*) dfl_charset;
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
else
{
2001-05-23 15:26:42 +02:00
/* If field is not specified with NATIONAL, or CHARACTER SET
* treat it as a single-byte-per-character field of character set NONE.
*/
2002-06-29 08:56:51 +02:00
assign_field_length (field, 1);
field->fld_ttype = 0;
2001-12-24 03:51:06 +01:00
if (!collation_name) {
2001-05-23 15:26:42 +02:00
return;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
}
const char* charset_name = 0;
2001-12-24 03:51:06 +01:00
if (field->fld_flags & FLD_national) {
charset_name = NATIONAL_CHARACTER_SET;
}
else if (field->fld_character_set) {
2003-11-10 10:16:38 +01:00
charset_name = ((dsql_str*) field->fld_character_set)->str_data;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// Find an intlsym for any specified character set name & collation name
const dsql_intlsym* resolved_type;
2003-10-16 10:51:06 +02:00
2001-12-24 03:51:06 +01:00
if (charset_name)
{
const dsql_intlsym* resolved_charset =
2001-05-23 15:26:42 +02:00
METD_get_charset(request,
(USHORT) strlen(charset_name),
charset_name);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// Error code -204 (IBM's DB2 manual) is close enough
2001-05-23 15:26:42 +02:00
if (!resolved_charset)
2001-12-24 03:51:06 +01:00
{
// specified character set not found
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -204,
isc_arg_gds, isc_dsql_datatype_err,
isc_arg_gds, isc_charset_not_found, isc_arg_string,
2001-05-23 15:26:42 +02:00
charset_name, 0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
field->fld_character_set_id = resolved_charset->intlsym_charset_id;
resolved_type = resolved_charset;
}
2001-12-24 03:51:06 +01:00
if (collation_name)
{
const dsql_intlsym* resolved_collation =
2001-12-24 03:51:06 +01:00
METD_get_collation(request, collation_name);
2001-05-23 15:26:42 +02:00
if (!resolved_collation)
2001-12-24 03:51:06 +01:00
{
// Specified collation not found
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -204,
isc_arg_gds, isc_dsql_datatype_err,
isc_arg_gds, isc_collation_not_found, isc_arg_string,
2001-05-23 15:26:42 +02:00
collation_name->str_data, 0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// If both specified, must be for same character set
// A "literal constant" must be handled (charset as ttype_dynamic)
2001-05-23 15:26:42 +02:00
resolved_type = resolved_collation;
if ((field->fld_character_set_id != resolved_type->intlsym_charset_id)
&& (field->fld_character_set_id != ttype_dynamic))
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -204, isc_arg_gds,
isc_dsql_datatype_err, isc_arg_gds,
isc_collation_not_for_charset, isc_arg_string,
2001-05-23 15:26:42 +02:00
collation_name->str_data, 0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
2002-06-29 08:56:51 +02:00
assign_field_length (field, resolved_type->intlsym_bytes_per_char);
field->fld_ttype = resolved_type->intlsym_ttype;
field->fld_character_set_id = resolved_type->intlsym_charset_id;
field->fld_collation_id = resolved_type->intlsym_collate_id;
}
static void assign_field_length (
dsql_fld* field,
2002-06-29 08:56:51 +02:00
USHORT bytes_per_char)
{
/**************************************
*
* a s s i g n _ f i e l d _ l e n g t h
*
**************************************
*
* Function
* We'll see if the field's length fits in the maximum
* allowed field, including charset and space for varchars.
* Either we raise an error or assign the field's length.
* If the charlen comes as zero, we do nothing, although we
* know that DYN, MET and DFW will blindly set field length
* to zero if they don't catch charlen or another condition.
*
**************************************/
2001-12-24 03:51:06 +01:00
if (field->fld_character_length)
{
2003-10-16 10:51:06 +02:00
ULONG field_length = (ULONG) bytes_per_char *
field->fld_character_length;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (field->fld_dtype == dtype_varying) {
2001-05-23 15:26:42 +02:00
field_length += sizeof(USHORT);
2001-12-24 03:51:06 +01:00
}
2004-04-29 16:51:02 +02:00
if (field_length > MAX_COLUMN_SIZE)
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -204,
isc_arg_gds, isc_dsql_datatype_err,
isc_arg_gds, isc_imp_exc,
isc_arg_gds, isc_field_name, isc_arg_string,
2001-05-23 15:26:42 +02:00
field->fld_name, 0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
field->fld_length = (USHORT) field_length;
2002-06-29 08:56:51 +02:00
}
2001-05-23 15:26:42 +02:00
}
static bool is_array_or_blob(const dsql_nod* node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* i s _ a r r a y _ o r _ b l o b
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
2003-10-16 10:51:06 +02:00
* return true if there is an array or blob in expression, else false.
2001-05-23 15:26:42 +02:00
* Array and blob expressions have limited usefullness in a computed
* expression - so we detect it here to report a syntax error at
2001-05-23 15:26:42 +02:00
* definition time, rather than a runtime error at execution.
*
**************************************/
2001-12-24 03:51:06 +01:00
BLKCHK(node, dsql_type_nod);
2001-05-23 15:26:42 +02:00
switch (node->nod_type) {
case nod_agg_count:
case nod_count:
case nod_gen_id:
case nod_gen_id2:
case nod_dbkey:
case nod_current_date:
case nod_current_time:
case nod_current_timestamp:
case nod_constant:
case nod_null:
2001-05-23 15:26:42 +02:00
case nod_via:
case nod_internal_info:
return false;
2001-05-23 15:26:42 +02:00
case nod_map:
2001-12-24 03:51:06 +01:00
{
2003-11-10 10:16:38 +01:00
const dsql_map* map = (dsql_map*) node->nod_arg[e_map_map];
return is_array_or_blob(map->map_node);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
case nod_agg_max:
case nod_agg_min:
case nod_agg_average:
case nod_agg_total:
case nod_agg_average2:
case nod_agg_total2:
case nod_upcase:
case nod_negate:
return is_array_or_blob(node->nod_arg[0]);
2001-05-23 15:26:42 +02:00
case nod_cast:
2001-12-24 03:51:06 +01:00
{
const dsql_fld* fld = (dsql_fld*) node->nod_arg[e_cast_target];
2001-12-24 03:51:06 +01:00
if ((fld->fld_dtype == dtype_blob) || (fld->fld_dtype == dtype_array)) {
return true;
2001-12-24 03:51:06 +01:00
}
return is_array_or_blob(node->nod_arg[e_cast_source]);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
case nod_add:
case nod_subtract:
case nod_concatenate:
case nod_multiply:
case nod_divide:
case nod_add2:
case nod_subtract2:
case nod_multiply2:
case nod_divide2:
if (is_array_or_blob(node->nod_arg[0])) {
return true;
2001-12-24 03:51:06 +01:00
}
return is_array_or_blob(node->nod_arg[1]);
2001-05-23 15:26:42 +02:00
case nod_alias:
return is_array_or_blob(node->nod_arg[e_alias_value]);
2001-05-23 15:26:42 +02:00
case nod_udf:
2001-12-24 03:51:06 +01:00
{
2003-11-10 10:16:38 +01:00
const dsql_udf* userFunc = (dsql_udf*) node->nod_arg[0];
if ((userFunc->udf_dtype == dtype_blob) || (userFunc->udf_dtype == dtype_array))
{
return true;
2001-12-24 03:51:06 +01:00
}
// parameters to UDF don't need checking, a blob or array can be passed
return false;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
case nod_extract:
case nod_list:
2001-12-24 03:51:06 +01:00
{
const dsql_nod* const* const end = node->nod_arg + node->nod_count;
for (const dsql_nod* const* ptr = node->nod_arg; ptr < end; ++ptr)
2001-12-24 03:51:06 +01:00
{
if (is_array_or_blob(*ptr)) {
return true;
2001-12-24 03:51:06 +01:00
}
}
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
return false;
2001-05-23 15:26:42 +02:00
case nod_field:
if ((node->nod_desc.dsc_dtype == dtype_blob) ||
(node->nod_desc.dsc_dtype == dtype_array))
2001-12-24 03:51:06 +01:00
{
return true;
2001-12-24 03:51:06 +01:00
}
return false;
2001-05-23 15:26:42 +02:00
default:
2003-11-04 00:59:24 +01:00
fb_assert(false);
return false;
2001-05-23 15:26:42 +02:00
}
}
static void check_constraint( dsql_req* request,
dsql_nod* element,
bool delete_trigger_required)
2001-05-23 15:26:42 +02:00
{
2004-02-02 12:02:12 +01:00
/**************************************
2001-05-23 15:26:42 +02:00
*
* c h e c k _ c o n s t r a i n t
*
**************************************
*
* Function
* Generate triggers to implement the CHECK
* clause, either at the field or table level.
*
**************************************/
dsql_nod* ddl_node = request->req_ddl_node;
2001-12-24 03:51:06 +01:00
if (!(element->nod_arg[e_cnstr_table])) {
2001-05-23 15:26:42 +02:00
element->nod_arg[e_cnstr_table] = ddl_node->nod_arg[e_drl_name];
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// specify that the trigger should abort if the condition is not met
2001-05-23 15:26:42 +02:00
dsql_nod* list_node = MAKE_node(nod_list, (int) 1);
2001-12-24 03:51:06 +01:00
element->nod_arg[e_cnstr_actions] = list_node;
2001-05-23 15:26:42 +02:00
list_node->nod_arg[0] = MAKE_node(nod_gdscode, (int) 1);
2001-12-24 03:51:06 +01:00
dsql_nod** errorcode_node = &list_node->nod_arg[0]->nod_arg[0];
*errorcode_node = (dsql_nod*) MAKE_cstring("check_constraint");
2001-05-23 15:26:42 +02:00
element->nod_arg[e_cnstr_message] = NULL;
2001-12-24 03:51:06 +01:00
// create the INSERT trigger
// element->nod_arg[e_cnstr_message] =
// (dsql_nod*) MAKE_cstring ("insert violates CHECK constraint on table");
2001-05-23 15:26:42 +02:00
element->nod_arg[e_cnstr_type] =
2003-11-10 10:16:38 +01:00
MAKE_constant((dsql_str*) PRE_STORE_TRIGGER, CONSTANT_SLONG);
2001-05-23 15:26:42 +02:00
define_constraint_trigger(request, element);
2001-12-24 03:51:06 +01:00
// create the UPDATE trigger
// element->nod_arg[e_cnstr_message] =
// (dsql_nod*) MAKE_cstring ("update violates CHECK constraint on table");
2001-05-23 15:26:42 +02:00
element->nod_arg[e_cnstr_type] =
2003-11-10 10:16:38 +01:00
MAKE_constant((dsql_str*) PRE_MODIFY_TRIGGER, CONSTANT_SLONG);
2001-05-23 15:26:42 +02:00
define_constraint_trigger(request, element);
2001-12-24 03:51:06 +01:00
// create the DELETE trigger, if required
if (delete_trigger_required)
{
//
// element->nod_arg[e_cnstr_message] =
// (dsql_nod*) MAKE_cstring ("delete violates CHECK constraint on table");
2001-12-24 03:51:06 +01:00
//
2001-05-23 15:26:42 +02:00
element->nod_arg[e_cnstr_type] =
2003-11-10 10:16:38 +01:00
MAKE_constant((dsql_str*) PRE_ERASE_TRIGGER, CONSTANT_SLONG);
2001-05-23 15:26:42 +02:00
define_constraint_trigger(request, element);
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end); // For CHECK constraint definition
2001-05-23 15:26:42 +02:00
}
2003-09-13 12:26:47 +02:00
static void check_one_call (USHORT* repetition_count,
2003-09-12 03:41:03 +02:00
SSHORT pos,
2003-09-13 12:26:47 +02:00
const TEXT* error_msg)
2002-06-29 08:56:51 +02:00
{
/**************************************
*
* c h e c k _ o n e _ c a l l
*
**************************************
*
* Function
* Ensure that each option in modify_domain() is called only once.
* This restriction cannot be enforced by the DSQL parser.
*
**************************************/
2003-09-13 12:26:47 +02:00
if (++repetition_count[pos] > 1) {
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -637,
isc_arg_gds, isc_dsql_duplicate_spec,
isc_arg_string, error_msg,
2003-09-13 12:26:47 +02:00
0);
2003-09-12 03:41:03 +02:00
}
2002-06-29 08:56:51 +02:00
}
static void create_view_triggers(dsql_req* request, dsql_nod* element,
dsql_nod* items)
{ // Fields in the VIEW actually
2004-02-02 12:02:12 +01:00
/**************************************
2001-05-23 15:26:42 +02:00
*
* c r e a t e _ v i e w _ t r i g g e r s
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Function
* Generate triggers to implement the WITH CHECK OPTION
* clause for a VIEW
2002-06-29 08:56:51 +02:00
*
2001-05-23 15:26:42 +02:00
**************************************/
dsql_nod* ddl_node = request->req_ddl_node;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (!(element->nod_arg[e_cnstr_table])) {
2001-05-23 15:26:42 +02:00
element->nod_arg[e_cnstr_table] = ddl_node->nod_arg[e_drl_name];
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// specify that the trigger should abort if the condition is not met
2001-05-23 15:26:42 +02:00
dsql_nod* list_node = MAKE_node(nod_list, (int) 1);
2001-12-24 03:51:06 +01:00
element->nod_arg[e_cnstr_actions] = list_node;
2001-05-23 15:26:42 +02:00
list_node->nod_arg[0] = MAKE_node(nod_gdscode, (int) 1);
2001-12-24 03:51:06 +01:00
dsql_nod** errorcode_node = &list_node->nod_arg[0]->nod_arg[0];
*errorcode_node = (dsql_nod*) MAKE_cstring("check_constraint");
2001-05-23 15:26:42 +02:00
element->nod_arg[e_cnstr_message] = NULL;
2001-12-24 03:51:06 +01:00
// create the UPDATE trigger
// element->nod_arg[e_cnstr_message] =
// (dsql_nod*) MAKE_cstring ("update violates CHECK constraint on view");
2001-05-23 15:26:42 +02:00
element->nod_arg[e_cnstr_type] =
2003-11-10 10:16:38 +01:00
MAKE_constant((dsql_str*) PRE_MODIFY_TRIGGER, CONSTANT_SLONG);
2003-10-16 10:51:06 +02:00
dsql_nod* base_and_node = 0;
dsql_nod* base_relation = 0;
2001-05-23 15:26:42 +02:00
define_update_action(request, &base_and_node, &base_relation);
dsql_nod* rse = MAKE_node(nod_rse, e_rse_count);
2001-05-23 15:26:42 +02:00
rse->nod_arg[e_rse_boolean] = base_and_node;
dsql_nod* temp = MAKE_node(nod_list, 1);
2003-10-16 10:51:06 +02:00
rse->nod_arg[e_rse_streams] = temp;
2001-05-23 15:26:42 +02:00
temp->nod_arg[0] = base_relation;
define_view_trigger(request, element, rse, items);
2001-12-24 03:51:06 +01:00
// create the INSERT trigger
// element->nod_arg[e_cnstr_message] =
// (dsql_nod*) MAKE_cstring ("insert violates CHECK constraint on view");
2001-05-23 15:26:42 +02:00
element->nod_arg[e_cnstr_type] =
2003-11-10 10:16:38 +01:00
MAKE_constant((dsql_str*) PRE_STORE_TRIGGER, CONSTANT_SLONG);
2001-05-23 15:26:42 +02:00
define_view_trigger(request, element, NULL, items);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end); // For triggers definition
2001-05-23 15:26:42 +02:00
}
static void define_computed(dsql_req* request,
dsql_nod* relation_node,
dsql_fld* field,
dsql_nod* node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e f i n e _ c o m p u t e d
*
**************************************
*
* Function
* Create the ddl to define a computed field
* or an expression index.
2001-05-23 15:26:42 +02:00
*
**************************************/
dsql_nod* ddl_node = request->req_ddl_node;
2001-05-23 15:26:42 +02:00
request->req_ddl_node = node;
2001-12-24 03:51:06 +01:00
// Get the table node & set up correct context
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (request->req_context_number) {
2001-05-23 15:26:42 +02:00
reset_context_stack(request);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2003-10-16 10:51:06 +02:00
dsc save_desc;
2001-12-24 03:51:06 +01:00
// Save the size of the field if it is specified
2001-05-23 15:26:42 +02:00
save_desc.dsc_dtype = 0;
2001-12-24 03:51:06 +01:00
if (field && field->fld_dtype)
{
2003-11-04 00:59:24 +01:00
fb_assert(field->fld_dtype <= MAX_UCHAR);
2001-05-23 15:26:42 +02:00
save_desc.dsc_dtype = (UCHAR) field->fld_dtype;
save_desc.dsc_length = field->fld_length;
2003-11-04 00:59:24 +01:00
fb_assert(field->fld_scale <= MAX_SCHAR);
2001-05-23 15:26:42 +02:00
save_desc.dsc_scale = (SCHAR) field->fld_scale;
field->fld_dtype = 0;
field->fld_length = 0;
field->fld_scale = 0;
}
PASS1_make_context(request, relation_node);
dsql_nod* input = PASS1_node(request, node->nod_arg[e_cmp_expr], false);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// check if array or blobs are used in expression
2001-05-23 15:26:42 +02:00
if (is_array_or_blob(input))
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_no_blob_array, 0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// generate the blr expression
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_fld_computed_blr);
2001-12-24 03:51:06 +01:00
request->begin_blr(0);
GEN_expr(request, input);
request->end_blr();
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// try to calculate size of the computed field. The calculated size
// may be ignored, but it will catch self references
2003-10-16 10:51:06 +02:00
dsc desc;
MAKE_desc(&desc, input, NULL);
2001-05-23 15:26:42 +02:00
if (save_desc.dsc_dtype) {
2001-12-24 03:51:06 +01:00
// restore the field size/type overrides
field->fld_dtype = save_desc.dsc_dtype;
2001-05-23 15:26:42 +02:00
field->fld_length = save_desc.dsc_length;
2001-12-24 03:51:06 +01:00
field->fld_scale = save_desc.dsc_scale;
2001-05-23 15:26:42 +02:00
}
else if (field) {
2001-12-24 03:51:06 +01:00
// use size calculated
field->fld_dtype = desc.dsc_dtype;
2001-05-23 15:26:42 +02:00
field->fld_length = desc.dsc_length;
2001-12-24 03:51:06 +01:00
field->fld_scale = desc.dsc_scale;
2001-05-23 15:26:42 +02:00
}
request->req_type = REQ_DDL;
request->req_ddl_node = ddl_node;
reset_context_stack(request);
2001-12-24 03:51:06 +01:00
// generate the source text
2003-11-10 10:16:38 +01:00
const dsql_str* source = (dsql_str*) node->nod_arg[e_cmp_text];
2003-11-04 00:59:24 +01:00
fb_assert(source->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_fld_computed_source,
source->str_data,
2001-12-24 03:51:06 +01:00
(USHORT) source->str_length);
2001-05-23 15:26:42 +02:00
}
static void define_constraint_trigger(dsql_req* request, dsql_nod* node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e f i n e _ c o n s t r a i n t _ t r i g g e r
*
**************************************
*
* Function
* Create the ddl to define or alter a constraint trigger.
2002-06-29 08:56:51 +02:00
* This is a SQL's check constraint.
2001-05-23 15:26:42 +02:00
*
**************************************/
/* make the "define trigger" node the current request ddl node so
that generating of BLR will be appropriate for trigger */
dsql_nod* ddl_node = request->req_ddl_node;
2001-05-23 15:26:42 +02:00
request->req_ddl_node = node;
if (node->nod_type != nod_def_constraint)
{
return;
}
2003-11-10 10:16:38 +01:00
const dsql_str* trigger_name = (dsql_str*) node->nod_arg[e_cnstr_name];
2001-05-23 15:26:42 +02:00
2003-11-04 00:59:24 +01:00
fb_assert(trigger_name->str_length <= MAX_USHORT);
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_def_trigger,
trigger_name->str_data,
2001-12-24 03:51:06 +01:00
(USHORT) trigger_name->str_length);
2001-05-23 15:26:42 +02:00
dsql_nod* relation_node = node->nod_arg[e_cnstr_table];
2003-11-10 10:16:38 +01:00
const dsql_str* relation_name = (dsql_str*) relation_node->nod_arg[e_rln_name];
2001-05-23 15:26:42 +02:00
2003-11-04 00:59:24 +01:00
fb_assert(trigger_name->str_length <= MAX_USHORT);
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_rel_name,
relation_name->str_data,
2001-12-24 03:51:06 +01:00
(USHORT) relation_name->str_length);
2001-05-23 15:26:42 +02:00
2003-11-10 10:16:38 +01:00
const dsql_str* source = (dsql_str*) node->nod_arg[e_cnstr_source];
2001-05-23 15:26:42 +02:00
if (source)
{
2003-11-04 00:59:24 +01:00
fb_assert(source->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_trg_source,
source->str_data,
2001-12-24 03:51:06 +01:00
(USHORT) source->str_length);
2001-05-23 15:26:42 +02:00
}
const dsql_nod* constant = node->nod_arg[e_cnstr_position];
2001-12-24 03:51:06 +01:00
if (constant)
2001-05-23 15:26:42 +02:00
{
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_trg_sequence,
(SSHORT) (constant ? (IPTR) constant->nod_arg[0] : 0));
2001-05-23 15:26:42 +02:00
}
constant = node->nod_arg[e_cnstr_type];
if (constant != NULL)
2001-05-23 15:26:42 +02:00
{
const SSHORT type = (SSHORT)(IPTR) constant->nod_arg[0];
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_trg_type, type);
2001-05-23 15:26:42 +02:00
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_sql_object);
2001-05-23 15:26:42 +02:00
2003-11-10 10:16:38 +01:00
const dsql_str* message = (dsql_str*) node->nod_arg[e_cnstr_message];
2001-05-23 15:26:42 +02:00
if (message)
{
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_def_trigger_msg, 0);
2003-11-04 00:59:24 +01:00
fb_assert(message->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_trg_msg,
message->str_data,
2001-12-24 03:51:06 +01:00
(USHORT) message->str_length);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
// generate the trigger blr
2001-05-23 15:26:42 +02:00
if (node->nod_arg[e_cnstr_condition] && node->nod_arg[e_cnstr_actions])
{
2003-11-08 00:27:24 +01:00
request->begin_blr(isc_dyn_trg_blr);
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_begin);
2001-05-23 15:26:42 +02:00
/* create the "OLD" and "NEW" contexts for the trigger --
the new one could be a dummy place holder to avoid resolving
fields to that context but prevent relations referenced in
the trigger actions from referencing the predefined "1" context */
if (request->req_context_number)
{
reset_context_stack(request);
}
2002-06-29 08:56:51 +02:00
// CVC: check_constraint() is the only caller and it always receives
2003-10-16 10:51:06 +02:00
// false for the delete_trigger_required flag. Hence, I thought I could
2002-06-29 08:56:51 +02:00
// disable the OLD context here to avoid "ambiguous field name" errors
// in pre_store and pre_modify triggers. Also, what sense can I make
// from NEW in pre_delete? However, we clash at JRD with "no current
// record for fetch operation".
relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(OLD_CONTEXT);
2001-05-23 15:26:42 +02:00
PASS1_make_context(request, relation_node);
relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(NEW_CONTEXT);
2001-05-23 15:26:42 +02:00
PASS1_make_context(request, relation_node);
2001-12-24 03:51:06 +01:00
// generate the condition for firing the trigger
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_if);
2001-05-23 15:26:42 +02:00
GEN_expr(request,
2003-09-02 01:22:22 +02:00
PASS1_node(request, node->nod_arg[e_cnstr_condition], false));
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_begin);
request->append_uchar(blr_end); // of begin
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// generate the action statements for the trigger
dsql_nod* actions = node->nod_arg[e_cnstr_actions];
dsql_nod** ptr = actions->nod_arg;
for (const dsql_nod* const* const end = ptr + actions->nod_count;
2001-05-23 15:26:42 +02:00
ptr < end; ptr++)
{
GEN_statement(request, PASS1_statement(request, *ptr, false));
2001-05-23 15:26:42 +02:00
}
// generate the action statements for the trigger
2001-05-23 15:26:42 +02:00
if ((actions = node->nod_arg[e_cnstr_else]) != NULL)
{
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_begin);
ptr = actions->nod_arg;
for (const dsql_nod* const* const end = ptr + actions->nod_count;
2001-05-23 15:26:42 +02:00
ptr < end; ptr++)
{
GEN_statement(request, PASS1_statement(request, *ptr, false));
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_end); // of begin
2001-05-23 15:26:42 +02:00
}
else
{
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_end); // of if
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
request->end_blr();
2001-05-23 15:26:42 +02:00
}
2002-06-29 08:56:51 +02:00
request->append_number(isc_dyn_system_flag, frb_sysflag_check_constraint);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
/* the request type may have been set incorrectly when parsing
the trigger actions, so reset it to reflect the fact that this
is a data definition request; also reset the ddl node */
request->req_type = REQ_DDL;
request->req_ddl_node = ddl_node;
reset_context_stack(request);
}
static void define_database( dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e f i n e _ d a t a b a s e
*
**************************************
*
* Function
* Create a database. Assumes that
* database is created elsewhere with
* initial options. Modify the
2001-05-23 15:26:42 +02:00
* database using DYN to add the remaining
* options.
*
**************************************/
SLONG start = 0;
const dsql_nod* ddl_node = request->req_ddl_node;
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_mod_database);
2001-05-23 15:26:42 +02:00
/*
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_rel_sql_protection, 1);
2001-05-23 15:26:42 +02:00
*/
const dsql_nod* elements = ddl_node->nod_arg[e_database_initial_desc];
2001-05-23 15:26:42 +02:00
if (elements) {
const dsql_nod* const* ptr = elements->nod_arg;
for (const dsql_nod* const* const end = ptr + elements->nod_count;
2003-10-16 10:51:06 +02:00
ptr < end; ptr++)
{
const dsql_nod* element = *ptr;
2001-05-23 15:26:42 +02:00
switch (element->nod_type) {
case nod_file_length:
start = (IPTR) (element->nod_arg[0]) + 1;
2001-05-23 15:26:42 +02:00
break;
default:
break;
}
}
}
2003-10-16 10:51:06 +02:00
2003-11-10 10:16:38 +01:00
const dsql_str* name;
const dsql_fil* file;
//SLONG temp_long;
//SSHORT temp_short;
//SSHORT number = 0;
2001-05-23 15:26:42 +02:00
elements = ddl_node->nod_arg[e_database_rem_desc];
if (elements)
2001-12-24 03:51:06 +01:00
{
const dsql_nod* const* ptr = elements->nod_arg;
for (const dsql_nod* const* const end = ptr + elements->nod_count;
2001-12-24 03:51:06 +01:00
ptr < end; ptr++)
{
2003-10-16 10:51:06 +02:00
const dsql_nod* element = *ptr;
2001-05-23 15:26:42 +02:00
switch (element->nod_type) {
case nod_difference_file:
request->append_cstring(isc_dyn_def_difference,
2003-11-10 10:16:38 +01:00
((dsql_str*)element->nod_arg[0])->str_data);
break;
2001-05-23 15:26:42 +02:00
case nod_file_desc:
2003-11-10 10:16:38 +01:00
file = (dsql_fil*) element->nod_arg[0];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_file,
file->fil_name->str_data);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
start = MAX(start, file->fil_start);
request->append_file_start(start);
request->append_file_length(file->fil_length);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
start += file->fil_length;
break;
/*
2001-05-23 15:26:42 +02:00
case nod_log_file_desc:
2003-11-10 10:16:38 +01:00
file = (dsql_fil*) element->nod_arg[0];
2001-05-23 15:26:42 +02:00
if (file->fil_flags & LOG_default) {
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_def_default_log);
2001-05-23 15:26:42 +02:00
break;
}
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_log_file,
file->fil_name->str_data);
2001-12-24 03:51:06 +01:00
request->append_file_length(file->fil_length);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_file_sequence);
2001-12-24 03:51:06 +01:00
request->append_ushort_with_length(number);
++number;
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_file_partitions);
2001-12-24 03:51:06 +01:00
request->append_ushort_with_length(file->fil_partitions);
if (file->fil_flags & LOG_serial) {
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_file_serial);
2001-12-24 03:51:06 +01:00
}
if (file->fil_flags & LOG_overflow) {
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_file_overflow);
2001-12-24 03:51:06 +01:00
}
if (file->fil_flags & LOG_raw) {
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_file_raw);
2001-12-24 03:51:06 +01:00
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_cache_file_desc:
2003-11-10 10:16:38 +01:00
file = (dsql_fil*) element->nod_arg[0];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_cache_file,
file->fil_name->str_data);
2001-12-24 03:51:06 +01:00
request->append_file_length(file->fil_length);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_group_commit_wait:
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_group_commit_wait);
temp_long = (IPTR) (element->nod_arg[0]);
2001-12-24 03:51:06 +01:00
request->append_ulong_with_length(temp_long);
2001-05-23 15:26:42 +02:00
break;
case nod_check_point_len:
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_check_point_length);
temp_long = (IPTR) (element->nod_arg[0]);
2001-12-24 03:51:06 +01:00
request->append_ulong_with_length(temp_long);
2001-05-23 15:26:42 +02:00
break;
case nod_num_log_buffers:
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_num_of_buffers);
temp_short = (SSHORT)(IPTR) (element->nod_arg[0]);
2001-12-24 03:51:06 +01:00
request->append_ushort_with_length(temp_short);
2001-05-23 15:26:42 +02:00
break;
case nod_log_buffer_size:
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_buffer_size);
temp_short = (SSHORT)(IPTR) (element->nod_arg[0]);
2001-12-24 03:51:06 +01:00
request->append_ushort_with_length(temp_short);
2001-05-23 15:26:42 +02:00
break;
*/
2001-05-23 15:26:42 +02:00
case nod_dfl_charset:
2003-11-10 10:16:38 +01:00
name = (dsql_str*) element->nod_arg[0];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_fld_character_set_name,
name->str_data);
2001-05-23 15:26:42 +02:00
break;
default:
break;
}
}
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void define_del_cascade_trg( dsql_req* request,
const dsql_nod* element,
const dsql_nod* for_columns,
const dsql_nod* prim_columns,
const char* prim_rel_name,
const char* for_rel_name)
2001-05-23 15:26:42 +02:00
{
/*****************************************************
*
* d e f i n e _ d e l _ c a s c a d e _ t r g
*
*****************************************************
*
* Function
* define "on delete cascade" trigger (for referential integrity)
* along with its blr
*
*****************************************************/
2001-12-24 03:51:06 +01:00
if (element->nod_type != nod_foreign) {
2001-05-23 15:26:42 +02:00
return;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// stuff a trigger_name of size 0. So the dyn-parser will make one up.
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_def_trigger, "", 0);
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_trg_type, (SSHORT) POST_ERASE_TRIGGER);
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_sql_object);
request->append_number(isc_dyn_trg_sequence, (SSHORT) 1);
request->append_number(isc_dyn_trg_inactive, (SSHORT) 0);
request->append_cstring(isc_dyn_rel_name, prim_rel_name);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// the trigger blr
2003-11-08 00:27:24 +01:00
request->begin_blr(isc_dyn_trg_blr);
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_for);
request->append_uchar(blr_rse);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// the context for the prim. key relation
request->append_uchar(1);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_relation);
request->append_cstring(0, for_rel_name);
// the context for the foreign key relation
request->append_uchar(2);
2001-05-23 15:26:42 +02:00
stuff_matching_blr(request, for_columns, prim_columns);
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_erase);
request->append_uchar(2);
request->end_blr();
// end of the blr
2001-05-23 15:26:42 +02:00
request->append_number(isc_dyn_system_flag,
frb_sysflag_referential_constraint);
2001-12-24 03:51:06 +01:00
// no trg_source and no trg_description
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void define_set_default_trg( dsql_req* request,
const dsql_nod* element,
const dsql_nod* for_columns,
const dsql_nod* prim_columns,
const char* prim_rel_name,
const char* for_rel_name,
bool on_upd_trg)
2001-05-23 15:26:42 +02:00
{
/*****************************************************
*
* d e f i n e _ s e t _ d e f a u l t _ t r g
*
*****************************************************
*
* Function
* define "on delete|update set default" trigger (for
2001-05-23 15:26:42 +02:00
* referential integrity) along with its blr
*
*****************************************************/
char default_val[BLOB_BUFFER_SIZE];
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (element->nod_type != nod_foreign) {
2001-05-23 15:26:42 +02:00
return;
}
2001-12-24 03:51:06 +01:00
request->generate_unnamed_trigger_beginning(on_upd_trg,
prim_rel_name,
prim_columns,
for_rel_name,
for_columns);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
USHORT num_fields = 0;
const dsql_nod* const* for_key_flds = for_columns->nod_arg;
const dsql_nod* ddl_node = request->req_ddl_node;
2001-05-23 15:26:42 +02:00
do {
// for every column in the foreign key ....
2003-11-10 10:16:38 +01:00
const dsql_str* for_key_fld_name_str = (dsql_str*) (*for_key_flds)->nod_arg[1];
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_assignment);
2001-05-23 15:26:42 +02:00
/* here stuff the default value as blr_literal .... or blr_null
if this col. does not have an applicable default */
/* the default is determined in many cases:
(1) the info. for the column is in memory. (This is because
the column is being created in this ddl statement)
(1-a) the table has a column level default. We get this by
searching the dsql parse tree starting from the ddl node.
(1-b) the table does not have a column level default, but
has a domain default. We get the domain name from the dsql
parse tree and call METD_get_domain_default to read the
default from the system tables.
(2) The default-info for this column is not in memory (This is
because this is an alter table ddl statement). The table
already exists; therefore we get the column and/or domain
default value from the system tables by calling:
2001-05-23 15:26:42 +02:00
METD_get_col_default(). */
2003-09-12 03:41:03 +02:00
bool found_default = false;
2001-12-24 03:51:06 +01:00
bool search_for_default = true;
2001-05-23 15:26:42 +02:00
// search the parse tree to find the column
2001-05-23 15:26:42 +02:00
const dsql_nod* elem = ddl_node->nod_arg[e_drl_elements];
const dsql_nod* const* ptr = elem->nod_arg;
for (const dsql_nod* const* const end = ptr + elem->nod_count;
ptr < end; ++ptr)
2001-12-24 03:51:06 +01:00
{
2001-05-23 15:26:42 +02:00
elem = *ptr;
2001-12-24 03:51:06 +01:00
if (elem->nod_type != nod_def_field) {
2001-05-23 15:26:42 +02:00
continue;
2001-12-24 03:51:06 +01:00
}
const dsql_fld* field = (dsql_fld*) elem->nod_arg[e_dfl_field];
if (strcmp(field->fld_name, for_key_fld_name_str->str_data))
2001-12-24 03:51:06 +01:00
{
continue;
}
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
// Now, we have the right column in the parse tree. case (1) above
2001-05-23 15:26:42 +02:00
dsql_nod* default_node = elem->nod_arg[e_dfl_default];
2001-12-24 03:51:06 +01:00
if (default_node)
{
2004-03-07 08:58:55 +01:00
// case (1-a) above: there is a col. level default
2001-05-23 15:26:42 +02:00
GEN_expr(request, default_node);
2003-10-16 10:51:06 +02:00
found_default = true;
2001-12-24 03:51:06 +01:00
search_for_default = false;
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
else
{
2003-10-16 10:51:06 +02:00
const TEXT* domain_name;
2003-11-10 10:16:38 +01:00
const dsql_str* domain_name_str;
const dsql_nod* tmp_node;
2001-12-24 03:51:06 +01:00
const dsql_nod* domain_node = elem->nod_arg[e_dfl_domain];
2003-10-16 10:51:06 +02:00
if (!domain_node ||
2001-05-23 15:26:42 +02:00
!(tmp_node = domain_node->nod_arg[e_dom_name]) ||
2003-11-10 10:16:38 +01:00
!(domain_name_str = (dsql_str*) tmp_node->nod_arg[e_fln_name])
|| !(domain_name = domain_name_str->str_data))
2001-12-24 03:51:06 +01:00
{
break;
}
2001-05-23 15:26:42 +02:00
/* case: (1-b): domain name is available. Column level default
2001-05-23 15:26:42 +02:00
is not declared. so get the domain default */
const USHORT def_len =
METD_get_domain_default(request, domain_name, &found_default,
default_val,
2001-05-23 15:26:42 +02:00
sizeof(default_val));
2001-12-24 03:51:06 +01:00
search_for_default = false;
2001-05-23 15:26:42 +02:00
if (found_default)
2001-12-24 03:51:06 +01:00
{
stuff_default_blr(request, default_val, def_len);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
else
2001-12-24 03:51:06 +01:00
{
// neither col level nor domain level default exists
request->append_uchar(blr_null);
}
2001-05-23 15:26:42 +02:00
}
break;
}
2001-12-24 03:51:06 +01:00
if (search_for_default)
{
// case 2: see if the column/domain has already been created
2001-05-23 15:26:42 +02:00
const USHORT def_len =
METD_get_col_default(request, for_rel_name,
for_key_fld_name_str->str_data,
2001-05-23 15:26:42 +02:00
&found_default,
default_val,
2001-05-23 15:26:42 +02:00
sizeof(default_val));
2001-12-24 03:51:06 +01:00
if (found_default) {
stuff_default_blr(request, default_val, def_len);
}
else {
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_null);
}
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
// the context for the foreign key relation
request->append_uchar(blr_field);
request->append_uchar(2);
request->append_cstring(0, for_key_fld_name_str->str_data);
2001-05-23 15:26:42 +02:00
num_fields++;
for_key_flds++;
2001-12-24 03:51:06 +01:00
} while (num_fields < for_columns->nod_count);
request->append_uchar(blr_end);
2001-05-23 15:26:42 +02:00
if (on_upd_trg) {
2001-12-24 03:51:06 +01:00
request->append_uchars(blr_end, 3);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
request->end_blr();
request->append_number(isc_dyn_system_flag,
frb_sysflag_referential_constraint);
2001-12-24 03:51:06 +01:00
// no trg_source and no trg_description
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void define_dimensions( dsql_req* request, const dsql_fld* field)
2001-05-23 15:26:42 +02:00
{
/*****************************************
*
* d e f i n e _ d i m e n s i o n s
*
*****************************************
*
* Function
* Define dimensions of an array
2001-05-23 15:26:42 +02:00
*
**************************************/
dsql_nod* elements = field->fld_ranges;
2003-10-16 10:51:06 +02:00
const USHORT dims = elements->nod_count / 2;
2001-05-23 15:26:42 +02:00
if (dims > MAX_ARRAY_DIMENSIONS)
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -604,
isc_arg_gds, isc_dsql_max_arr_dim_exceeded, 0);
2001-05-23 15:26:42 +02:00
}
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_dimensions, (SSHORT) dims);
2001-05-23 15:26:42 +02:00
SSHORT position = 0;
const dsql_nod* const* ptr = elements->nod_arg;
for (const dsql_nod* const* const end = ptr + elements->nod_count;
ptr < end; ++ptr, ++position)
2001-05-23 15:26:42 +02:00
{
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_def_dimension, position);
const dsql_nod* element = *ptr++;
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_dim_lower);
const SLONG lrange = (IPTR) (element->nod_arg[0]);
2001-12-24 03:51:06 +01:00
request->append_ulong_with_length(lrange);
2001-05-23 15:26:42 +02:00
element = *ptr;
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_dim_upper);
const SLONG hrange = (IPTR) (element->nod_arg[0]);
2001-12-24 03:51:06 +01:00
request->append_ulong_with_length(hrange);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
if (lrange >= hrange)
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -604,
isc_arg_gds, isc_dsql_arr_range_error, 0);
2001-05-23 15:26:42 +02:00
}
}
}
static void define_domain(dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e f i n e _ d o m a i n
*
**************************************
*
* Function
* Define a domain (global field)
2001-05-23 15:26:42 +02:00
*
**************************************/
2001-12-24 03:51:06 +01:00
bool null_flag = false;
bool check_flag = false;
2001-05-23 15:26:42 +02:00
dsql_nod* element = request->req_ddl_node;
dsql_fld* field = (dsql_fld*) element->nod_arg[e_dom_name];
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_global_fld, field->fld_name);
2001-05-23 15:26:42 +02:00
DDL_resolve_intl_type(request, field,
2003-11-10 10:16:38 +01:00
(dsql_str*) element->nod_arg[e_dom_collate]);
put_field(request, field, false);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// check for a default value
2001-05-23 15:26:42 +02:00
dsql_nod* node = element->nod_arg[e_dom_default];
2001-05-23 15:26:42 +02:00
if (node)
{
2003-09-02 01:22:22 +02:00
node = PASS1_node(request, node, false);
2003-11-08 00:27:24 +01:00
request->begin_blr(isc_dyn_fld_default_value);
2001-05-23 15:26:42 +02:00
GEN_expr(request, node);
2001-12-24 03:51:06 +01:00
request->end_blr();
2001-05-23 15:26:42 +02:00
2003-11-10 10:16:38 +01:00
const dsql_str* string = (dsql_str*) element->nod_arg[e_dom_default_source];
2001-05-23 15:26:42 +02:00
if (string)
{
2003-11-04 00:59:24 +01:00
fb_assert(string->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_fld_default_source,
string->str_data,
string->str_length);
2001-05-23 15:26:42 +02:00
}
}
if (field->fld_ranges)
{
define_dimensions(request, field);
}
2001-12-24 03:51:06 +01:00
// check for constraints
2001-05-23 15:26:42 +02:00
node = element->nod_arg[e_dom_constraint];
if (node)
{
dsql_nod** ptr = node->nod_arg;
const dsql_nod* const* const end_ptr = ptr + node->nod_count;
2001-05-23 15:26:42 +02:00
for (; ptr < end_ptr; ++ptr)
{
if ((*ptr)->nod_type == nod_rel_constraint)
{
dsql_nod* node1 = (*ptr)->nod_arg[e_rct_type];
2001-05-23 15:26:42 +02:00
if (node1->nod_type == nod_null)
{
2001-12-24 03:51:06 +01:00
if (!null_flag)
2001-05-23 15:26:42 +02:00
{
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_fld_not_null);
2001-12-24 03:51:06 +01:00
null_flag = true;
2001-05-23 15:26:42 +02:00
}
else
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -637,
isc_arg_gds, isc_dsql_duplicate_spec,
isc_arg_string, "NOT NULL", 0);
2001-05-23 15:26:42 +02:00
}
}
else if (node1->nod_type == nod_def_constraint)
{
if (check_flag)
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -637,
isc_arg_gds, isc_dsql_duplicate_spec,
isc_arg_string, "DOMAIN CHECK CONSTRAINT",
2001-05-23 15:26:42 +02:00
0);
}
2001-12-24 03:51:06 +01:00
check_flag = true;
2001-05-23 15:26:42 +02:00
2003-11-10 10:16:38 +01:00
const dsql_str* string = (dsql_str*) node1->nod_arg[e_cnstr_source];
2001-05-23 15:26:42 +02:00
if (string)
{
2003-11-04 00:59:24 +01:00
fb_assert(string->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_fld_validation_source,
string->str_data,
string->str_length);
2001-05-23 15:26:42 +02:00
}
2003-11-08 00:27:24 +01:00
request->begin_blr(isc_dyn_fld_validation_blr);
2001-05-23 15:26:42 +02:00
// Set any VALUE nodes to the type of the domain being defined.
2001-05-23 15:26:42 +02:00
if (node1->nod_arg[e_cnstr_condition])
{
set_nod_value_attributes(node1->nod_arg[e_cnstr_condition],
field);
}
/* Increment the context level for this request, so
that the context number for any RSE generated for a
SELECT within the CHECK clause will be greater than
0. In the environment of a domain check
constraint, context number 0 is reserved for the
"blr_fid, 0, 0, 0," which is emitted for a
2001-05-23 15:26:42 +02:00
nod_dom_value, corresponding to an occurance of the
VALUE keyword in the bod of the check constraint.
-- chrisj 1999-08-20 */
request->req_context_number++;
GEN_expr(request,
PASS1_node(request,
node1->nod_arg[e_cnstr_condition],
2003-09-02 01:22:22 +02:00
false));
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->end_blr();
2001-05-23 15:26:42 +02:00
}
}
}
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void define_exception( dsql_req* request, NOD_TYPE op)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e f i n e _ e x c e p t i o n
*
**************************************
*
* Function
* Generate ddl to create an exception code.
*
**************************************/
const dsql_nod* ddl_node = request->req_ddl_node;
2003-11-10 10:16:38 +01:00
const dsql_str* name = (dsql_str*) ddl_node->nod_arg[e_xcp_name];
const dsql_str* text = (dsql_str*) ddl_node->nod_arg[e_xcp_text];
2001-05-23 15:26:42 +02:00
if (op == nod_def_exception)
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_exception, name->str_data);
2001-05-23 15:26:42 +02:00
else if (op == nod_mod_exception)
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_mod_exception, name->str_data);
2001-05-23 15:26:42 +02:00
else
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_del_exception, name->str_data);
2001-05-23 15:26:42 +02:00
if (op != nod_del_exception) {
2003-11-04 00:59:24 +01:00
fb_assert(text->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string(isc_dyn_xcp_msg, text->str_data, text->str_length);
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
}
static void define_field(
dsql_req* request,
dsql_nod* element, SSHORT position,
2003-11-10 10:16:38 +01:00
const dsql_str* relation_name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e f i n e _ f i e l d
*
**************************************
*
* Function
* Define a field, either as part of a create
* table or an alter table statement.
*
**************************************/
dsql_fld* field = (dsql_fld*) element->nod_arg[e_dfl_field];
2001-05-23 15:26:42 +02:00
// add the field to the relation being defined for parsing purposes
2001-05-23 15:26:42 +02:00
dsql_rel* relation = request->req_relation;
2003-10-16 10:51:06 +02:00
if (relation != NULL) {
2001-05-23 15:26:42 +02:00
field->fld_next = relation->rel_fields;
relation->rel_fields = field;
}
const dsql_nod* domain_node = element->nod_arg[e_dfl_domain];
2003-10-16 10:51:06 +02:00
if (domain_node) {
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_local_fld, field->fld_name);
const dsql_nod* node1 = domain_node->nod_arg[e_dom_name];
2003-11-10 10:16:38 +01:00
const dsql_str* domain_name = (dsql_str*) node1->nod_arg[e_fln_name];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_fld_source, domain_name->str_data);
2001-05-23 15:26:42 +02:00
// Get the domain information
2001-05-23 15:26:42 +02:00
if (!(METD_get_domain(request, field, domain_name->str_data)))
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_dsql_domain_not_found,
isc_arg_string, domain_name->str_data,
// Specified domain or source field does not exist
2001-05-23 15:26:42 +02:00
0);
DDL_resolve_intl_type( request,
field,
reinterpret_cast<const dsql_str*>(element->nod_arg[e_dfl_collate]));
2001-05-23 15:26:42 +02:00
if (element->nod_arg[e_dfl_collate]) {
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_collation,
2001-05-23 15:26:42 +02:00
field->fld_collation_id);
}
}
2001-12-24 03:51:06 +01:00
else
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_sql_fld, field->fld_name);
2001-12-24 03:51:06 +01:00
if (relation_name) {
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_rel_name, relation_name->str_data);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (element->nod_arg[e_dfl_computed])
{
2001-05-23 15:26:42 +02:00
field->fld_flags |= FLD_computed;
dsql_nod* computed_node = element->nod_arg[e_dfl_computed];
2001-05-23 15:26:42 +02:00
define_computed(request,
request->req_ddl_node->nod_arg[e_drl_name], field,
computed_node);
}
DDL_resolve_intl_type(request, field,
reinterpret_cast<const dsql_str*>(element->nod_arg[e_dfl_collate]));
put_field(request, field, false);
2001-05-23 15:26:42 +02:00
}
if (position != -1)
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_position, position);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// check for a default value
2003-10-16 10:51:06 +02:00
bool default_null_flag = false;
dsql_nod* node = element->nod_arg[e_dfl_default];
2001-12-24 03:51:06 +01:00
if (node)
{
2003-09-02 01:22:22 +02:00
node = PASS1_node(request, node, false);
2003-11-08 00:27:24 +01:00
request->begin_blr(isc_dyn_fld_default_value);
2001-12-24 03:51:06 +01:00
if (node->nod_type == nod_null) {
default_null_flag = true;
}
2001-05-23 15:26:42 +02:00
GEN_expr(request, node);
2001-12-24 03:51:06 +01:00
request->end_blr();
const dsql_str* string = (dsql_str*) element->nod_arg[e_dfl_default_source];
2001-12-24 03:51:06 +01:00
if (string)
{
2003-11-04 00:59:24 +01:00
fb_assert(string->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_fld_default_source,
string->str_data,
string->str_length);
2001-05-23 15:26:42 +02:00
}
}
2001-12-24 03:51:06 +01:00
if (field->fld_ranges) {
2001-05-23 15:26:42 +02:00
define_dimensions(request, field);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2003-10-16 10:51:06 +02:00
// check for constraints
bool cnstrt_flag = false;
2001-12-24 03:51:06 +01:00
if (node = element->nod_arg[e_dfl_constraint])
{
const dsql_nod* const* const end_ptr = node->nod_arg + node->nod_count;
for (dsql_nod** ptr = node->nod_arg; ptr < end_ptr; ++ptr)
2001-12-24 03:51:06 +01:00
{
if ((*ptr)->nod_type == nod_rel_constraint)
{
const dsql_str* string = (dsql_str*) (*ptr)->nod_arg[e_rct_name];
dsql_nod* node1 = (*ptr)->nod_arg[e_rct_type];
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
switch (node1->nod_type)
2001-12-24 03:51:06 +01:00
{
2004-02-02 12:02:12 +01:00
case nod_null:
2001-12-24 03:51:06 +01:00
if (default_null_flag)
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -204,
isc_arg_gds, isc_bad_default_value,
isc_arg_gds, isc_invalid_clause,
isc_arg_string, "default null not null", 0);
2001-12-24 03:51:06 +01:00
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_fld_not_null);
if (!cnstrt_flag) {
request->append_uchar(isc_dyn_end); // For field definition
cnstrt_flag = true;
2001-05-23 15:26:42 +02:00
}
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_rel_constraint,
string ? string->str_data : 0);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_fld_not_null);
request->append_uchar(isc_dyn_end); // For NOT NULL Constraint definition
2004-02-02 12:02:12 +01:00
break;
case nod_primary:
case nod_unique:
2001-12-24 03:51:06 +01:00
{
if (!cnstrt_flag)
2001-12-24 03:51:06 +01:00
{
request->append_uchar(isc_dyn_end); // For field definition
cnstrt_flag = true;
2001-05-23 15:26:42 +02:00
}
const char* constraint_name = string ? string->str_data : 0;
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_rel_constraint, constraint_name);
const dsql_nod* index = node1->nod_arg[e_pri_index];
2003-11-04 00:59:24 +01:00
fb_assert(index);
const char* index_name = constraint_name;
2003-11-10 10:16:38 +01:00
string = (dsql_str*) index->nod_arg[e_idx_name];
2003-01-17 13:40:01 +01:00
if (string)
{
index_name = string->str_data;
2003-01-17 13:40:01 +01:00
}
if (node1->nod_type == nod_primary)
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_primary_key, index_name);
2001-12-24 03:51:06 +01:00
}
else if (node1->nod_type == nod_unique)
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_unique, index_name);
}
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_idx_unique, 1);
if (index->nod_arg[e_idx_asc_dsc])
{
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_idx_type, 1);
}
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_fld_name, field->fld_name);
request->append_uchar(isc_dyn_end);
2004-02-02 12:02:12 +01:00
break;
2001-05-23 15:26:42 +02:00
}
2004-02-02 12:02:12 +01:00
case nod_foreign:
{
if (!cnstrt_flag) {
request->append_uchar(isc_dyn_end); // For field definition
cnstrt_flag = true;
2001-05-23 15:26:42 +02:00
}
const char* constraint_name = string ? string->str_data : 0;
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_rel_constraint, constraint_name);
2003-01-17 13:40:01 +01:00
foreign_key(request, node1, constraint_name);
2004-02-02 12:02:12 +01:00
break;
2001-05-23 15:26:42 +02:00
}
2004-02-02 12:02:12 +01:00
case nod_def_constraint:
if (!cnstrt_flag) {
request->append_uchar(isc_dyn_end); // For field definition
cnstrt_flag = true;
2001-05-23 15:26:42 +02:00
}
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_rel_constraint,
string ? string->str_data : 0);
2001-05-23 15:26:42 +02:00
check_constraint(request, node1,
false); // No delete trigger
2004-02-02 12:02:12 +01:00
break;
2001-05-23 15:26:42 +02:00
}
}
}
}
if (!cnstrt_flag) {
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
2004-09-08 14:01:30 +02:00
static SSHORT getBlobFilterSubType(dsql_req* request, const dsql_nod* node)
{
/*******************************************
*
* g e t B l o b F i l t e r S u b T y p e
*
*******************************************
*
* Function
2004-09-09 10:58:13 +02:00
* get sub_type value from nod_constant.
2004-09-08 14:01:30 +02:00
*
**************************************/
fb_assert(node->nod_type == nod_constant);
switch(node->nod_desc.dsc_dtype)
{
case dtype_long:
return (SSHORT)(IPTR)node->nod_arg[0];
case dtype_text:
break;
default:
fb_assert(false);
return 0;
}
// fall thru for dtype_text
SSHORT blob_sub_type;
if (!METD_get_type(request,
(const dsql_str*)(node->nod_arg[0]),
"RDB$FIELD_SUB_TYPE",
&blob_sub_type))
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -204, isc_arg_gds,
isc_dsql_datatype_err, isc_arg_gds,
isc_dsql_blob_type_unknown, isc_arg_string,
((const dsql_str*)(node->nod_arg[0]))->str_data, 0);
}
return blob_sub_type;
}
static void define_filter( dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e f i n e _ f i l t e r
*
**************************************
*
* Function
* define a filter to the database.
*
**************************************/
2003-10-16 10:51:06 +02:00
const dsql_nod* filter_node = request->req_ddl_node;
const dsql_nod* const* ptr = filter_node->nod_arg;
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_filter,
2003-11-10 10:16:38 +01:00
((dsql_str*) (ptr[e_filter_name]))->str_data);
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_filter_in_subtype,
2004-09-08 14:01:30 +02:00
getBlobFilterSubType(request, ptr[e_filter_in_type]));
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_filter_out_subtype,
2004-09-08 14:01:30 +02:00
getBlobFilterSubType(request, ptr[e_filter_out_type]));
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_func_entry_point,
2003-11-10 10:16:38 +01:00
((dsql_str*) (ptr[e_filter_entry_pt]))->str_data);
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_func_module_name,
2003-11-10 10:16:38 +01:00
((dsql_str*) (ptr[e_filter_module]))->str_data);
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void define_generator( dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e f i n e _ g e n e r a t o r
*
**************************************
*
* Function
* create a generator.
*
**************************************/
2003-11-10 10:16:38 +01:00
const dsql_str* gen_name = (dsql_str*) request->req_ddl_node->nod_arg[e_gen_name];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_generator, gen_name->str_data);
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void define_index(dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e f i n e _ i n d e x
*
**************************************
*
* Function
* Generate ddl to create an index.
*
**************************************/
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_begin);
2001-05-23 15:26:42 +02:00
const dsql_nod* ddl_node = request->req_ddl_node;
dsql_nod* relation_node = (dsql_nod*) ddl_node->nod_arg[e_idx_table];
2003-11-10 10:16:38 +01:00
const dsql_str* relation_name = (dsql_str*) relation_node->nod_arg[e_rln_name];
dsql_nod* field_list = ddl_node->nod_arg[e_idx_fields];
2003-11-10 10:16:38 +01:00
const dsql_str* index_name = (dsql_str*) ddl_node->nod_arg[e_idx_name];
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_idx, index_name->str_data);
request->append_cstring(isc_dyn_rel_name, relation_name->str_data);
2001-05-23 15:26:42 +02:00
/* go through the fields list, making an index segment for each field,
2001-05-23 15:26:42 +02:00
unless we have a computation, in which case generate an expression index */
if (field_list->nod_type == nod_list)
2003-10-16 10:51:06 +02:00
{
const dsql_nod* const* ptr = field_list->nod_arg;
const dsql_nod* const* const end = ptr + field_list->nod_count;
2003-10-16 10:51:06 +02:00
for (; ptr < end; ptr++)
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_fld_name,
2003-11-10 10:16:38 +01:00
((dsql_str*) (*ptr)->nod_arg[1])->str_data);
}
2003-10-16 10:51:06 +02:00
}
2001-05-23 15:26:42 +02:00
#ifdef EXPRESSION_INDICES
else if (field_list->nod_type == nod_def_computed)
define_computed(request, relation_node, NULL, field_list);
#endif
// check for a unique index
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (ddl_node->nod_arg[e_idx_unique]) {
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_idx_unique, 1);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (ddl_node->nod_arg[e_idx_asc_dsc]) {
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_idx_type, 1);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
request->append_uchar(isc_dyn_end); // of define index
request->append_uchar(isc_dyn_end); // of begin
2001-05-23 15:26:42 +02:00
}
#ifdef NOT_USED_OR_REPLACED
static dsql_nod* define_insert_action( dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e f i n e _ i n s e r t _ a c t i o n
*
**************************************
*
* Function
* Define an action statement which, given a view
2001-05-23 15:26:42 +02:00
* definition, will store a record from
* a view of a single relation into the
2001-05-23 15:26:42 +02:00
* base relation.
*
**************************************/
dsql_nod* select_node, *select_expr, *from_list;
dsql_nod* fields_node, *values_node, *field_node;
dsql_nod **ptr, **end, **ptr2, **end2;
2003-11-10 10:16:38 +01:00
dsql_lls* field_stack;
dsql_lls* value_stack;
dsql_rel* relation;
dsql_fld* field;
2001-05-23 15:26:42 +02:00
dsql_nod* ddl_node = request->req_ddl_node;
2001-05-23 15:26:42 +02:00
// check whether this is an updatable view definition
2001-05-23 15:26:42 +02:00
2003-03-15 09:14:54 +01:00
if ((ddl_node->nod_type != nod_def_view && ddl_node->nod_type != nod_redef_view) ||
2001-05-23 15:26:42 +02:00
!(select_node = ddl_node->nod_arg[e_view_select]) ||
/*
2001-05-23 15:26:42 +02:00
Handle VIEWS with UNION : nod_select now points to nod_list
which in turn points to nod_select_expr
*/
!(select_expr = select_node->nod_arg[0]->nod_arg[0]) ||
!(from_list = select_expr->nod_arg[e_sel_from]) ||
from_list->nod_count != 1)
return NULL;
// make up an action node consisting of a list of 1 insert statement
2001-05-23 15:26:42 +02:00
dsql_nod* action_node = MAKE_node(nod_list, (int) 1);
dsql_nod* insert_node = MAKE_node(nod_insert, (int) e_ins_count);
2003-10-16 10:51:06 +02:00
action_node->nod_arg[0] = insert_node;
2001-05-23 15:26:42 +02:00
// use the relation referenced in the select statement to insert into
2001-05-23 15:26:42 +02:00
dsql_nod* relation_node = MAKE_node(nod_relation_name, (int) e_rln_count);
2001-05-23 15:26:42 +02:00
insert_node->nod_arg[e_ins_relation] = relation_node;
relation_node->nod_arg[e_rln_name] =
from_list->nod_arg[0]->nod_arg[e_rln_name];
relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(TEMP_CONTEXT);
2001-05-23 15:26:42 +02:00
/* get the list of values and fields to assign to -- if there is
2001-05-23 15:26:42 +02:00
no list of fields, get all fields in the base relation that
are not computed */
values_node = ddl_node->nod_arg[e_view_fields];
fields_node = select_expr->nod_arg[e_sel_list];
if (!fields_node)
{
const dsql_str* rel_name =
reinterpret_cast<const dsql_str*>(relation_node->nod_arg[e_rln_name]);
relation = METD_get_relation(request, rel_name);
2001-05-23 15:26:42 +02:00
field_stack = NULL;
for (field = relation->rel_fields; field; field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
continue;
field_node = MAKE_node(nod_field_name, (int) e_fln_count);
field_node->nod_arg[e_fln_name] = (dsql_nod*)MAKE_cstring(field->fld_name);
2001-05-23 15:26:42 +02:00
LLS_PUSH(field_node, &field_stack);
}
fields_node = MAKE_list(field_stack);
}
if (!values_node)
values_node = fields_node;
// generate the list of assignments to fields in the base relation
2001-05-23 15:26:42 +02:00
ptr = fields_node->nod_arg;
end = ptr + fields_node->nod_count;
ptr2 = values_node->nod_arg;
end2 = ptr2 + values_node->nod_count;
value_stack = field_stack = NULL;
for (; (ptr < end) && (ptr2 < end2); ptr++, ptr2++) {
field_node = *ptr;
if (field_node->nod_type == nod_alias)
field_node = field_node->nod_arg[e_alias_value];
// generate the actual assignment, assigning from a field in the "NEW" context
2001-05-23 15:26:42 +02:00
if (field_node->nod_type == nod_field_name) {
field_node->nod_arg[e_fln_context] =
(dsql_nod*) MAKE_cstring(TEMP_CONTEXT);
2001-05-23 15:26:42 +02:00
LLS_PUSH(field_node, &field_stack);
dsql_nod* value_node = MAKE_node(nod_field_name, (int) e_fln_count);
2001-05-23 15:26:42 +02:00
value_node->nod_arg[e_fln_name] = (*ptr2)->nod_arg[e_fln_name];
value_node->nod_arg[e_fln_context] =
(dsql_nod*) MAKE_cstring(NEW_CONTEXT);
2001-05-23 15:26:42 +02:00
LLS_PUSH(value_node, &value_stack);
}
}
insert_node->nod_arg[e_ins_values] = MAKE_list(value_stack);
insert_node->nod_arg[e_ins_fields] = MAKE_list(field_stack);
return action_node;
}
#endif
2001-05-23 15:26:42 +02:00
static void define_procedure( dsql_req* request, NOD_TYPE op)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e f i n e _ p r o c e d u r e
*
**************************************
*
* Function
* Create DYN to store a procedure
*
**************************************/
tsql* tdsql = DSQL_get_thread_data();
2001-05-23 15:26:42 +02:00
SSHORT inputs = 0, defaults = 0;
2001-12-24 03:51:06 +01:00
SSHORT outputs = 0;
SSHORT locals = 0;
const dsql_nod* procedure_node = request->req_ddl_node;
2003-11-10 10:16:38 +01:00
const dsql_str* procedure_name = (dsql_str*) procedure_node->nod_arg[e_prc_name];
2001-12-24 03:51:06 +01:00
if (op == nod_replace_procedure)
{
if (METD_get_procedure(request, procedure_name))
{
define_procedure(request, nod_mod_procedure);
}
else
{
define_procedure(request, nod_def_procedure);
}
return;
}
else if (op == nod_def_procedure || op == nod_redef_procedure)
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_procedure,
procedure_name->str_data);
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_rel_sql_protection, 1);
2001-05-23 15:26:42 +02:00
}
else // op == nod_mod_procedure
2001-12-24 03:51:06 +01:00
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_mod_procedure,
procedure_name->str_data);
const dsql_prc* procedure = METD_get_procedure(request, procedure_name);
2001-12-24 03:51:06 +01:00
if (procedure)
{
const dsql_fld* field;
2001-05-23 15:26:42 +02:00
for (field = procedure->prc_inputs; field;
2001-12-24 03:51:06 +01:00
field = field->fld_next)
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_delete_parameter,
2001-05-23 15:26:42 +02:00
field->fld_name);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
for (field = procedure->prc_outputs; field;
2001-12-24 03:51:06 +01:00
field = field->fld_next)
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_delete_parameter,
2001-05-23 15:26:42 +02:00
field->fld_name);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
}
}
2001-12-24 03:51:06 +01:00
2003-11-10 10:16:38 +01:00
const dsql_str* source = (dsql_str*) procedure_node->nod_arg[e_prc_source];
2001-12-24 03:51:06 +01:00
if (source)
{
2003-11-04 00:59:24 +01:00
fb_assert(source->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_prc_source,
source->str_data,
source->str_length);
2001-05-23 15:26:42 +02:00
}
// fill req_procedure to allow procedure to self reference
const size_t nExtra = strlen(procedure_name->str_data);
dsql_prc* procedure = FB_NEW_RPT(*tdsql->getDefaultPool(), nExtra) dsql_prc;
2001-05-23 15:26:42 +02:00
procedure->prc_name = procedure->prc_data;
procedure->prc_owner =
procedure->prc_data + procedure_name->str_length + 1;
strcpy(procedure->prc_name, (SCHAR *) procedure_name->str_data);
*procedure->prc_owner = '\0';
request->req_procedure = procedure;
// now do the input parameters
2001-05-23 15:26:42 +02:00
dsql_fld** field_ptr = &procedure->prc_inputs;
2001-05-23 15:26:42 +02:00
dsql_nod* parameters = procedure_node->nod_arg[e_prc_inputs];
if (parameters)
2001-12-24 03:51:06 +01:00
{
SSHORT position = 0;
dsql_nod** ptr = parameters->nod_arg;
for (const dsql_nod* const* const end = ptr + parameters->nod_count;
2001-12-24 03:51:06 +01:00
ptr < end; ptr++)
{
dsql_nod* parameter = *ptr;
dsql_fld* field = (dsql_fld*) parameter->nod_arg[e_dfl_field];
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_parameter, field->fld_name);
request->append_number(isc_dyn_prm_number, position);
request->append_number(isc_dyn_prm_type, 0);
2001-05-23 15:26:42 +02:00
DDL_resolve_intl_type(request, field, NULL);
put_field(request, field, false);
2001-05-23 15:26:42 +02:00
// check for a parameter default value
dsql_nod* node = parameter->nod_arg[e_dfl_default];
if (node)
{
node = PASS1_node(request, node, 0);
request->begin_blr(isc_dyn_fld_default_value);
GEN_expr(request, node);
request->end_blr();
dsql_str* string = (dsql_str*) parameter->nod_arg[e_dfl_default_source];
if (string)
{
fb_assert(string->str_length <= MAX_USHORT);
request->append_string(isc_dyn_fld_default_source,
string->str_data,
string->str_length);
}
defaults++;
}
else if (defaults) {
// parameter without default value after parameters with default
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -204,
isc_arg_gds, isc_bad_default_value,
isc_arg_gds, isc_invalid_clause,
isc_arg_string, "defaults must be last", 0);
}
2001-05-23 15:26:42 +02:00
*ptr = MAKE_variable(field, field->fld_name,
VAR_input, 0, (USHORT) (2 * position),
locals);
// put the field in a field list which will be stored to allow
// procedure self referencing
2001-05-23 15:26:42 +02:00
*field_ptr = field;
field_ptr = &field->fld_next;
position++;
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
request->append_number(isc_dyn_prc_inputs, position);
2001-05-23 15:26:42 +02:00
}
inputs = position;
}
// terminate the input list
2001-05-23 15:26:42 +02:00
*field_ptr = NULL;
// now do the output parameters
2001-05-23 15:26:42 +02:00
field_ptr = &procedure->prc_outputs;
2001-12-24 03:51:06 +01:00
if (parameters = procedure_node->nod_arg[e_prc_outputs])
{
SSHORT position = 0;
dsql_nod** ptr = parameters->nod_arg;
for (const dsql_nod* const* const end = ptr + parameters->nod_count;
ptr < end; ++ptr)
2001-12-24 03:51:06 +01:00
{
dsql_nod* parameter = *ptr;
dsql_fld* field = (dsql_fld*) parameter->nod_arg[e_dfl_field];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_parameter, field->fld_name);
request->append_number(isc_dyn_prm_number, position);
request->append_number(isc_dyn_prm_type, 1);
2001-05-23 15:26:42 +02:00
DDL_resolve_intl_type(request, field, NULL);
put_field(request, field, false);
2001-05-23 15:26:42 +02:00
*ptr = MAKE_variable(field, field->fld_name,
VAR_output, 1, (USHORT) (2 * position),
locals);
*field_ptr = field;
field_ptr = &field->fld_next;
position++;
locals++;
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
request->append_number(isc_dyn_prc_outputs, position);
2001-05-23 15:26:42 +02:00
}
outputs = position;
}
*field_ptr = NULL;
procedure->prc_out_count = outputs;
procedure->prc_in_count = inputs;
procedure->prc_def_count = defaults;
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->begin_blr(isc_dyn_prc_blr);
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_begin);
if (inputs)
{
request->append_uchar(blr_message);
request->append_uchar(0);
request->append_ushort(2 * inputs);
2001-05-23 15:26:42 +02:00
parameters = procedure_node->nod_arg[e_prc_inputs];
dsql_nod** ptr = parameters->nod_arg;
for (const dsql_nod* const* const end = ptr + parameters->nod_count;
2001-12-24 03:51:06 +01:00
ptr < end; ptr++)
{
dsql_nod* parameter = *ptr;
2004-02-02 12:02:12 +01:00
dsql_var* variable = (dsql_var*) parameter->nod_arg[e_var_variable];
dsql_fld* field = variable->var_field;
2001-05-23 15:26:42 +02:00
put_msg_field(request, field);
}
}
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_message);
request->append_uchar(1);
request->append_ushort(2 * outputs + 1);
if (outputs)
{
2001-05-23 15:26:42 +02:00
parameters = procedure_node->nod_arg[e_prc_outputs];
dsql_nod** ptr = parameters->nod_arg;
for (const dsql_nod* const* const end = ptr + parameters->nod_count;
2001-12-24 03:51:06 +01:00
ptr < end; ptr++)
{
dsql_nod* parameter = *ptr;
2004-02-02 12:02:12 +01:00
dsql_var* variable = (dsql_var*) parameter->nod_arg[e_var_variable];
dsql_fld* field = variable->var_field;
2001-05-23 15:26:42 +02:00
put_msg_field(request, field);
}
}
// add slot for EOS
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_short);
request->append_uchar(0);
2001-05-23 15:26:42 +02:00
if (inputs) {
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_receive);
request->append_uchar(0);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_begin);
if (outputs)
{
2001-05-23 15:26:42 +02:00
parameters = procedure_node->nod_arg[e_prc_outputs];
dsql_nod** ptr = parameters->nod_arg;
for (const dsql_nod* const* const end = ptr + parameters->nod_count;
2001-12-24 03:51:06 +01:00
ptr < end; ptr++)
{
dsql_nod* parameter = *ptr;
2004-02-02 12:02:12 +01:00
dsql_var* variable = (dsql_var*) parameter->nod_arg[e_var_variable];
put_local_variable(request, variable, 0);
2001-05-23 15:26:42 +02:00
}
}
put_local_variables(request, procedure_node->nod_arg[e_prc_dcls], locals);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_stall);
// put a label before body of procedure,
// so that any EXIT statement can get out
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_label);
request->append_uchar(0);
request->req_loop_level = 0;
request->req_cursor_number = 0;
2001-05-23 15:26:42 +02:00
GEN_statement(request,
PASS1_statement(request, procedure_node->nod_arg[e_prc_body], true));
2001-05-23 15:26:42 +02:00
request->req_type = REQ_DDL;
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_end);
GEN_return(request, procedure_node->nod_arg[e_prc_outputs], true);
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_end);
request->end_blr();
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
void DDL_gen_block(dsql_req* request, dsql_nod* node)
{
/**************************************
*
* D D L _ g e n _ b l o c k
*
**************************************
*
* Function
* Generate BLR for EXECUTE BLOCK statement
*
**************************************/
SSHORT inputs = 0, outputs = 0, locals = 0;
request->req_blk_node = node;
tsql* tdsql = DSQL_get_thread_data();
dsql_nod* parameters;
// now do the input parameters
if (parameters = node->nod_arg[e_exe_blk_inputs])
{
SSHORT position = 0;
dsql_nod** ptr = parameters->nod_arg;
for (const dsql_nod* const* const end = ptr + parameters->nod_count;
ptr < end; ptr++)
{
dsql_nod* parameter = (*ptr)->nod_arg[e_prm_val_fld];
dsql_fld* field = (dsql_fld*) parameter->nod_arg[e_dfl_field];
// parameter = (*ptr)->nod_arg[e_prm_val_val]; USELESS
DDL_resolve_intl_type(request, field, NULL);
*ptr = MAKE_variable(field, field->fld_name,
VAR_input, 0, (USHORT) (2 * position),
locals++);
position++;
}
inputs = position;
}
// now do the output parameters
if (parameters = node->nod_arg[e_exe_blk_outputs])
{
SSHORT position = 0;
dsql_nod** ptr = parameters->nod_arg;
for (const dsql_nod* const* const end = ptr + parameters->nod_count;
ptr < end; ++ptr)
{
dsql_fld* field = (dsql_fld*) (*ptr)->nod_arg[e_dfl_field];
DDL_resolve_intl_type(request, field, NULL);
*ptr = MAKE_variable(field, field->fld_name,
VAR_output, 1, (USHORT) (2 * position),
locals++);
position++;
}
outputs = position;
}
request->append_uchar(blr_begin);
if (inputs) {
request->req_send->msg_parameters =
parameter_reverse_order(request->req_send->msg_parameters, NULL);
GEN_port(request, request->req_send);
}
else
request->req_send = NULL;
if (outputs)
{
SSHORT position = 0;
parameters = node->nod_arg[e_exe_blk_outputs];
dsql_nod** ptr = parameters->nod_arg;
for (const dsql_nod* const* const end = ptr + parameters->nod_count;
ptr < end; ptr++)
{
2004-02-02 12:02:12 +01:00
dsql_par* param = MAKE_parameter(request->req_receive, true, true, ++position);
param->par_node = *ptr;
MAKE_desc(&param->par_desc, *ptr, NULL);
param->par_desc.dsc_flags |= DSC_nullable;
dsql_nod* parameter = *ptr;
2004-02-02 12:02:12 +01:00
dsql_var* variable = (dsql_var*) parameter->nod_arg[e_var_variable];
dsql_fld* field = variable->var_field;
param->par_name = param->par_alias = field->fld_name;
}
}
// Set up parameter to handle EOF
2004-02-02 12:02:12 +01:00
dsql_par* param = MAKE_parameter(request->req_receive, false, false, 0);
request->req_eof = param;
param->par_desc.dsc_dtype = dtype_short;
param->par_desc.dsc_scale = 0;
param->par_desc.dsc_length = sizeof(SSHORT);
request->req_receive->msg_parameters =
parameter_reverse_order(request->req_receive->msg_parameters, NULL);
GEN_port(request, request->req_receive);
if (inputs) {
request->append_uchar(blr_receive);
request->append_uchar(0);
}
request->append_uchar(blr_begin);
if (outputs)
{
parameters = node->nod_arg[e_exe_blk_outputs];
dsql_nod** ptr = parameters->nod_arg;
for (const dsql_nod* const* const end = ptr + parameters->nod_count;
ptr < end; ptr++)
{
dsql_nod* parameter = *ptr;
2004-02-02 12:02:12 +01:00
dsql_var* variable = (dsql_var*) parameter->nod_arg[e_var_variable];
put_local_variable(request, variable, 0);
}
}
put_local_variables(request, node->nod_arg[e_exe_blk_dcls], locals);
request->append_uchar(blr_stall);
// Put a label before body of procedure, so that
// any exit statement can get out
request->append_uchar(blr_label);
request->append_uchar(0);
request->req_loop_level = 0;
GEN_statement(request,
PASS1_statement(request, node->nod_arg[e_exe_blk_body], 1));
if (outputs)
request->req_type = REQ_SELECT_BLOCK;
else
request->req_type = REQ_EXEC_BLOCK;
request->append_uchar(blr_end);
GEN_return(request, node->nod_arg[e_exe_blk_outputs], true);
request->append_uchar(blr_end);
}
2001-05-23 15:26:42 +02:00
//
// Define a constraint, either as part of a create
// table or an alter table statement.
//
static void define_rel_constraint( dsql_req* request, dsql_nod* element)
2001-05-23 15:26:42 +02:00
{
2003-11-10 10:16:38 +01:00
const dsql_str* string = (dsql_str*) element->nod_arg[e_rct_name];
const char* constraint_name = string ? string->str_data : 0;
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_rel_constraint, constraint_name);
2001-05-23 15:26:42 +02:00
dsql_nod* node = element->nod_arg[e_rct_type];
2003-10-16 10:51:06 +02:00
switch(node->nod_type) {
case nod_unique:
case nod_primary:
2003-01-17 13:40:01 +01:00
make_index(request, node, node->nod_arg[0], 0, 0, constraint_name);
2003-10-16 10:51:06 +02:00
break;
case nod_foreign:
2003-01-17 13:40:01 +01:00
foreign_key(request, node, constraint_name);
2003-10-16 10:51:06 +02:00
break;
case nod_def_constraint:
check_constraint(request, node, false); // false = No delete trigger
break;
default: // silence compiler
break;
}
2001-05-23 15:26:42 +02:00
}
static void define_relation( dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e f i n e _ r e l a t i o n
*
**************************************
*
* Function
* Create an SQL table, relying on DYN to generate
* global fields for the local fields.
2001-05-23 15:26:42 +02:00
*
**************************************/
dsql_nod* ddl_node = request->req_ddl_node;
2001-05-23 15:26:42 +02:00
const dsql_nod* relation_node = ddl_node->nod_arg[e_drl_name];
2003-11-10 10:16:38 +01:00
const dsql_str* relation_name = (dsql_str*) relation_node->nod_arg[e_rln_name];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_rel, relation_name->str_data);
2003-11-10 10:16:38 +01:00
const dsql_str* external_file = (dsql_str*) ddl_node->nod_arg[e_drl_ext_file];
2003-10-16 10:51:06 +02:00
if (external_file)
2001-12-24 03:51:06 +01:00
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_rel_ext_file, external_file->str_data);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
save_relation(request, relation_name);
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_rel_sql_protection, 1);
2001-05-23 15:26:42 +02:00
// now do the actual metadata definition
2001-05-23 15:26:42 +02:00
dsql_nod* elements = ddl_node->nod_arg[e_drl_elements];
2003-10-16 10:51:06 +02:00
SSHORT position = 0;
dsql_nod** ptr = elements->nod_arg;
for (const dsql_nod* const* const end = ptr + elements->nod_count;
2003-10-16 10:51:06 +02:00
ptr < end; ptr++)
{
dsql_nod* element = *ptr;
2001-05-23 15:26:42 +02:00
switch (element->nod_type) {
case nod_def_field:
define_field(request, element, position, relation_name);
2003-10-16 10:51:06 +02:00
++position;
2001-05-23 15:26:42 +02:00
break;
case nod_rel_constraint:
define_rel_constraint(request, element);
break;
default:
break;
}
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
//
// Create a SQL role.
//
static void define_role(dsql_req* request)
2001-05-23 15:26:42 +02:00
{
2003-11-10 10:16:38 +01:00
const dsql_str* gen_name = (dsql_str*) request->req_ddl_node->nod_arg[e_gen_name];
request->append_cstring(isc_dyn_def_sql_role, gen_name->str_data);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void define_set_null_trg(dsql_req* request,
const dsql_nod* element,
const dsql_nod* for_columns,
const dsql_nod* prim_columns,
const char* prim_rel_name,
const char* for_rel_name,
bool on_upd_trg)
2001-05-23 15:26:42 +02:00
{
/*****************************************************
*
* d e f i n e _ s e t _ n u l l _ t r g
*
*****************************************************
*
* Function
* define "on delete/update set null" trigger (for referential integrity)
* The trigger blr is the same for both the delete and update
* cases. Only difference is its TRIGGER_TYPE (ON DELETE or ON UPDATE)
2003-10-16 10:51:06 +02:00
* The on_upd_trg parameter == true is an update trigger.
2001-05-23 15:26:42 +02:00
*
*****************************************************/
2001-12-24 03:51:06 +01:00
if (element->nod_type != nod_foreign) {
2001-05-23 15:26:42 +02:00
return;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// count of foreign key columns
2003-11-04 00:59:24 +01:00
fb_assert(prim_columns->nod_count == for_columns->nod_count);
fb_assert(prim_columns->nod_count != 0);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->generate_unnamed_trigger_beginning(on_upd_trg,
prim_rel_name,
prim_columns,
for_rel_name,
for_columns);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
USHORT num_fields = 0;
const dsql_nod* const* for_key_flds = for_columns->nod_arg;
2001-05-23 15:26:42 +02:00
do {
2003-11-10 10:16:38 +01:00
const dsql_str* for_key_fld_name_str = (dsql_str*) (*for_key_flds)->nod_arg[1];
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_assignment);
request->append_uchar(blr_null);
request->append_uchar(blr_field);
request->append_uchar(2);
request->append_cstring(0, for_key_fld_name_str->str_data);
2001-05-23 15:26:42 +02:00
num_fields++;
for_key_flds++;
2001-12-24 03:51:06 +01:00
} while (num_fields < for_columns->nod_count);
request->append_uchar(blr_end);
2001-05-23 15:26:42 +02:00
if (on_upd_trg) {
2001-12-24 03:51:06 +01:00
request->append_uchars(blr_end, 3);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
request->end_blr();
// end of the blr
2001-05-23 15:26:42 +02:00
2002-06-29 08:56:51 +02:00
request->append_number(isc_dyn_system_flag,
frb_sysflag_referential_constraint);
2001-12-24 03:51:06 +01:00
// no trg_source and no trg_description
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
//
// create a shadow for the database
//
static void define_shadow(dsql_req* request)
2001-05-23 15:26:42 +02:00
{
const dsql_nod* shadow_node = request->req_ddl_node;
const dsql_nod* const* ptr = shadow_node->nod_arg;
2001-05-23 15:26:42 +02:00
if (!ptr[e_shadow_number])
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_dsql_shadow_number_err, 0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
request->append_number(isc_dyn_def_shadow, (SSHORT)(IPTR) (ptr[e_shadow_number]));
2003-11-10 10:16:38 +01:00
request->append_cstring(isc_dyn_def_file, ((dsql_str*) (ptr[e_shadow_name]))->str_data);
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_shadow_man_auto,
(SSHORT)(IPTR) ((ptr[e_shadow_man_auto])->nod_arg[0]));
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_shadow_conditional,
(SSHORT)(IPTR) ((ptr[e_shadow_conditional])->nod_arg[0]));
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_file_start(0);
2001-05-23 15:26:42 +02:00
SLONG length = (IPTR) ptr[e_shadow_length];
2001-12-24 03:51:06 +01:00
request->append_file_length(length);
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
const dsql_nod* elements = ptr[e_shadow_sec_files];
2001-05-23 15:26:42 +02:00
if (elements)
2001-12-24 03:51:06 +01:00
{
ptr = elements->nod_arg;
for (const dsql_nod* const* const end = ptr + elements->nod_count;
ptr < end; ++ptr)
2001-12-24 03:51:06 +01:00
{
const dsql_nod* element = *ptr;
const dsql_fil* file = (dsql_fil*) element->nod_arg[0];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_file, file->fil_name->str_data);
2001-05-23 15:26:42 +02:00
if (!length && !file->fil_start)
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_dsql_file_length_err,
isc_arg_number, (ISC_STATUS) file->fil_name->str_data,
// Preceding file did not specify length, so %s must include starting page number
2001-05-23 15:26:42 +02:00
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
const SLONG start = file->fil_start;
2001-12-24 03:51:06 +01:00
request->append_file_start(start);
2001-05-23 15:26:42 +02:00
length = file->fil_length;
2001-12-24 03:51:06 +01:00
request->append_file_length(length);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
//
// Create the ddl to define or alter a trigger.
//
static void define_trigger( dsql_req* request, dsql_nod* node)
2001-05-23 15:26:42 +02:00
{
tsql* tdsql = DSQL_get_thread_data();
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// make the "define trigger" node the current request ddl node so
// that generating of BLR will be appropriate for trigger
2001-05-23 15:26:42 +02:00
request->req_ddl_node = node;
2003-11-10 10:16:38 +01:00
const dsql_str* trigger_name = (dsql_str*) node->nod_arg[e_trg_name];
2001-05-23 15:26:42 +02:00
USHORT trig_type;
dsql_nod* relation_node = NULL;
if (node->nod_type == nod_replace_trigger)
{
if (METD_get_trigger_relation(request, trigger_name, &trig_type))
{
node->nod_type = nod_mod_trigger;
}
else
{
node->nod_type = nod_def_trigger;
}
define_trigger(request, node);
return;
}
else if (node->nod_type == nod_def_trigger)
2001-12-24 03:51:06 +01:00
{
2003-11-04 00:59:24 +01:00
fb_assert(trigger_name->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_def_trigger,
trigger_name->str_data,
trigger_name->str_length);
2001-05-23 15:26:42 +02:00
relation_node = node->nod_arg[e_trg_table];
const dsql_str* relation_name =
(dsql_str*) relation_node->nod_arg[e_rln_name];
2003-11-04 00:59:24 +01:00
fb_assert(relation_name->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_rel_name,
relation_name->str_data,
relation_name->str_length);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_sql_object);
2001-05-23 15:26:42 +02:00
}
else // nod_mod_trigger
{
2003-11-04 00:59:24 +01:00
fb_assert(node->nod_type == nod_mod_trigger);
fb_assert(trigger_name->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_mod_trigger,
trigger_name->str_data,
trigger_name->str_length);
2001-12-24 03:51:06 +01:00
if (node->nod_arg[e_trg_actions])
{
2001-05-23 15:26:42 +02:00
/* Since we will be updating the body of the trigger, we need
to know what relation the trigger relates to. */
const dsql_str* relation_name =
METD_get_trigger_relation(request, trigger_name, &trig_type);
2001-12-24 03:51:06 +01:00
if (!relation_name)
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -204,
isc_arg_gds, isc_dsql_trigger_err, isc_arg_gds,
isc_random, isc_arg_string,
2001-05-23 15:26:42 +02:00
trigger_name->str_data, 0);
2001-12-24 03:51:06 +01:00
}
relation_node = FB_NEW_RPT(*tdsql->getDefaultPool(), e_rln_count) dsql_nod;
2001-05-23 15:26:42 +02:00
node->nod_arg[e_trg_table] = relation_node;
relation_node->nod_type = nod_relation_name;
relation_node->nod_count = e_rln_count;
// Warning: implicit const cast
relation_node->nod_arg[e_rln_name] = (dsql_nod*) relation_name;
2001-05-23 15:26:42 +02:00
}
}
2003-11-10 10:16:38 +01:00
const dsql_str* source = (dsql_str*) node->nod_arg[e_trg_source];
dsql_nod* actions = (node->nod_arg[e_trg_actions]) ?
node->nod_arg[e_trg_actions]->nod_arg[e_trg_act_body] : NULL;
2001-05-23 15:26:42 +02:00
if (source && actions) {
2003-11-04 00:59:24 +01:00
fb_assert(source->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_trg_source,
source->str_data,
source->str_length);
2001-05-23 15:26:42 +02:00
}
dsql_nod* constant = node->nod_arg[e_trg_active];
if (constant)
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_trg_inactive,
(SSHORT)(IPTR) constant->nod_arg[0]);
2001-05-23 15:26:42 +02:00
if (constant = node->nod_arg[e_trg_position])
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_trg_sequence,
(SSHORT)(IPTR) constant->nod_arg[0]);
2001-05-23 15:26:42 +02:00
if (constant = node->nod_arg[e_trg_type]) {
request->append_number(isc_dyn_trg_type, (SSHORT)(IPTR) constant->nod_arg[0]);
trig_type = (USHORT)(IPTR) constant->nod_arg[0];
2001-05-23 15:26:42 +02:00
}
else {
2003-11-04 00:59:24 +01:00
fb_assert(node->nod_type == nod_mod_trigger);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
if (actions)
{
2001-05-23 15:26:42 +02:00
/* create the "OLD" and "NEW" contexts for the trigger --
the new one could be a dummy place holder to avoid resolving
fields to that context but prevent relations referenced in
the trigger actions from referencing the predefined "1" context */
2001-12-24 03:51:06 +01:00
if (request->req_context_number) {
2001-05-23 15:26:42 +02:00
reset_context_stack(request);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
dsql_nod* const temp = relation_node->nod_arg[e_rln_alias];
if (hasOldContext(trig_type))
{
2001-05-23 15:26:42 +02:00
relation_node->nod_arg[e_rln_alias] =
(dsql_nod*) MAKE_cstring(OLD_CONTEXT);
2001-05-23 15:26:42 +02:00
PASS1_make_context(request, relation_node);
}
else
{
2001-05-23 15:26:42 +02:00
request->req_context_number++;
}
2001-05-23 15:26:42 +02:00
if (hasNewContext(trig_type))
2001-12-24 03:51:06 +01:00
{
2001-05-23 15:26:42 +02:00
relation_node->nod_arg[e_rln_alias] =
(dsql_nod*) MAKE_cstring(NEW_CONTEXT);
2001-05-23 15:26:42 +02:00
PASS1_make_context(request, relation_node);
}
else
2001-12-24 03:51:06 +01:00
{
2001-05-23 15:26:42 +02:00
request->req_context_number++;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
relation_node->nod_arg[e_rln_alias] = temp;
2001-12-24 03:51:06 +01:00
// generate the trigger blr
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->begin_blr(isc_dyn_trg_blr);
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_begin);
2001-05-23 15:26:42 +02:00
put_local_variables(request,
node->nod_arg[e_trg_actions]->nod_arg[e_trg_act_dcls], 0);
2001-05-23 15:26:42 +02:00
request->req_scope_level++;
// dimitr: I see no reason to deny EXIT command in triggers,
// hence I've added zero label at the beginning.
// My first suspicion regarding an obvious conflict
// with trigger messages (nod_abort) is wrong,
// although the fact that they use the same BLR code
// is still a potential danger and must be fixed.
// Hopefully, system triggers are never recompiled.
request->append_uchar(blr_label);
request->append_uchar(0);
request->req_loop_level = 0;
request->req_cursor_number = 0;
GEN_statement(request, PASS1_statement(request, actions, true));
2001-05-23 15:26:42 +02:00
request->req_scope_level--;
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_end);
request->end_blr();
2001-05-23 15:26:42 +02:00
/* the request type may have been set incorrectly when parsing
the trigger actions, so reset it to reflect the fact that this
is a data definition request; also reset the ddl node */
request->req_type = REQ_DDL;
}
/* const dsql_nod* temp = node->nod_arg[e_trg_messages];
if (temp)
2001-12-24 03:51:06 +01:00
{
const dsql_nod* const* ptr = temp->nod_arg;
for (const dsql_nod* const* const end = ptr + temp->nod_count;
ptr < end; ++ptr)
2001-12-24 03:51:06 +01:00
{
const dsql_nod* message = *ptr;
const SSHORT number = (SSHORT)(IPTR) message->nod_arg[e_msg_number];
2001-12-24 03:51:06 +01:00
if (message->nod_type == nod_del_trigger_msg)
{
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_delete_trigger_msg, number);
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
else
{
2003-11-10 10:16:38 +01:00
const dsql_str* message_text = (dsql_str*) message->nod_arg[e_msg_text];
2001-12-24 03:51:06 +01:00
if (message->nod_type == nod_def_trigger_msg) {
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_def_trigger_msg, number);
}
else {
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_mod_trigger_msg, number);
2001-12-24 03:51:06 +01:00
}
2003-11-04 00:59:24 +01:00
fb_assert(message_text->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_trg_msg,
message_text->str_data,
message_text->str_length);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
}
2001-12-24 03:51:06 +01:00
}
*/
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void define_udf( dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e f i n e _ u d f
*
**************************************
*
* Function
* define a udf to the database.
*
**************************************/
SSHORT position, blob_position = -1;
2001-05-23 15:26:42 +02:00
dsql_nod* udf_node = request->req_ddl_node;
dsql_nod* arguments = udf_node->nod_arg[e_udf_args];
dsql_nod** ptr = udf_node->nod_arg;
2003-11-10 10:16:38 +01:00
const char* udf_name = ((dsql_str*) (ptr[e_udf_name]))->str_data;
const dsql_str* func_entry_point_name = reinterpret_cast<dsql_str*>(ptr[e_udf_entry_pt]);
const dsql_str* func_module_name = reinterpret_cast<dsql_str*>(ptr[e_udf_module]);
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_function, udf_name);
request->append_cstring(isc_dyn_func_entry_point, func_entry_point_name->str_data);
request->append_cstring(isc_dyn_func_module_name, func_module_name->str_data);
2001-05-23 15:26:42 +02:00
dsql_nod** ret_val_ptr = ptr[e_udf_return_value]->nod_arg;
2001-05-23 15:26:42 +02:00
dsql_fld* field = (dsql_fld*) ret_val_ptr[0];
2003-10-16 10:51:06 +02:00
if (field) {
2001-05-23 15:26:42 +02:00
// CVC: This is case of "returns <type> [by value|reference]"
// Some data types can not be returned as value
2001-05-23 15:26:42 +02:00
if (((int) (IPTR) (ret_val_ptr[1]->nod_arg[0]) == Jrd::FUN_value) &&
2001-05-23 15:26:42 +02:00
(field->fld_dtype == dtype_text ||
field->fld_dtype == dtype_varying ||
field->fld_dtype == dtype_cstring ||
field->fld_dtype == dtype_blob ||
field->fld_dtype == dtype_timestamp))
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_return_mode_err,
// Return mode by value not allowed for this data type
2001-05-23 15:26:42 +02:00
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
/* For functions returning a blob, coerce return argument position to
be the last parameter. */
2001-12-24 03:51:06 +01:00
if (field->fld_dtype == dtype_blob)
{
2001-05-23 15:26:42 +02:00
blob_position = (arguments) ? arguments->nod_count + 1 : 1;
if (blob_position > MAX_UDF_ARGUMENTS)
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_extern_func_err,
// External functions can not have more than 10 parameters
// Or 9 if the function returns a BLOB
2001-05-23 15:26:42 +02:00
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_func_return_argument, blob_position);
2001-05-23 15:26:42 +02:00
}
else
2001-12-24 03:51:06 +01:00
{
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_func_return_argument, (SSHORT) 0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
position = 0;
}
else {
2002-06-29 08:56:51 +02:00
// CVC: This is case of "returns parameter <N>"
2002-06-29 08:56:51 +02:00
position = (SSHORT)(IPTR) (ret_val_ptr[1]->nod_arg[0]);
// Function modifies an argument whose value is the function return value
2001-05-23 15:26:42 +02:00
2002-06-29 08:56:51 +02:00
if (!arguments || position > arguments->nod_count || position < 1) {
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_udf_return_pos_err, //gds__extern_func_err,
isc_arg_number, (SLONG) (arguments ? arguments->nod_count : 0),
// CVC: We should devise new msg "position should be between 1 and #params";
// here it is: dsql_udf_return_pos_err
2002-06-29 08:56:51 +02:00
// External functions can not have more than 10 parameters
// Not strictly correct -- return position error
0);
}
// We'll verify that SCALAR_ARRAY can't be used as a return type.
// The support for SCALAR_ARRAY is only for input parameters.
const dsql_nod* ret_arg = arguments->nod_arg[position - 1];
const dsql_nod* const* param_node = ret_arg->nod_arg;
if (param_node[e_udf_param_type]) {
const SSHORT arg_mechanism = (SSHORT)(IPTR) (param_node[e_udf_param_type]->nod_arg[0]);
if (arg_mechanism == Jrd::FUN_scalar_array)
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_random,
isc_arg_string, "BY SCALAR_ARRAY can't be used as a return parameter",
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_func_return_argument, position);
2001-05-23 15:26:42 +02:00
position = 1;
}
// Now define all the arguments
2001-12-24 03:51:06 +01:00
if (!position)
{
/* CVC: This is case of "returns <type> [by value|reference]" */
2001-12-24 03:51:06 +01:00
if (field->fld_dtype == dtype_blob)
{
/* CVC: I need to test returning blobs by descriptor before allowing the
2003-10-16 10:51:06 +02:00
change there. For now, I ignore the return type specification. */
const bool free_it = ((SSHORT)(IPTR) ret_val_ptr[1]->nod_arg[0] < 0);
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_def_function_arg, blob_position);
request->append_number(isc_dyn_func_mechanism,
(SSHORT)(SLONG) ((free_it ? -1 : 1) * Jrd::FUN_blob_struct));
2001-05-23 15:26:42 +02:00
/* if we have the free_it set then the blob has
to be freed on return */
}
2001-12-24 03:51:06 +01:00
else
{
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_def_function_arg, (SSHORT) 0);
request->append_number(isc_dyn_func_mechanism,
(SSHORT)(IPTR) (ret_val_ptr[1]->nod_arg[0]));
2001-05-23 15:26:42 +02:00
}
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_function_name, udf_name);
2001-05-23 15:26:42 +02:00
DDL_resolve_intl_type(request, field, NULL);
put_field(request, field, true);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
position = 1;
}
2003-11-04 00:59:24 +01:00
fb_assert(position == 1);
2002-06-29 08:56:51 +02:00
/* CVC: This for all params, including the case of "returns parameter <N>" */
2002-06-29 08:56:51 +02:00
2001-05-23 15:26:42 +02:00
if (arguments)
2001-12-24 03:51:06 +01:00
{
ptr = arguments->nod_arg;
for (const dsql_nod* const* const end = ptr + arguments->nod_count;
2001-12-24 03:51:06 +01:00
ptr < end; ptr++, position++)
{
2001-05-23 15:26:42 +02:00
if (position > MAX_UDF_ARGUMENTS)
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_extern_func_err,
// External functions can not have more than 10 parameters
2001-05-23 15:26:42 +02:00
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
/*field = (dsql_fld*) *ptr; */
dsql_nod** param_node = (*ptr)->nod_arg;
field = (dsql_fld*) param_node[e_udf_param_field];
2002-06-29 08:56:51 +02:00
request->append_number(isc_dyn_def_function_arg, position);
2001-05-23 15:26:42 +02:00
if (param_node[e_udf_param_type]) {
const SSHORT arg_mechanism = (SSHORT)(IPTR) (param_node[e_udf_param_type]->nod_arg[0]);
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_func_mechanism, arg_mechanism);
}
else if (field->fld_dtype == dtype_blob) {
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_func_mechanism,
(SSHORT) Jrd::FUN_blob_struct);
}
2002-06-29 08:56:51 +02:00
else {
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_func_mechanism,
(SSHORT) Jrd::FUN_reference);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_function_name, udf_name);
2001-05-23 15:26:42 +02:00
DDL_resolve_intl_type(request, field, NULL);
put_field(request, field, true);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void define_update_action(
dsql_req* request,
dsql_nod** base_and_node, dsql_nod** base_relation)
2001-05-23 15:26:42 +02:00
{
2004-02-02 12:02:12 +01:00
/**************************************
2001-05-23 15:26:42 +02:00
*
* d e f i n e _ u p d a t e _ a c t i o n
*
**************************************
*
* Function
* Define an action statement which, given a view
2001-05-23 15:26:42 +02:00
* definition, will map a update to a record from
* a view of a single relation into the
2001-05-23 15:26:42 +02:00
* base relation.
*
**************************************/
dsql_nod* ddl_node = request->req_ddl_node;
2001-05-23 15:26:42 +02:00
// check whether this is an updatable view definition
2001-05-23 15:26:42 +02:00
dsql_nod* select_node = 0;
dsql_nod* select_expr = 0;
dsql_nod* from_list = 0;
2003-03-15 09:14:54 +01:00
if ((ddl_node->nod_type != nod_def_view && ddl_node->nod_type != nod_redef_view) ||
2001-05-23 15:26:42 +02:00
!(select_node = ddl_node->nod_arg[e_view_select]) ||
/*
2001-05-23 15:26:42 +02:00
Handle VIEWS with UNION : nod_select now points to nod_list
which in turn points to nod_select_expr
*/
!(select_expr = select_node->nod_arg[0]->nod_arg[0]) ||
!(from_list = select_expr->nod_arg[e_sel_from]) ||
from_list->nod_count != 1)
2003-10-16 10:51:06 +02:00
{
2001-05-23 15:26:42 +02:00
return;
2003-10-16 10:51:06 +02:00
}
2001-05-23 15:26:42 +02:00
// use the relation referenced in the select statement for rse
2001-05-23 15:26:42 +02:00
dsql_nod* relation_node = MAKE_node(nod_relation_name, (int) e_rln_count);
2001-05-23 15:26:42 +02:00
relation_node->nod_arg[e_rln_name] =
from_list->nod_arg[0]->nod_arg[e_rln_name];
relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(TEMP_CONTEXT);
2001-05-23 15:26:42 +02:00
*base_relation = relation_node;
/* get the list of values and fields to compare to -- if there is
2001-05-23 15:26:42 +02:00
no list of fields, get all fields in the base relation that
are not computed */
dsql_nod* values_node = ddl_node->nod_arg[e_view_fields];
dsql_nod* fields_node = select_expr->nod_arg[e_sel_list];
2003-10-16 10:51:06 +02:00
if (!fields_node)
2001-05-23 15:26:42 +02:00
{
const dsql_str* rel_name =
reinterpret_cast<const dsql_str*>(relation_node->nod_arg[e_rln_name]);
const dsql_rel* relation = METD_get_relation(request, rel_name);
DsqlNodStack field_stack;
for (const dsql_fld* field = relation->rel_fields; field;
field = field->fld_next)
2001-05-23 15:26:42 +02:00
{
if (field->fld_flags & FLD_computed)
continue;
2003-10-16 10:51:06 +02:00
dsql_nod* field_node = MAKE_node(nod_field_name, (int) e_fln_count);
2001-05-23 15:26:42 +02:00
field_node->nod_arg[e_fln_name] =
(dsql_nod*) MAKE_cstring(field->fld_name);
field_stack.push(field_node);
2001-05-23 15:26:42 +02:00
}
fields_node = MAKE_list(field_stack);
}
if (!values_node)
values_node = fields_node;
// generate the list of assignments to fields in the base relation
2001-05-23 15:26:42 +02:00
dsql_nod** ptr = fields_node->nod_arg;
const dsql_nod* const* const end = ptr + fields_node->nod_count;
dsql_nod** ptr2 = values_node->nod_arg;
const dsql_nod* const* const end2 = ptr2 + values_node->nod_count;
dsql_nod* and_node = MAKE_node(nod_and, (int) 2);
int and_arg = 0;
2001-05-23 15:26:42 +02:00
for (; (ptr < end) && (ptr2 < end2); ptr++, ptr2++) {
2003-10-16 10:51:06 +02:00
dsql_nod* field_node = *ptr;
2001-05-23 15:26:42 +02:00
if (field_node->nod_type == nod_alias)
field_node = field_node->nod_arg[e_alias_value];
// generate the actual comparisons
2001-05-23 15:26:42 +02:00
if (field_node->nod_type == nod_field_name) {
field_node->nod_arg[e_fln_context] =
(dsql_nod*) MAKE_cstring(TEMP_CONTEXT);
2001-05-23 15:26:42 +02:00
2003-10-20 12:12:49 +02:00
// CVC: This code serves no purpose.
//dsql_nod* value_node = MAKE_node(nod_field_name, (int) e_fln_count);
2003-10-20 12:12:49 +02:00
//value_node->nod_arg[e_fln_name] = (*ptr2)->nod_arg[e_fln_name];
//value_node->nod_arg[e_fln_context] =
// (dsql_nod*) MAKE_cstring(NEW_CONTEXT);
2001-05-23 15:26:42 +02:00
dsql_nod* old_value_node = MAKE_node(nod_field_name, (int) e_fln_count);
2001-05-23 15:26:42 +02:00
old_value_node->nod_arg[e_fln_name] =
(*ptr2)->nod_arg[e_fln_name];
old_value_node->nod_arg[e_fln_context] =
(dsql_nod*) MAKE_cstring(OLD_CONTEXT);
2003-10-16 10:51:06 +02:00
dsql_nod* eql_node = MAKE_node(nod_eql, (int) 2);
2001-05-23 15:26:42 +02:00
eql_node->nod_arg[0] = old_value_node;
eql_node->nod_arg[1] = field_node;
dsql_nod* anull_node = MAKE_node(nod_missing, 1);
2001-05-23 15:26:42 +02:00
anull_node->nod_arg[0] = old_value_node;
dsql_nod* bnull_node = MAKE_node(nod_missing, 1);
2001-05-23 15:26:42 +02:00
bnull_node->nod_arg[0] = field_node;
dsql_nod* iand_node = MAKE_node(nod_and, (int) 2);
2001-05-23 15:26:42 +02:00
iand_node->nod_arg[0] = anull_node;
iand_node->nod_arg[1] = bnull_node;
dsql_nod* or_node = MAKE_node(nod_or, (int) 2);
2001-05-23 15:26:42 +02:00
or_node->nod_arg[0] = eql_node;
or_node->nod_arg[1] = iand_node;
if (and_arg <= 1)
and_node->nod_arg[and_arg++] = or_node;
else {
dsql_nod* old_and = and_node;
2001-05-23 15:26:42 +02:00
and_node = MAKE_node(nod_and, (int) 2);
and_node->nod_arg[0] = old_and;
and_node->nod_arg[1] = or_node;
}
}
}
if (and_arg <= 1)
and_node->nod_arg[and_arg] = select_expr->nod_arg[e_sel_where];
else {
dsql_nod* old_and = and_node;
2001-05-23 15:26:42 +02:00
and_node = MAKE_node(nod_and, (int) 2);
and_node->nod_arg[0] = old_and;
and_node->nod_arg[1] = select_expr->nod_arg[e_sel_where];
}
*base_and_node = and_node;
}
static void define_upd_cascade_trg( dsql_req* request,
const dsql_nod* element,
const dsql_nod* for_columns,
const dsql_nod* prim_columns,
const char* prim_rel_name,
const char* for_rel_name)
2001-05-23 15:26:42 +02:00
{
/*****************************************************
*
* d e f i n e _ u p d _ c a s c a d e _ t r g
*
*****************************************************
*
* Function
* define "on update cascade" trigger (for referential integrity)
* along with the trigger blr.
*
*****************************************************/
2001-12-24 03:51:06 +01:00
if (element->nod_type != nod_foreign) {
2001-05-23 15:26:42 +02:00
return;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// count of foreign key columns
2003-11-04 00:59:24 +01:00
fb_assert(prim_columns->nod_count == for_columns->nod_count);
fb_assert(prim_columns->nod_count != 0);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->generate_unnamed_trigger_beginning(true,
prim_rel_name,
prim_columns,
for_rel_name,
for_columns);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
USHORT num_fields = 0;
const dsql_nod* const* for_key_flds = for_columns->nod_arg;
const dsql_nod* const* prim_key_flds = prim_columns->nod_arg;
2001-05-23 15:26:42 +02:00
do {
2003-11-10 10:16:38 +01:00
const dsql_str* for_key_fld_name_str = (dsql_str*) (*for_key_flds)->nod_arg[1];
const dsql_str* prim_key_fld_name_str = (dsql_str*) (*prim_key_flds)->nod_arg[1];
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_assignment);
request->append_uchar(blr_field);
request->append_uchar(1);
request->append_cstring(0, prim_key_fld_name_str->str_data);
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_field);
request->append_uchar(2);
request->append_cstring(0, for_key_fld_name_str->str_data);
2001-05-23 15:26:42 +02:00
num_fields++;
prim_key_flds++;
for_key_flds++;
2001-12-24 03:51:06 +01:00
} while (num_fields < for_columns->nod_count);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchars(blr_end, 4);
request->end_blr();
// end of the blr
2002-06-29 08:56:51 +02:00
request->append_number(isc_dyn_system_flag,
frb_sysflag_referential_constraint);
2001-12-24 03:51:06 +01:00
// no trg_source and no trg_description
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void define_view( dsql_req* request, NOD_TYPE op)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d e f i n e _ v i e w
*
**************************************
*
* Function
* Create the ddl to define a view, using a SELECT
* statement as the source of the view.
*
**************************************/
dsql_nod* node = request->req_ddl_node;
2003-11-10 10:16:38 +01:00
const dsql_str* view_name = (dsql_str*) node->nod_arg[e_view_name];
if (op == nod_replace_view)
{
if (METD_get_relation(request, view_name))
{
define_view(request, nod_mod_view);
}
else
{
define_view(request, nod_def_view);
}
return;
}
else if (op == nod_def_view || op == nod_redef_view)
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_view,
view_name->str_data);
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_rel_sql_protection, 1);
save_relation(request, view_name);
}
else // op == nod_mod_view
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_mod_view,
view_name->str_data);
2003-10-16 10:51:06 +02:00
const dsql_rel* relation = METD_get_relation(request, view_name);
if (relation)
{
2003-10-16 10:51:06 +02:00
for (const dsql_fld* field = relation->rel_fields; field;
field = field->fld_next)
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_delete_local_fld,
field->fld_name);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
}
}
else
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
/* isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_dsql_view_not_found, */
isc_arg_gds, 336068783L,
isc_arg_string, view_name->str_data,
isc_arg_end);
}
}
2001-05-23 15:26:42 +02:00
/* compile the SELECT statement into a record selection expression,
making sure to bump the context number since view contexts start
at 1 (except for computed fields) -- note that calling PASS1_rse
directly rather than PASS1_statement saves the context stack */
if (request->req_context_number)
reset_context_stack(request);
request->req_context_number++;
dsql_nod* select = node->nod_arg[e_view_select];
dsql_nod* select_expr = select->nod_arg[0];
dsql_nod* rse =
PASS1_rse(request, select_expr, select->nod_arg[e_select_order],
select->nod_arg[e_select_rows], NULL);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// store the blr and source string for the view definition
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->begin_blr(isc_dyn_view_blr);
2001-05-23 15:26:42 +02:00
GEN_expr(request, rse);
2001-12-24 03:51:06 +01:00
request->end_blr();
2001-05-23 15:26:42 +02:00
/* Store source for view. gdef -e cannot cope with it.
We need to add something to rdb$views to indicate source type.
Source will be for documentation purposes. */
2003-11-10 10:16:38 +01:00
const dsql_str* source = (dsql_str*) node->nod_arg[e_view_source];
2003-11-04 00:59:24 +01:00
fb_assert(source->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_view_source,
source->str_data,
source->str_length);
2001-05-23 15:26:42 +02:00
2002-06-29 08:56:51 +02:00
/* define the view source relations from the request contexts & union contexts*/
while (request->req_dt_context.hasData())
{
request->req_context->push(request->req_dt_context.pop());
}
2003-08-15 01:34:37 +02:00
while (request->req_union_context.hasData())
{
request->req_context->push(request->req_union_context.pop());
}
2002-06-29 08:56:51 +02:00
for (DsqlContextStack::iterator temp(*request->req_context); temp.hasData(); ++temp)
2001-12-24 03:51:06 +01:00
{
const dsql_ctx* context = temp.object();
2003-10-16 10:51:06 +02:00
const dsql_rel* relation = context->ctx_relation;
if (relation)
2001-12-24 03:51:06 +01:00
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_view_relation, relation->rel_name);
request->append_number(isc_dyn_view_context, context->ctx_context);
request->append_cstring(isc_dyn_view_context_name,
2001-05-23 15:26:42 +02:00
context->ctx_alias ? context->ctx_alias : relation->
rel_name);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
}
/* if there are field names defined for the view, match them in order
with the items from the SELECT. Otherwise use all the fields from
the rse node that was created from the select expression */
const dsql_nod* const* ptr = NULL;
const dsql_nod* const* end = NULL;
2003-10-16 10:51:06 +02:00
const dsql_nod* view_fields = node->nod_arg[e_view_fields];
if (view_fields != NULL) {
2001-05-23 15:26:42 +02:00
ptr = view_fields->nod_arg;
end = ptr + view_fields->nod_count;
}
2003-10-16 10:51:06 +02:00
const TEXT* field_string;
bool updatable = true;
SSHORT position = 0;
2001-05-23 15:26:42 +02:00
/* go through the fields list, defining the local fields;
if an expression is specified rather than a field, define
a global field for the computed value as well */
dsql_nod* items = rse->nod_arg[e_rse_items];
dsql_nod** i_ptr = items->nod_arg;
for (const dsql_nod* const* const i_end = i_ptr + items->nod_count;
i_ptr < i_end; i_ptr++, position++)
{
2003-10-16 10:51:06 +02:00
dsql_nod* field_node = *i_ptr;
2001-05-23 15:26:42 +02:00
// check if this is a field or an expression
2001-05-23 15:26:42 +02:00
2003-10-16 10:51:06 +02:00
const dsql_fld* field = NULL;
const dsql_ctx* context = NULL;
2001-05-23 15:26:42 +02:00
if (field_node->nod_type == nod_field) {
field = (dsql_fld*) field_node->nod_arg[e_fld_field];
2003-11-10 10:16:38 +01:00
context = (dsql_ctx*) field_node->nod_arg[e_fld_context];
2001-05-23 15:26:42 +02:00
}
else
updatable = false;
2001-05-23 15:26:42 +02:00
// if this is an expression, check to make sure there is a name specified
2001-05-23 15:26:42 +02:00
if (!ptr && !field)
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_specify_field_err,
// must specify field name for view select expression
2001-05-23 15:26:42 +02:00
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
// determine the proper field name, replacing the default if necessary
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (field) {
2001-05-23 15:26:42 +02:00
field_string = field->fld_name;
2001-12-24 03:51:06 +01:00
}
2002-10-02 15:24:03 +02:00
/* CVC: Small modification here to catch any mismatch between number of
explicit field names in a view and number of fields in the select expression,
see comment below. This closes Firebird Bug #223059. */
if (ptr)
2001-12-24 03:51:06 +01:00
{
2002-10-02 15:24:03 +02:00
if (ptr < end)
{
2003-11-10 10:16:38 +01:00
const dsql_str* field_name = (dsql_str*) (*ptr)->nod_arg[1];
2003-10-16 10:51:06 +02:00
field_string = (TEXT*) field_name->str_data;
2002-10-02 15:24:03 +02:00
}
2001-05-23 15:26:42 +02:00
ptr++;
}
/* if not an expression, point to the proper base relation field,
else make up an SQL field with generated global field for calculations */
2001-12-24 03:51:06 +01:00
if (field)
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_local_fld, field_string);
request->append_cstring(isc_dyn_fld_base_fld, field->fld_name);
request->append_number(isc_dyn_view_context, context->ctx_context);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
else
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_sql_fld, field_string);
MAKE_desc(&field_node->nod_desc, field_node, NULL);
2001-05-23 15:26:42 +02:00
put_descriptor(request, &field_node->nod_desc);
2003-11-08 00:27:24 +01:00
request->begin_blr(isc_dyn_fld_computed_blr);
2001-05-23 15:26:42 +02:00
GEN_expr(request, field_node);
2001-12-24 03:51:06 +01:00
request->end_blr();
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_view_context, (SSHORT) 0);
2001-05-23 15:26:42 +02:00
}
save_field(request, field_string);
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_position, position);
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
2002-06-29 08:56:51 +02:00
/* CVC: This message was not catching the case when
#fields<items in select list, see comment above. */
2001-05-23 15:26:42 +02:00
if (ptr != end)
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_num_field_err,
// number of fields does not match select list
2001-05-23 15:26:42 +02:00
0);
2001-12-24 03:51:06 +01:00
}
// setup to define triggers for WITH CHECK OPTION
2001-05-23 15:26:42 +02:00
dsql_nod* check = node->nod_arg[e_view_check];
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (check)
{
2001-05-23 15:26:42 +02:00
if (!updatable)
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_col_name_err,
// Only simple column names permitted for VIEW WITH CHECK OPTION
2001-05-23 15:26:42 +02:00
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
if (select_expr->nod_count != 1)
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_table_view_err,
// Only one table allowed for VIEW WITH CHECK OPTION
2001-05-23 15:26:42 +02:00
0);
2001-12-24 03:51:06 +01:00
}
/*
2001-05-23 15:26:42 +02:00
Handle VIEWS with UNION : nod_select now points to nod_list
which in turn points to nod_select_expr
*/
else if (select_expr->nod_arg[0]->nod_arg[e_sel_from]->nod_count != 1)
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_table_view_err,
// Only one table allowed for VIEW WITH CHECK OPTION
2001-05-23 15:26:42 +02:00
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
/*
2001-05-23 15:26:42 +02:00
Handle VIEWS with UNION : nod_select now points to nod_list
which in turn points to nod_select_expr
*/
select_expr = select_expr->nod_arg[0];
if (!(select_expr->nod_arg[e_sel_where]))
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_where_err,
// No where clause for VIEW WITH CHECK OPTION
2001-05-23 15:26:42 +02:00
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
if (select_expr->nod_arg[e_sel_distinct] ||
select_expr->nod_arg[e_sel_group] ||
select_expr->nod_arg[e_sel_having])
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_distinct_err,
// DISTINCT, GROUP or HAVING not permitted for VIEW WITH CHECK OPTION
2001-05-23 15:26:42 +02:00
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
dsql_nod* relation_node = MAKE_node(nod_relation_name, e_rln_count);
// Warning: implicit const_cast
relation_node->nod_arg[e_rln_name] = (dsql_nod*) view_name;
2001-05-23 15:26:42 +02:00
check->nod_arg[e_cnstr_table] = relation_node;
check->nod_arg[e_cnstr_source] = (dsql_nod*) source;
2001-05-23 15:26:42 +02:00
/* the condition for the trigger is the converse of the selection
criteria for the view, suitably fixed up so that the fields in
2001-05-23 15:26:42 +02:00
the view are referenced */
check->nod_arg[e_cnstr_condition] = select_expr->nod_arg[e_sel_where];
// Define the triggers
2001-05-23 15:26:42 +02:00
create_view_triggers(request, check, rse->nod_arg[e_rse_items]);
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
reset_context_stack(request);
}
static void define_view_trigger( dsql_req* request, dsql_nod* node, dsql_nod* rse,
dsql_nod* items)
{ // The fields in VIEW actually
2001-05-23 15:26:42 +02:00
/**************************************
*
* d e f i n e _ v i e w _ t r i g g e r
*
**************************************
*
* Function
* Create the ddl to define a trigger for a VIEW WITH CHECK OPTION.
*
**************************************/
tsql* tdsql = DSQL_get_thread_data();
2001-05-23 15:26:42 +02:00
dsql_nod* ddl_node = request->req_ddl_node;
2001-05-23 15:26:42 +02:00
dsql_nod* select = ddl_node->nod_arg[e_view_select];
/*
2001-05-23 15:26:42 +02:00
Handle VIEWS with UNION : nod_select now points to nod_list
which in turn points to nod_select_expr
*/
dsql_nod* select_expr = select->nod_arg[0]->nod_arg[0];
dsql_nod* view_fields = ddl_node->nod_arg[e_view_fields];
2001-05-23 15:26:42 +02:00
/* make the "define trigger" node the current request ddl node so
that generating of BLR will be appropriate for trigger */
request->req_ddl_node = node;
2003-11-10 10:16:38 +01:00
const dsql_str* trigger_name = (dsql_str*) node->nod_arg[e_cnstr_name];
dsql_nod* relation_node = NULL;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (node->nod_type == nod_def_constraint)
{
2003-11-04 00:59:24 +01:00
fb_assert(trigger_name->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_def_trigger,
trigger_name->str_data,
trigger_name->str_length);
2001-05-23 15:26:42 +02:00
relation_node = node->nod_arg[e_cnstr_table];
const dsql_str* relation_name = (dsql_str*) relation_node->nod_arg[e_rln_name];
2003-11-04 00:59:24 +01:00
fb_assert(relation_name->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_rel_name,
relation_name->str_data,
relation_name->str_length);
2001-05-23 15:26:42 +02:00
}
else
2001-12-24 03:51:06 +01:00
{
2001-05-23 15:26:42 +02:00
return;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
dsql_nod* constant = node->nod_arg[e_cnstr_position];
2001-12-24 03:51:06 +01:00
if (constant)
{
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_trg_sequence,
(SSHORT)(IPTR) (constant ? constant->nod_arg[0] : 0));
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
constant = node->nod_arg[e_cnstr_type];
2003-10-16 10:51:06 +02:00
USHORT trig_type;
2001-12-24 03:51:06 +01:00
if (constant)
{
trig_type = (USHORT)(IPTR) constant->nod_arg[0];
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_trg_type, trig_type);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
else
{
2001-05-23 15:26:42 +02:00
/* If we don't have a trigger type assigned, then this is just a template
definition for use with domains. The real triggers are defined when
the domain is used. */
trig_type = 0;
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_sql_object);
2001-05-23 15:26:42 +02:00
2003-11-10 10:16:38 +01:00
const dsql_str* message = (dsql_str*) node->nod_arg[e_cnstr_message];
2001-12-24 03:51:06 +01:00
if (message)
{
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_def_trigger_msg, 0);
2003-11-04 00:59:24 +01:00
fb_assert(message->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_trg_msg,
message->str_data,
message->str_length);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
// generate the trigger blr
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (node->nod_arg[e_cnstr_condition] && node->nod_arg[e_cnstr_actions])
{
2003-11-08 00:27:24 +01:00
request->begin_blr(isc_dyn_trg_blr);
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_begin);
2001-05-23 15:26:42 +02:00
/* create the "OLD" and "NEW" contexts for the trigger --
the new one could be a dummy place holder to avoid resolving
fields to that context but prevent relations referenced in
the trigger actions from referencing the predefined "1" context */
2003-10-16 10:51:06 +02:00
dsql_ctx* sav_context = 0;
dsql_ctx* context = 0;
2001-05-23 15:26:42 +02:00
if (request->req_context_number) {
/* If an alias is specified for the single base table involved,
save and then add the context */
context = request->req_context->object();
2001-05-23 15:26:42 +02:00
if (context->ctx_alias) {
sav_context = FB_NEW(*tdsql->getDefaultPool())
dsql_ctx(*tdsql->getDefaultPool());
2001-05-23 15:26:42 +02:00
*sav_context = *context;
}
}
reset_context_stack(request);
dsql_nod* temp_alias = relation_node->nod_arg[e_rln_alias];
relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(OLD_CONTEXT);
2001-05-23 15:26:42 +02:00
PASS1_make_context(request, relation_node);
relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(NEW_CONTEXT);
2001-05-23 15:26:42 +02:00
PASS1_make_context(request, relation_node);
2003-10-16 10:51:06 +02:00
relation_node->nod_arg[e_rln_alias] = temp_alias;
2001-05-23 15:26:42 +02:00
if (sav_context) {
sav_context->ctx_context = request->req_context_number++;
context->ctx_scope_level = request->req_scope_level;
request->req_context->push(sav_context);
2001-05-23 15:26:42 +02:00
}
if (trig_type == PRE_MODIFY_TRIGGER) {
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_for);
dsql_nod* temp = rse->nod_arg[e_rse_streams];
2003-09-02 01:22:22 +02:00
temp->nod_arg[0] = PASS1_node(request, temp->nod_arg[0], false);
2001-05-23 15:26:42 +02:00
temp = rse->nod_arg[e_rse_boolean];
2003-09-02 01:22:22 +02:00
rse->nod_arg[e_rse_boolean] = PASS1_node(request, temp, false);
2001-05-23 15:26:42 +02:00
GEN_expr(request, rse);
dsql_nod* condition = MAKE_node(nod_not, 1);
2001-05-23 15:26:42 +02:00
condition->nod_arg[0] =
replace_field_names(select_expr->nod_arg[e_sel_where], items,
view_fields, false);
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_begin);
request->append_uchar(blr_if);
2003-09-02 01:22:22 +02:00
GEN_expr(request, PASS1_node(request, condition->nod_arg[0], false));
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_begin);
request->append_uchar(blr_end);
2001-05-23 15:26:42 +02:00
}
if (trig_type == PRE_STORE_TRIGGER) {
dsql_nod* condition = MAKE_node(nod_not, 1);
2001-05-23 15:26:42 +02:00
condition->nod_arg[0] =
replace_field_names(select_expr->nod_arg[e_sel_where], items,
view_fields, true);
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_if);
2003-09-02 01:22:22 +02:00
GEN_expr(request, PASS1_node(request, condition->nod_arg[0], false));
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_begin);
request->append_uchar(blr_end);
2001-05-23 15:26:42 +02:00
}
// generate the action statements for the trigger
2001-05-23 15:26:42 +02:00
dsql_nod* actions = node->nod_arg[e_cnstr_actions];
dsql_nod** ptr = actions->nod_arg;
for (const dsql_nod* const* const end = ptr + actions->nod_count;
2001-05-23 15:26:42 +02:00
ptr < end; ptr++)
2001-12-24 03:51:06 +01:00
{
GEN_statement(request, PASS1_statement(request, *ptr, false));
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// generate the action statements for the trigger
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
actions = node->nod_arg[e_cnstr_else];
if (actions)
{
request->append_uchar(blr_begin);
dsql_nod** ptr2 = actions->nod_arg;
for (const dsql_nod* const* const end2 = ptr2 + actions->nod_count;
ptr2 < end2; ptr++)
2001-12-24 03:51:06 +01:00
{
dsql_nod* action_node = PASS1_statement(request, *ptr2, false);
2001-12-24 03:51:06 +01:00
if (action_node->nod_type == nod_modify)
{
dsql_nod* temp_rse = action_node->nod_arg[e_mod_rse];
2001-05-23 15:26:42 +02:00
temp_rse->nod_arg[e_rse_first] =
2003-11-10 10:16:38 +01:00
MAKE_constant((dsql_str*) 1, CONSTANT_SLONG);
2001-05-23 15:26:42 +02:00
}
GEN_statement(request, action_node);
}
request->append_uchar(blr_end); // of begin
2001-05-23 15:26:42 +02:00
}
request->append_uchar(blr_end); // of if
2001-12-24 03:51:06 +01:00
if (trig_type == PRE_MODIFY_TRIGGER) {
request->append_uchar(blr_end); // of for
2001-12-24 03:51:06 +01:00
}
request->end_blr();
2001-05-23 15:26:42 +02:00
}
2002-06-29 08:56:51 +02:00
request->append_number(isc_dyn_system_flag, frb_sysflag_view_check);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
/* the request type may have been set incorrectly when parsing
the trigger actions, so reset it to reflect the fact that this
is a data definition request; also reset the ddl node */
request->req_type = REQ_DDL;
request->req_ddl_node = ddl_node;
reset_context_stack(request);
}
static void delete_procedure (dsql_req* request,
dsql_nod* node,
bool silent_deletion)
2002-06-29 08:56:51 +02:00
{
/**************************************
*
* d e l e t e _ p r o c e d u r e
*
**************************************
*
* Function
* Do nothing and don't throw error if the procedure doesn't exist
* and silent_deletion is true.
* CVC: Created this function to not clutter generate_dyn().
*
**************************************/
2003-11-10 10:16:38 +01:00
const dsql_str* string = (dsql_str*) node->nod_arg[e_prc_name];
2003-11-04 00:59:24 +01:00
fb_assert (string);
2002-06-29 08:56:51 +02:00
if (node->nod_type == nod_redef_procedure || silent_deletion) {
dsql_prc* procedure = METD_get_procedure (request, string);
2002-06-29 08:56:51 +02:00
if (!procedure) {
return;
}
}
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_delete_procedure, string->str_data);
request->append_uchar(isc_dyn_end);
2002-06-29 08:56:51 +02:00
}
static void delete_relation_view (
dsql_req* request,
dsql_nod* node,
bool silent_deletion)
2002-06-29 08:56:51 +02:00
{
/**************************************
*
* d e l e t e _ r e l a t i o n _ v i e w
*
**************************************
*
* Function
* Check that DROP TABLE is dropping a table and that
* DROP VIEW is dropping a view.
* Do nothing and don't throw error if the table or view doesn't exist
* and silent_deletion is true.
* CVC: Created this function to not clutter generate_dyn().
*
**************************************/
2003-11-10 10:16:38 +01:00
const dsql_str* string = 0;
2002-06-29 08:56:51 +02:00
if (node->nod_type == nod_redef_relation) {
dsql_nod* relation_node = node->nod_arg[e_alt_name];
2003-11-04 00:59:24 +01:00
fb_assert (relation_node);
2003-11-10 10:16:38 +01:00
string = (dsql_str*) relation_node->nod_arg[e_rln_name];
2002-06-29 08:56:51 +02:00
}
else {
2003-11-10 10:16:38 +01:00
string = (dsql_str*) node->nod_arg[e_alt_name];
2002-06-29 08:56:51 +02:00
}
2003-11-04 00:59:24 +01:00
fb_assert (string);
2002-06-29 08:56:51 +02:00
const dsql_rel* relation = METD_get_relation (request, string);
2002-06-29 08:56:51 +02:00
if (node->nod_type == nod_del_relation ||
2003-10-16 10:51:06 +02:00
node->nod_type == nod_redef_relation)
{
2002-06-29 08:56:51 +02:00
if (!relation && !silent_deletion ||
2003-10-16 10:51:06 +02:00
relation && (relation->rel_flags & REL_view))
{
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -607,
/* isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_dsql_table_not_found, */
isc_arg_gds, 336068783L,
isc_arg_string, string->str_data,
isc_arg_end);
2002-06-29 08:56:51 +02:00
}
}
else { /* node->nod_type == nod_del_view, nod_redef_view */
if (!relation && !silent_deletion ||
relation && !(relation->rel_flags & REL_view)) {
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -607,
/* isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_dsql_view_not_found, */
isc_arg_gds, 336068783L,
isc_arg_string, string->str_data,
isc_arg_end);
2002-06-29 08:56:51 +02:00
}
}
if (relation) {
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_delete_rel, string->str_data);
request->append_uchar(isc_dyn_end);
2002-06-29 08:56:51 +02:00
}
}
static void foreign_key( dsql_req* request, dsql_nod* element, const char* index_name)
2001-05-23 15:26:42 +02:00
{
2004-02-02 12:02:12 +01:00
/**************************************
2001-05-23 15:26:42 +02:00
*
* f o r e i g n _ k e y
*
**************************************
*
* Function
* Generate ddl to create a foreign key
* constraint.
*
**************************************/
dsql_nod* columns1 = element->nod_arg[e_for_columns];
2001-05-23 15:26:42 +02:00
dsql_nod* relation2_node = element->nod_arg[e_for_reftable];
2003-11-10 10:16:38 +01:00
const dsql_str* relation2 = (dsql_str*) relation2_node->nod_arg[e_rln_name];
2001-05-23 15:26:42 +02:00
/* If there is a referenced table name but no referenced field names, the
primary key of the referenced table designates the referenced fields. */
dsql_nod* columns2 = element->nod_arg[e_for_refcolumns];
2003-10-16 10:51:06 +02:00
if (!columns2)
2001-12-24 03:51:06 +01:00
{
2001-05-23 15:26:42 +02:00
element->nod_arg[e_for_refcolumns] =
columns2 = METD_get_primary_key(request, relation2);
/* If there is NEITHER an explicitly referenced field name, NOR does
the referenced table have a primary key to serve as the implicitly
referenced field, fail. */
if (!columns2)
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_reftable_requires_pk,
2001-05-23 15:26:42 +02:00
/* "REFERENCES table" without "(column)" requires PRIMARY
KEY on referenced table */
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
if (columns2 && (columns1->nod_count != columns2->nod_count))
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_key_field_count_err,
// foreign key field count does not match primary key
2001-05-23 15:26:42 +02:00
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
/* define the foreign key index and the triggers that may be needed
for referential integrity action. */
make_index_trg_ref_int(request, element, columns1,
element->nod_arg[e_for_refcolumns],
relation2->str_data,
2003-01-17 13:40:01 +01:00
index_name);
2001-05-23 15:26:42 +02:00
}
static void generate_dyn( dsql_req* request, dsql_nod* node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g e n e r a t e _ d y n
*
**************************************
*
* Functional description
* Switch off the type of node to generate a
* DYN string.
*
**************************************/
2003-11-10 10:16:38 +01:00
const dsql_str* string;
2001-05-23 15:26:42 +02:00
request->req_ddl_node = node;
switch (node->nod_type) {
case nod_def_domain:
define_domain(request);
break;
case nod_mod_domain:
modify_domain(request);
break;
case nod_def_index:
define_index(request);
break;
case nod_def_relation:
define_relation(request);
break;
2002-06-29 08:56:51 +02:00
case nod_redef_relation:
2003-11-08 00:27:24 +01:00
stuff(request, isc_dyn_begin);
2003-10-05 08:33:56 +02:00
delete_relation_view(request, node, true); // silent.
define_relation (request);
2003-11-08 00:27:24 +01:00
stuff(request, isc_dyn_end);
break;
2002-06-29 08:56:51 +02:00
2001-05-23 15:26:42 +02:00
case nod_def_view:
case nod_mod_view:
case nod_replace_view:
define_view(request, node->nod_type);
2001-05-23 15:26:42 +02:00
break;
case nod_redef_view:
2003-11-08 00:27:24 +01:00
stuff(request, isc_dyn_begin);
2003-10-05 08:33:56 +02:00
delete_relation_view(request, node, true); // silent.
define_view(request, node->nod_type);
2003-11-08 00:27:24 +01:00
stuff(request, isc_dyn_end);
break;
2001-05-23 15:26:42 +02:00
case nod_def_exception:
case nod_mod_exception:
case nod_del_exception:
define_exception(request, node->nod_type);
break;
case nod_def_procedure:
case nod_mod_procedure:
case nod_replace_procedure:
2001-05-23 15:26:42 +02:00
define_procedure(request, node->nod_type);
break;
2002-06-29 08:56:51 +02:00
case nod_redef_procedure:
2003-11-08 00:27:24 +01:00
stuff(request, isc_dyn_begin);
2003-10-05 08:33:56 +02:00
delete_procedure(request, node, true); // silent.
2003-10-01 20:11:23 +02:00
define_procedure(request, node->nod_type);
2003-11-08 00:27:24 +01:00
stuff(request, isc_dyn_end);
2002-06-29 08:56:51 +02:00
break;
2001-05-23 15:26:42 +02:00
case nod_def_constraint:
define_constraint_trigger(request, node);
break;
case nod_def_trigger:
case nod_mod_trigger:
case nod_replace_trigger:
2001-05-23 15:26:42 +02:00
define_trigger(request, node);
break;
case nod_mod_relation:
modify_relation(request);
break;
case nod_del_domain:
2003-11-10 10:16:38 +01:00
string = (dsql_str*) node->nod_arg[0];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_delete_global_fld, string->str_data);
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_del_index:
2003-11-10 10:16:38 +01:00
string = (dsql_str*) node->nod_arg[0];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_delete_idx, string->str_data);
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
break;
// CVC: Handling drop table and drop view properly.
2002-06-29 08:56:51 +02:00
case nod_del_relation:
case nod_del_view:
delete_relation_view (request, node, false); // no silent.
2002-06-29 08:56:51 +02:00
break;
2001-05-23 15:26:42 +02:00
case nod_del_procedure:
delete_procedure(request, node, false); // no silent.
2001-05-23 15:26:42 +02:00
break;
case nod_del_trigger:
2003-11-10 10:16:38 +01:00
string = (dsql_str*) node->nod_arg[0];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_delete_trigger, string->str_data);
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_del_role:
2003-11-10 10:16:38 +01:00
string = (dsql_str*) node->nod_arg[0];
request->append_cstring(isc_dyn_del_sql_role, string->str_data);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_grant:
case nod_revoke:
grant_revoke(request);
break;
case nod_def_generator:
define_generator(request);
break;
case nod_def_role:
define_role(request);
break;
case nod_def_filter:
define_filter(request);
break;
case nod_del_generator:
2003-11-10 10:16:38 +01:00
string = (dsql_str*) node->nod_arg[0];
request->append_cstring(isc_dyn_delete_generator, string->str_data);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_del_filter:
2003-11-10 10:16:38 +01:00
string = (dsql_str*) node->nod_arg[0];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_delete_filter, string->str_data);
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_def_udf:
define_udf(request);
break;
case nod_del_udf:
2003-11-10 10:16:38 +01:00
string = (dsql_str*) node->nod_arg[0];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_delete_function, string->str_data);
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_def_shadow:
define_shadow(request);
break;
case nod_del_shadow:
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_delete_shadow,
(SSHORT)(IPTR) (node->nod_arg[0]));
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_mod_database:
modify_database(request);
break;
case nod_def_database:
define_database(request);
break;
case nod_mod_index:
modify_index(request);
break;
case nod_set_statistics:
set_statistics(request);
break;
default:
break;
}
}
static void grant_revoke( dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g r a n t _ r e v o k e
*
**************************************
*
* Functional description
* Build DYN string for GRANT/REVOKE statements
*
**************************************/
dsql_nod** uptr;
dsql_nod** uend;
2001-05-23 15:26:42 +02:00
2003-10-16 10:51:06 +02:00
SSHORT option = 0; // no grant/admin option
dsql_nod* ddl_node = request->req_ddl_node;
dsql_nod* privs = ddl_node->nod_arg[e_grant_privs];
2001-05-23 15:26:42 +02:00
2003-10-16 10:51:06 +02:00
bool process_grant_role = false;
2001-05-23 15:26:42 +02:00
if (privs->nod_arg[0] != NULL) {
2001-12-24 03:51:06 +01:00
if (privs->nod_arg[0]->nod_type == nod_role_name) {
process_grant_role = true;
}
2001-05-23 15:26:42 +02:00
}
if (!process_grant_role)
{
dsql_nod* table = ddl_node->nod_arg[e_grant_table];
dsql_nod* users = ddl_node->nod_arg[e_grant_users];
2001-05-23 15:26:42 +02:00
if (ddl_node->nod_arg[e_grant_grant]) {
2003-10-16 10:51:06 +02:00
option = 1; // with grant option
2001-05-23 15:26:42 +02:00
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_begin);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
uend = users->nod_arg + users->nod_count;
for (uptr = users->nod_arg; uptr < uend; ++uptr)
2001-05-23 15:26:42 +02:00
{
modify_privileges( request,
ddl_node->nod_type,
option,
privs,
table,
*uptr);
}
}
else
{
dsql_nod* role_list = ddl_node->nod_arg[0];
dsql_nod* users = ddl_node->nod_arg[1];
2001-12-24 03:51:06 +01:00
if (ddl_node->nod_arg[3]) {
2003-10-16 10:51:06 +02:00
option = 2; // with admin option
2001-12-24 03:51:06 +01:00
}
request->append_uchar(isc_dyn_begin);
dsql_nod** role_end = role_list->nod_arg + role_list->nod_count;
for (dsql_nod** role_ptr = role_list->nod_arg; role_ptr < role_end; ++role_ptr)
2001-12-24 03:51:06 +01:00
{
uend = users->nod_arg + users->nod_count;
for (uptr = users->nod_arg; uptr < uend; ++uptr)
{
process_role_nm_list( request,
option,
*uptr,
*role_ptr,
ddl_node->nod_type);
2001-05-23 15:26:42 +02:00
}
}
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void make_index( dsql_req* request,
const dsql_nod* element,
const dsql_nod* columns,
const dsql_nod* referenced_columns, // unused
const char* relation_name,
const char* index_name)
2001-05-23 15:26:42 +02:00
{
2004-02-02 12:02:12 +01:00
/**************************************
2001-05-23 15:26:42 +02:00
*
* m a k e _ i n d e x
*
**************************************
*
* Function
* Generate ddl to create an index for a unique
* or primary key constraint.
2001-05-23 15:26:42 +02:00
* This is not called for a foreign key constraint.
* The func. make_index_trf_ref_int handles foreign key constraint
*
**************************************/
/* stuff either user-defined name or
zero-length name, indicating that an index name
should be generated */
2001-05-23 15:26:42 +02:00
2003-11-04 00:59:24 +01:00
fb_assert(element->nod_type != nod_foreign);
2001-05-23 15:26:42 +02:00
const dsql_nod* index = element->nod_arg[e_pri_index];
2003-11-04 00:59:24 +01:00
fb_assert(index);
2003-11-10 10:16:38 +01:00
const dsql_str* string = (dsql_str*) index->nod_arg[e_idx_name];
2003-01-17 13:40:01 +01:00
if (string)
{
index_name = string->str_data;
2003-01-17 13:40:01 +01:00
}
if (element->nod_type == nod_primary)
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_primary_key, index_name);
}
else if (element->nod_type == nod_unique)
{
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_unique, index_name);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_idx_unique, 1);
2001-05-23 15:26:42 +02:00
if (index->nod_arg[e_idx_asc_dsc])
{
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_idx_type, 1);
}
const dsql_nod* const* ptr = columns->nod_arg;
for (const dsql_nod* const* const end = ptr + columns->nod_count;
ptr < end; ++ptr)
2001-12-24 03:51:06 +01:00
{
2003-11-10 10:16:38 +01:00
const dsql_str* field_name = (dsql_str*) (*ptr)->nod_arg[1];
request->append_cstring(isc_dyn_fld_name, field_name->str_data);
2001-05-23 15:26:42 +02:00
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void make_index_trg_ref_int( dsql_req* request,
dsql_nod* element,
dsql_nod* columns,
dsql_nod* referenced_columns,
const char* relation_name,
const char* index_name)
2001-05-23 15:26:42 +02:00
{
/******************************************************
*
* m a k e _ i n d e x _ t r g _ r e f _ i n t
*
******************************************************
*
* Function
* This is called only when the element->nod_type == nod_foreign_key
*
2001-05-23 15:26:42 +02:00
* o Generate ddl to create an index for a unique
* or primary key constraint.
* o Also make an index for the foreign key constraint
* o in the caase of foreign key, also generate an appropriate trigger for
* cascading referential integrity.
*
*
*****************************************************/
2001-12-24 03:51:06 +01:00
2003-11-04 00:59:24 +01:00
fb_assert(element->nod_type == nod_foreign)
2001-05-23 15:26:42 +02:00
/* for_rel_name_str is the name of the relation
on which the ddl operation is being done,
in this case the foreign key table */
dsql_nod* ddl_node = request->req_ddl_node;
dsql_nod* for_rel_node = ddl_node->nod_arg[e_drl_name];
2003-11-10 10:16:38 +01:00
const dsql_str* for_rel_name_str = (dsql_str*) for_rel_node->nod_arg[e_rln_name];
2001-05-23 15:26:42 +02:00
/* stuff either user-defined name or
zero-length name, indicating that an index name
should be generated */
2001-05-23 15:26:42 +02:00
dsql_nod* index = element->nod_arg[e_for_index];
2003-11-04 00:59:24 +01:00
fb_assert(index);
2001-05-23 15:26:42 +02:00
2003-11-10 10:16:38 +01:00
const dsql_str* string = (dsql_str*) index->nod_arg[e_idx_name];
2003-01-17 13:40:01 +01:00
if (string)
{
index_name = string->str_data;
2003-01-17 13:40:01 +01:00
}
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_foreign_key, index_name);
2001-05-23 15:26:42 +02:00
if (index->nod_arg[e_idx_asc_dsc])
{
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_idx_type, 1);
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (element->nod_arg[e_for_action])
{
dsql_nod* nod_for_action = element->nod_arg[e_for_action];
2003-11-04 00:59:24 +01:00
fb_assert(nod_for_action->nod_type == nod_ref_upd_del);
2001-05-23 15:26:42 +02:00
dsql_nod* nod_ref_upd_action = nod_for_action->nod_arg[e_ref_upd];
2001-12-24 03:51:06 +01:00
if (nod_ref_upd_action)
{
2003-11-04 00:59:24 +01:00
fb_assert(nod_ref_upd_action->nod_type == nod_ref_trig_action);
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_foreign_key_update);
2001-12-24 03:51:06 +01:00
switch (nod_ref_upd_action->nod_flags)
{
2001-05-23 15:26:42 +02:00
case REF_ACTION_CASCADE:
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_foreign_key_cascade);
2001-05-23 15:26:42 +02:00
define_upd_cascade_trg(request, element, columns,
referenced_columns, relation_name,
for_rel_name_str->str_data);
2001-05-23 15:26:42 +02:00
break;
case REF_ACTION_SET_DEFAULT:
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_foreign_key_default);
2001-05-23 15:26:42 +02:00
define_set_default_trg(request, element, columns,
referenced_columns, relation_name,
for_rel_name_str->str_data,
2001-12-24 03:51:06 +01:00
true);
2001-05-23 15:26:42 +02:00
break;
case REF_ACTION_SET_NULL:
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_foreign_key_null);
2001-05-23 15:26:42 +02:00
define_set_null_trg(request, element, columns,
referenced_columns, relation_name,
for_rel_name_str->str_data,
2001-12-24 03:51:06 +01:00
true);
2001-05-23 15:26:42 +02:00
break;
case REF_ACTION_NONE:
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_foreign_key_none);
2001-05-23 15:26:42 +02:00
break;
default:
2003-11-04 00:59:24 +01:00
fb_assert(0);
request->append_uchar(isc_dyn_foreign_key_none); // just in case
2001-05-23 15:26:42 +02:00
break;
}
}
dsql_nod* nod_ref_del_action = nod_for_action->nod_arg[e_ref_del];
2001-12-24 03:51:06 +01:00
if (nod_ref_del_action)
{
2003-11-04 00:59:24 +01:00
fb_assert(nod_ref_del_action->nod_type == nod_ref_trig_action);
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_foreign_key_delete);
2001-05-23 15:26:42 +02:00
switch (nod_ref_del_action->nod_flags) {
case REF_ACTION_CASCADE:
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_foreign_key_cascade);
2001-05-23 15:26:42 +02:00
define_del_cascade_trg(request, element, columns,
referenced_columns, relation_name,
for_rel_name_str->str_data);
2001-05-23 15:26:42 +02:00
break;
case REF_ACTION_SET_DEFAULT:
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_foreign_key_default);
2001-05-23 15:26:42 +02:00
define_set_default_trg(request, element, columns,
referenced_columns, relation_name,
for_rel_name_str->str_data,
2001-12-24 03:51:06 +01:00
false);
2001-05-23 15:26:42 +02:00
break;
case REF_ACTION_SET_NULL:
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_foreign_key_null);
2001-05-23 15:26:42 +02:00
define_set_null_trg(request, element, columns,
referenced_columns, relation_name,
for_rel_name_str->str_data,
2001-12-24 03:51:06 +01:00
false);
2001-05-23 15:26:42 +02:00
break;
case REF_ACTION_NONE:
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_foreign_key_none);
2001-05-23 15:26:42 +02:00
break;
default:
2003-11-04 00:59:24 +01:00
fb_assert(0);
request->append_uchar(isc_dyn_foreign_key_none); // just in case
2001-05-23 15:26:42 +02:00
break;
// Error
2001-05-23 15:26:42 +02:00
}
}
}
const dsql_nod* const* ptr = columns->nod_arg;
for (const dsql_nod* const* const end = ptr + columns->nod_count;
ptr < end; ++ptr)
2001-12-24 03:51:06 +01:00
{
2003-11-10 10:16:38 +01:00
const dsql_str* field_name = (dsql_str*) (*ptr)->nod_arg[1];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_fld_name,
field_name->str_data);
2001-05-23 15:26:42 +02:00
}
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_idx_foreign_key, relation_name);
2001-05-23 15:26:42 +02:00
if (referenced_columns)
2001-12-24 03:51:06 +01:00
{
ptr = referenced_columns->nod_arg;
for (const dsql_nod* const* const end = ptr + referenced_columns->nod_count;
ptr < end; ++ptr)
2001-12-24 03:51:06 +01:00
{
2003-11-10 10:16:38 +01:00
const dsql_str* field_name = (dsql_str*) (*ptr)->nod_arg[1];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_idx_ref_column,
field_name->str_data);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void modify_database( dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* m o d i f y _ d a t a b a s e
*
**************************************
*
* Function
* Modify a database.
2001-05-23 15:26:42 +02:00
*
**************************************/
const dsql_nod* ddl_node = request->req_ddl_node;
request->append_uchar(isc_dyn_mod_database);
// request->append_number(isc_dyn_rel_sql_protection, 1);
// bool drop_log = false;
// bool drop_cache = false;
bool drop_difference = false;
2001-05-23 15:26:42 +02:00
const dsql_nod* elements = ddl_node->nod_arg[e_adb_all];
const dsql_nod* const* end = elements->nod_arg + elements->nod_count;
const dsql_nod* const* ptr;
2003-10-16 10:51:06 +02:00
2001-12-24 03:51:06 +01:00
for (ptr = elements->nod_arg; ptr < end; ptr++)
{
const dsql_nod* element = *ptr;
2001-05-23 15:26:42 +02:00
switch (element->nod_type) {
/*
2001-05-23 15:26:42 +02:00
case nod_drop_log:
drop_log = true;
2001-05-23 15:26:42 +02:00
break;
case nod_drop_cache:
drop_cache = true;
2001-05-23 15:26:42 +02:00
break;
*/
case nod_drop_difference:
drop_difference = true;
break;
2001-05-23 15:26:42 +02:00
default:
break;
}
}
/*
2001-12-24 03:51:06 +01:00
if (drop_log) {
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_drop_log);
2001-12-24 03:51:06 +01:00
}
if (drop_cache) {
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_drop_cache);
2001-12-24 03:51:06 +01:00
}
*/
if (drop_difference) {
request->append_uchar(isc_dyn_drop_difference);
}
2001-05-23 15:26:42 +02:00
SLONG start = 0;
//SSHORT number = 0;
//SLONG temp_long;
//SSHORT temp_short;
2001-05-23 15:26:42 +02:00
elements = ddl_node->nod_arg[e_adb_all];
2001-12-24 03:51:06 +01:00
end = elements->nod_arg + elements->nod_count;
for (ptr = elements->nod_arg; ptr < end; ptr++)
{
const dsql_fil* file;
const dsql_nod* element = *ptr;
2001-05-23 15:26:42 +02:00
switch (element->nod_type) {
case nod_file_desc:
2003-11-10 10:16:38 +01:00
file = (dsql_fil*) element->nod_arg[0];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_file,
file->fil_name->str_data);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
start = MAX(start, file->fil_start);
request->append_file_start(start);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_file_length(file->fil_length);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
start += file->fil_length;
break;
/*
2001-05-23 15:26:42 +02:00
case nod_log_file_desc:
2003-11-10 10:16:38 +01:00
file = (dsql_fil*) element->nod_arg[0];
2001-05-23 15:26:42 +02:00
if (file->fil_flags & LOG_default) {
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_def_default_log);
2001-05-23 15:26:42 +02:00
break;
}
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_log_file,
file->fil_name->str_data);
2001-12-24 03:51:06 +01:00
request->append_file_length(file->fil_length);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_file_sequence);
2001-12-24 03:51:06 +01:00
request->append_ushort_with_length(number);
2001-05-23 15:26:42 +02:00
number++;
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_file_partitions);
2001-12-24 03:51:06 +01:00
request->append_ushort_with_length(file->fil_partitions);
if (file->fil_flags & LOG_serial) {
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_file_serial);
2001-12-24 03:51:06 +01:00
}
if (file->fil_flags & LOG_overflow) {
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_file_overflow);
2001-12-24 03:51:06 +01:00
}
if (file->fil_flags & LOG_raw) {
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_file_raw);
2001-12-24 03:51:06 +01:00
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_cache_file_desc:
2003-11-10 10:16:38 +01:00
file = (dsql_fil*) element->nod_arg[0];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_def_cache_file,
file->fil_name->str_data);
2001-12-24 03:51:06 +01:00
request->append_file_length(file->fil_length);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_group_commit_wait:
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_group_commit_wait);
temp_long = (IPTR) (element->nod_arg[0]);
2001-12-24 03:51:06 +01:00
request->append_ulong_with_length(temp_long);
2001-05-23 15:26:42 +02:00
break;
case nod_check_point_len:
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_check_point_length);
temp_long = (IPTR) (element->nod_arg[0]);
2001-12-24 03:51:06 +01:00
request->append_ulong_with_length(temp_long);
2001-05-23 15:26:42 +02:00
break;
case nod_num_log_buffers:
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_num_of_buffers);
temp_short = (SSHORT)(IPTR) (element->nod_arg[0]);
2001-12-24 03:51:06 +01:00
request->append_ushort_with_length(temp_short);
2001-05-23 15:26:42 +02:00
break;
case nod_log_buffer_size:
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_log_buffer_size);
temp_short = (SSHORT)(IPTR) (element->nod_arg[0]);
2001-12-24 03:51:06 +01:00
request->append_ushort_with_length(temp_short);
2001-05-23 15:26:42 +02:00
break;
*/
case nod_difference_file:
request->append_cstring(isc_dyn_def_difference,
2003-11-10 10:16:38 +01:00
((dsql_str*)element->nod_arg[0])->str_data);
break;
case nod_begin_backup:
request->append_uchar(isc_dyn_begin_backup);
break;
case nod_end_backup:
request->append_uchar(isc_dyn_end_backup);
break;
// case nod_drop_log:
// case nod_drop_cache:
// break;
2001-05-23 15:26:42 +02:00
default:
break;
}
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void modify_domain( dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* m o d i f y _ d o m a i n
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Function
* Alter an SQL domain.
*
**************************************/
2003-11-10 10:16:38 +01:00
const dsql_str* string;
dsql_fld* field;
dsql_fld local_field;
2003-09-12 03:41:03 +02:00
/* CVC: This array used with check_one_call to ensure each modification
option is called only once. Enlarge it if the switch() below gets more
cases. */
USHORT repetition_count[6];
2001-05-23 15:26:42 +02:00
dsql_nod* ddl_node = request->req_ddl_node;
2001-05-23 15:26:42 +02:00
dsql_nod* domain_node = ddl_node->nod_arg[e_alt_dom_name];
2003-11-10 10:16:38 +01:00
const dsql_str* domain_name = (dsql_str*) domain_node->nod_arg[e_fln_name];
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_mod_global_fld,
domain_name->str_data);
2001-05-23 15:26:42 +02:00
2002-06-29 08:56:51 +02:00
2003-09-12 03:41:03 +02:00
/* Is MOVE_CLEAR enough for all platforms?
MOVE_CLEAR (repetition_count, sizeof (repetition_count)); */
2003-10-16 10:51:06 +02:00
const USHORT rtop = FB_NELEM(repetition_count);
USHORT* p = repetition_count;
2003-09-12 03:41:03 +02:00
while (p < repetition_count + rtop) {
*p++ = 0;
}
2002-06-29 08:56:51 +02:00
dsql_nod* ops = ddl_node->nod_arg[e_alt_dom_ops];
dsql_nod** ptr = ops->nod_arg;
for (const dsql_nod* const* const end = ptr + ops->nod_count;
ptr < end; ptr++)
2001-05-23 15:26:42 +02:00
{
dsql_nod* element = *ptr;
2001-05-23 15:26:42 +02:00
switch (element->nod_type)
{
case nod_def_default:
2003-09-12 03:41:03 +02:00
check_one_call (repetition_count, 0, "DOMAIN DEFAULT");
2001-05-23 15:26:42 +02:00
/* CVC: So do you want to crash me with ALTER DOMAIN dom SET; ??? */
2002-06-29 08:56:51 +02:00
if (!element->nod_arg[e_dft_default])
2003-09-12 03:41:03 +02:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -104,
isc_arg_gds, isc_command_end_err, // Unexpected end of command
2001-12-24 03:51:06 +01:00
0);
2001-05-23 15:26:42 +02:00
}
// CVC End modification.
2001-05-23 15:26:42 +02:00
element->nod_arg[e_dft_default] =
2003-09-02 01:22:22 +02:00
PASS1_node(request, element->nod_arg[e_dft_default], false);
2001-12-24 03:51:06 +01:00
2003-11-08 00:27:24 +01:00
request->begin_blr(isc_dyn_fld_default_value);
2001-05-23 15:26:42 +02:00
GEN_expr(request, element->nod_arg[e_dft_default]);
2001-12-24 03:51:06 +01:00
request->end_blr();
2003-11-10 10:16:38 +01:00
string = (dsql_str*) element->nod_arg[e_dft_default_source];
2001-12-24 03:51:06 +01:00
if (string)
{
2003-11-04 00:59:24 +01:00
fb_assert(string->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_fld_default_source,
string->str_data,
2001-12-24 03:51:06 +01:00
(USHORT) string->str_length);
2001-05-23 15:26:42 +02:00
}
break;
case nod_def_constraint:
2003-09-12 03:41:03 +02:00
check_one_call (repetition_count, 1, "DOMAIN CONSTRAINT");
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_single_validation);
request->begin_blr(isc_dyn_fld_validation_blr);
2001-05-23 15:26:42 +02:00
/* Get the attributes of the domain, and set any occurances of
nod_dom_value (corresponding to the keyword VALUE) to the
correct type, length, scale, etc. */
2001-12-24 03:51:06 +01:00
if (!METD_get_domain(request, &local_field, domain_name->str_data))
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_dsql_domain_not_found,
isc_arg_string, domain_name->str_data,
// Specified domain or source field does not exist
2001-05-23 15:26:42 +02:00
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
if (element->nod_arg[e_cnstr_condition])
2001-12-24 03:51:06 +01:00
{
2001-05-23 15:26:42 +02:00
set_nod_value_attributes(element->nod_arg[e_cnstr_condition],
&local_field);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
/* Increment the context level for this request, so that
the context number for any RSE generated for a SELECT
within the CHECK clause will be greater than 0. In the
environment of a domain check constraint, context
number 0 is reserved for the "blr_fid, 0, 0, 0," which
2001-05-23 15:26:42 +02:00
is emitted for a nod_dom_value, corresponding to an
occurance of the VALUE keyword in the body of the check
constraint. -- chrisj 1999-08-20 */
request->req_context_number++;
GEN_expr(request,
PASS1_node(request, element->nod_arg[e_cnstr_condition],
2003-09-02 01:22:22 +02:00
false));
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->end_blr();
2003-11-10 10:16:38 +01:00
if ((string = (dsql_str*) element->nod_arg[e_cnstr_source]) != NULL) {
2003-11-04 00:59:24 +01:00
fb_assert(string->str_length <= MAX_USHORT);
2003-11-08 00:27:24 +01:00
request->append_string( isc_dyn_fld_validation_source,
string->str_data,
string->str_length);
2001-05-23 15:26:42 +02:00
}
break;
case nod_mod_domain_type:
field = (dsql_fld*) element->nod_arg[e_mod_dom_new_dom_type];
2001-05-23 15:26:42 +02:00
DDL_resolve_intl_type(request, field, NULL);
put_field(request, field, false);
2001-05-23 15:26:42 +02:00
break;
case nod_field_name:
{
2003-09-12 03:41:03 +02:00
check_one_call(repetition_count, 3, "DOMAIN NAME");
2002-06-29 08:56:51 +02:00
2003-11-10 10:16:38 +01:00
const dsql_str* new_dom_name = (dsql_str*) element->nod_arg[e_fln_name];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_fld_name,
new_dom_name->str_data);
2001-05-23 15:26:42 +02:00
break;
}
case nod_delete_rel_constraint:
2003-09-12 03:41:03 +02:00
check_one_call (repetition_count, 4, "DOMAIN DROP CONSTRAINT");
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_del_validation);
2001-05-23 15:26:42 +02:00
break;
case nod_del_default:
2003-09-12 11:19:21 +02:00
check_one_call (repetition_count, 5, "DOMAIN DROP DEFAULT");
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_del_default);
2001-05-23 15:26:42 +02:00
break;
default:
break;
}
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void modify_index( dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* m o d i f y _ i n d e x
*
**************************************
*
* Function
* Alter an index (only active or inactive for now)
*
**************************************/
dsql_nod* ddl_node = request->req_ddl_node;
2001-05-23 15:26:42 +02:00
dsql_nod* index_node = ddl_node->nod_arg[e_alt_index];
2003-11-10 10:16:38 +01:00
const dsql_str* index_name = (dsql_str*) index_node->nod_arg[e_alt_idx_name];
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_mod_idx, index_name->str_data);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (index_node->nod_type == nod_idx_active) {
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_idx_inactive, 0);
}
else if (index_node->nod_type == nod_idx_inactive) {
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_idx_inactive, 1);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void modify_privilege( dsql_req* request,
2001-12-24 03:51:06 +01:00
NOD_TYPE type,
SSHORT option,
2003-10-16 10:51:06 +02:00
const UCHAR* privs,
const dsql_nod* table,
const dsql_nod* user,
2003-11-10 10:16:38 +01:00
const dsql_str* field_name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* m o d i f y _ p r i v i l e g e
*
**************************************
*
* Functional description
* Stuff a single grant/revoke verb and all its options.
*
**************************************/
2001-12-24 03:51:06 +01:00
if (type == nod_grant) {
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_grant);
}
else {
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_revoke);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
// stuff the privileges string
2001-05-23 15:26:42 +02:00
SSHORT priv_count = 0;
2001-12-24 03:51:06 +01:00
request->append_ushort(0);
2001-05-23 15:26:42 +02:00
for (; *privs; privs++) {
priv_count++;
2001-12-24 03:51:06 +01:00
request->append_uchar(*privs);
2001-05-23 15:26:42 +02:00
}
UCHAR* dynsave = request->req_blr_data.end();
for (SSHORT i = priv_count + 2; i; i--) {
2001-05-23 15:26:42 +02:00
--dynsave;
}
2001-05-23 15:26:42 +02:00
*dynsave++ = (UCHAR) priv_count;
*dynsave = (UCHAR) (priv_count >> 8);
2003-11-10 10:16:38 +01:00
const dsql_str* name = (dsql_str*) table->nod_arg[0];
if (table->nod_type == nod_procedure_name) {
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_prc_name, name->str_data);
}
else {
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_rel_name, name->str_data);
}
2003-11-10 10:16:38 +01:00
name = (dsql_str*) user->nod_arg[0];
2003-10-16 10:51:06 +02:00
2001-05-23 15:26:42 +02:00
switch (user->nod_type) {
case nod_user_group: // GRANT priv ON tbl TO GROUP unix_group
request->append_cstring(isc_dyn_grant_user_group, name->str_data);
2001-05-23 15:26:42 +02:00
break;
case nod_user_name:
2002-06-29 08:56:51 +02:00
if (user->nod_count == 2) {
request->append_cstring(isc_dyn_grant_user_explicit, name->str_data);
2002-06-29 08:56:51 +02:00
}
else {
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_grant_user, name->str_data);
2002-06-29 08:56:51 +02:00
}
2001-05-23 15:26:42 +02:00
break;
case nod_proc_obj:
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_grant_proc, name->str_data);
2001-05-23 15:26:42 +02:00
break;
case nod_trig_obj:
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_grant_trig, name->str_data);
2001-05-23 15:26:42 +02:00
break;
case nod_view_obj:
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_grant_view, name->str_data);
2001-05-23 15:26:42 +02:00
break;
2002-06-29 08:56:51 +02:00
case nod_role_name:
request->append_cstring(isc_dyn_grant_role, name->str_data);
2002-06-29 08:56:51 +02:00
break;
2001-05-23 15:26:42 +02:00
default:
2002-06-29 08:56:51 +02:00
/* CVC: Here we should complain: DYN doesn't check parameters
and it will write trash in rdb$user_privileges. We probably
should complain in most cases when "name" is blank, too. */
2001-05-23 15:26:42 +02:00
break;
}
if (field_name) {
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_fld_name, field_name->str_data);
2001-05-23 15:26:42 +02:00
}
if ((option) &&
((type == nod_grant) ||
(!(request->req_dbb->dbb_flags & DBB_v3))))
{
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_grant_options, option);
2001-05-23 15:26:42 +02:00
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static SCHAR modify_privileges(dsql_req* request,
2001-05-23 15:26:42 +02:00
NOD_TYPE type,
SSHORT option,
const dsql_nod* privs,
const dsql_nod* table,
const dsql_nod* user)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* m o d i f y _ p r i v i l e g e s
*
**************************************
*
* Functional description
* Return a SCHAR indicating the privilege to be modified
*
**************************************/
SCHAR privileges[10];
const char* p = 0;
char* q;
const dsql_nod* fields;
const dsql_nod* const* ptr;
const dsql_nod* const* end;
2001-05-23 15:26:42 +02:00
switch (privs->nod_type) {
case nod_all:
p = "A";
break;
case nod_select:
return 'S';
case nod_execute:
return 'X';
case nod_insert:
return 'I';
case nod_references:
case nod_update:
p = (privs->nod_type == nod_references) ? "R" : "U";
fields = privs->nod_arg[0];
if (!fields) {
2001-05-23 15:26:42 +02:00
return *p;
}
2001-05-23 15:26:42 +02:00
for (ptr = fields->nod_arg, end = ptr + fields->nod_count; ptr < end;
ptr++)
{
2001-05-23 15:26:42 +02:00
modify_privilege(request, type, option,
reinterpret_cast<const UCHAR*>(p), table, user,
2003-11-10 10:16:38 +01:00
reinterpret_cast<dsql_str*>((*ptr)->nod_arg[1]));
}
2001-05-23 15:26:42 +02:00
return 0;
case nod_delete:
return 'D';
case nod_list:
p = q = privileges;
2001-05-23 15:26:42 +02:00
for (ptr = privs->nod_arg, end = ptr + privs->nod_count; ptr < end;
ptr++)
{
*q = modify_privileges(request, type, option, *ptr, table,
user);
if (*q) {
q++;
}
}
*q = 0;
2001-05-23 15:26:42 +02:00
break;
default:
break;
}
if (*p) {
modify_privilege( request,
type,
option,
reinterpret_cast<const UCHAR*>(p),
2001-05-23 15:26:42 +02:00
table,
user,
0);
}
return 0;
}
static void modify_relation( dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* m o d i f y _ r e l a t i o n
*
**************************************
*
* Function
* Alter an SQL table, relying on DYN to generate
* global fields for the local fields.
2001-05-23 15:26:42 +02:00
*
**************************************/
tsql* tdsql = DSQL_get_thread_data();
2001-05-23 15:26:42 +02:00
dsql_nod* ddl_node = request->req_ddl_node;
2001-05-23 15:26:42 +02:00
dsql_nod* relation_node = ddl_node->nod_arg[e_alt_name];
2003-11-10 10:16:38 +01:00
const dsql_str* relation_name = (dsql_str*) relation_node->nod_arg[e_rln_name];
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_mod_rel, relation_name->str_data);
2001-05-23 15:26:42 +02:00
save_relation(request, relation_name);
/* need to handle error that occur in generating dyn string.
* If there is an error, get rid of the cached data
*/
2001-12-24 03:51:06 +01:00
try {
2001-05-23 15:26:42 +02:00
dsql_nod* ops = ddl_node->nod_arg[e_alt_ops];
dsql_nod** ptr = ops->nod_arg;
for (const dsql_nod* const* const end = ptr + ops->nod_count; ptr < end; ptr++)
{
const dsql_nod* field_node;
const dsql_str* field_name;
2003-10-16 10:51:06 +02:00
dsql_nod* element = *ptr;
2001-05-23 15:26:42 +02:00
switch (element->nod_type) {
case nod_mod_field_name:
{
const dsql_nod* old_field = element->nod_arg[e_mod_fld_name_orig_name];
2003-11-10 10:16:38 +01:00
const dsql_str* old_field_name = (dsql_str*) old_field->nod_arg[e_fln_name];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_mod_local_fld,
old_field_name->str_data);
2001-05-23 15:26:42 +02:00
dsql_nod* new_field = element->nod_arg[e_mod_fld_name_new_name];
2003-11-10 10:16:38 +01:00
const dsql_str* new_field_name = (dsql_str*) new_field->nod_arg[e_fln_name];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_rel_name,
relation_name->str_data);
2001-12-24 03:51:06 +01:00
request->append_cstring(isc_dyn_new_fld_name,
new_field_name->str_data);
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
break;
}
case nod_mod_field_pos:
{
field_node = element->nod_arg[e_mod_fld_pos_orig_name];
2003-11-10 10:16:38 +01:00
field_name = (dsql_str*) field_node->nod_arg[e_fln_name];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_mod_local_fld, field_name->str_data);
const dsql_nod* const_node = element->nod_arg[e_mod_fld_pos_new_position];
2002-06-29 08:56:51 +02:00
2004-03-07 08:58:55 +01:00
// CVC: Since now the parser accepts pos=1..N, let's subtract one here.
const SSHORT constant = (SSHORT)(IPTR) const_node->nod_arg[0] - 1;
2002-06-29 08:56:51 +02:00
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_rel_name,
relation_name->str_data);
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_position, constant);
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
break;
}
case nod_mod_field_type:
2003-10-16 10:51:06 +02:00
modify_field(request, element, (SSHORT) -1, relation_name);
2001-05-23 15:26:42 +02:00
break;
case nod_def_field:
2003-10-16 10:51:06 +02:00
define_field(request, element, (SSHORT) -1, relation_name);
2001-05-23 15:26:42 +02:00
break;
case nod_del_field:
/* Fix for bug 8054:
[CASCADE | RESTRICT] syntax is available in IB4.5, but not
required until v5.0.
2001-05-23 15:26:42 +02:00
Option CASCADE causes an error :
unsupported DSQL construct
Option RESTRICT is default behaviour.
*/
field_node = element->nod_arg[0];
2003-11-10 10:16:38 +01:00
field_name = (dsql_str*) field_node->nod_arg[e_fln_name];
2001-05-23 15:26:42 +02:00
if ((element->nod_arg[1])->nod_type == nod_cascade)
2001-12-24 03:51:06 +01:00
{
// Unsupported DSQL construct
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -901,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_dsql_construct_err, 0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2003-11-04 00:59:24 +01:00
fb_assert((element->nod_arg[1])->nod_type == nod_restrict);
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_delete_local_fld, field_name->str_data);
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_delete_rel_constraint:
2003-11-10 10:16:38 +01:00
field_name = (dsql_str*) element->nod_arg[0];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_delete_rel_constraint, field_name->str_data);
2001-05-23 15:26:42 +02:00
break;
case nod_rel_constraint:
define_rel_constraint(request, element);
break;
default:
break;
}
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
} // try
2003-02-13 13:01:28 +01:00
catch (const std::exception&)
2001-12-24 03:51:06 +01:00
{
METD_drop_relation(request, relation_name);
request->req_relation = 0;
throw;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
2004-02-02 12:02:12 +01:00
static dsql_par* parameter_reverse_order(dsql_par* parameter, dsql_par* prev)
{
/**************************************
*
* p a r a m e t e r _ r e v e r s e _ o r d e r
*
**************************************
*
* Function
* Reverse parameters order for EXECUTE BLOCK statement
*
**************************************/
2004-02-02 12:02:12 +01:00
dsql_par* result;
if (parameter->par_next)
result = parameter_reverse_order(parameter->par_next, parameter);
else
result = parameter;
parameter->par_next = prev;
return result;
}
static void process_role_nm_list( dsql_req* request,
2001-12-24 03:51:06 +01:00
SSHORT option,
dsql_nod* user_ptr,
dsql_nod* role_ptr,
2001-12-24 03:51:06 +01:00
NOD_TYPE type)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p r o c e s s _ r o l e _ n m _ l i s t
*
**************************************
*
* Functional description
* Build req_blr for grant & revoke role stmt
*
**************************************/
2001-12-24 03:51:06 +01:00
if (type == nod_grant) {
request->append_uchar(isc_dyn_grant);
}
else {
2001-12-24 03:51:06 +01:00
request->append_uchar(isc_dyn_revoke);
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_ushort(1);
request->append_uchar('M');
2001-05-23 15:26:42 +02:00
2003-11-10 10:16:38 +01:00
const dsql_str* role_nm = (dsql_str*) role_ptr->nod_arg[0];
request->append_cstring(isc_dyn_sql_role_name, role_nm->str_data);
2001-05-23 15:26:42 +02:00
2003-11-10 10:16:38 +01:00
const dsql_str* user_nm = (dsql_str*) user_ptr->nod_arg[0];
request->append_cstring(isc_dyn_grant_user, user_nm->str_data);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (option) {
request->append_number(isc_dyn_grant_admin_options, option);
}
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void put_descriptor(dsql_req* request, const dsc* desc)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p u t _ d e s c r i p t o r
*
**************************************
*
* Function
* Write out field description in ddl, given the
* input descriptor.
*
**************************************/
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_type, blr_dtypes[desc->dsc_dtype]);
2001-12-24 03:51:06 +01:00
if (desc->dsc_dtype == dtype_varying) {
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_length,
2001-05-23 15:26:42 +02:00
(SSHORT) (desc->dsc_length - sizeof(USHORT)));
}
else {
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_length, desc->dsc_length);
2001-12-24 03:51:06 +01:00
}
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_scale, desc->dsc_scale);
request->append_number(isc_dyn_fld_sub_type, desc->dsc_sub_type);
2001-05-23 15:26:42 +02:00
}
//
// Write out field data type
// Taking special care to declare international text.
//
static void put_dtype(dsql_req* request, const dsql_fld* field, bool use_subtype)
2001-05-23 15:26:42 +02:00
{
#ifdef DEV_BUILD
// Check if the field describes a known datatype
2001-05-23 15:26:42 +02:00
if (field->fld_dtype > FB_NELEM(blr_dtypes) ||
2001-05-23 15:26:42 +02:00
!blr_dtypes[field->fld_dtype]) {
SCHAR buffer[100];
sprintf(buffer, "Invalid dtype %d in put_dtype", field->fld_dtype);
ERRD_bugcheck(buffer);
}
#endif
if (field->fld_dtype == dtype_cstring ||
2001-12-24 03:51:06 +01:00
field->fld_dtype == dtype_text || field->fld_dtype == dtype_varying)
{
2001-05-23 15:26:42 +02:00
if (!use_subtype || (request->req_dbb->dbb_flags & DBB_v3)) {
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_dtypes[field->fld_dtype]);
2001-05-23 15:26:42 +02:00
}
else if (field->fld_dtype == dtype_varying) {
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_varying2);
request->append_ushort(field->fld_ttype);
2001-05-23 15:26:42 +02:00
}
else if (field->fld_dtype == dtype_cstring) {
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_cstring2);
request->append_ushort(field->fld_ttype);
2001-05-23 15:26:42 +02:00
}
else {
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_text2);
request->append_ushort(field->fld_ttype);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
if (field->fld_dtype == dtype_varying) {
request->append_ushort(field->fld_length - sizeof(USHORT));
}
else {
2001-12-24 03:51:06 +01:00
request->append_ushort(field->fld_length);
}
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
else
{
request->append_uchar(blr_dtypes[field->fld_dtype]);
2001-05-23 15:26:42 +02:00
if (DTYPE_IS_EXACT(field->fld_dtype) ||
2001-12-24 03:51:06 +01:00
(dtype_quad == field->fld_dtype))
{
request->append_uchar(field->fld_scale);
2001-05-23 15:26:42 +02:00
}
}
}
static void put_field( dsql_req* request, dsql_fld* field, bool udf_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p u t _ f i e l d
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Function
* Emit dyn which describes a field data type.
* This field could be a column, a procedure input,
* or a procedure output.
*
**************************************/
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_type, blr_dtypes[field->fld_dtype]);
2001-12-24 03:51:06 +01:00
if (field->fld_dtype == dtype_blob)
{
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_sub_type, field->fld_sub_type);
request->append_number(isc_dyn_fld_scale, 0);
2001-12-24 03:51:06 +01:00
if (!udf_flag)
{
if (!field->fld_seg_length) {
2001-05-23 15:26:42 +02:00
field->fld_seg_length = DEFAULT_BLOB_SEGMENT_SIZE;
2001-12-24 03:51:06 +01:00
}
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_segment_length,
2001-05-23 15:26:42 +02:00
field->fld_seg_length);
}
if (!(request->req_dbb->dbb_flags & DBB_v3))
2001-12-24 03:51:06 +01:00
{
if (field->fld_sub_type == isc_blob_text) {
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_character_set,
2001-05-23 15:26:42 +02:00
field->fld_character_set_id);
2001-12-24 03:51:06 +01:00
}
}
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
else if (field->fld_dtype <= dtype_any_text)
{
if (field->fld_sub_type) {
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_sub_type, field->fld_sub_type);
2001-12-24 03:51:06 +01:00
}
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_scale, 0);
2001-12-24 03:51:06 +01:00
if (field->fld_dtype == dtype_varying)
{
// CVC: Fix the assertion
2003-11-04 00:59:24 +01:00
fb_assert((field->fld_length) <= MAX_SSHORT);
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_length,
2001-05-23 15:26:42 +02:00
(SSHORT) (field->fld_length - sizeof(USHORT)));
}
else
2001-12-24 03:51:06 +01:00
{
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_length, field->fld_length);
2001-12-24 03:51:06 +01:00
}
if (!(request->req_dbb->dbb_flags & DBB_v3))
{
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_char_length,
2001-05-23 15:26:42 +02:00
field->fld_character_length);
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_character_set,
2001-05-23 15:26:42 +02:00
field->fld_character_set_id);
if (!udf_flag)
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_collation,
2001-05-23 15:26:42 +02:00
field->fld_collation_id);
}
}
else {
2003-11-08 00:27:24 +01:00
request->append_number(isc_dyn_fld_scale, field->fld_scale);
request->append_number(isc_dyn_fld_length, field->fld_length);
2001-12-24 03:51:06 +01:00
if (DTYPE_IS_EXACT(field->fld_dtype))
{
request->append_number(isc_dyn_fld_precision, field->fld_precision);
2001-05-23 15:26:42 +02:00
if (field->fld_sub_type)
2001-12-24 03:51:06 +01:00
{
request->append_number(isc_dyn_fld_sub_type,
2001-05-23 15:26:42 +02:00
field->fld_sub_type);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
}
}
2004-02-02 12:02:12 +01:00
static void put_local_variable( dsql_req* request, dsql_var* variable,
dsql_nod* host_param)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p u t _ l o c a l _ v a r i a b l e
*
**************************************
*
* Function
* Write out local variable field data type
*
**************************************/
dsql_fld* field = variable->var_field;
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_dcl_variable);
request->append_ushort(variable->var_variable_number);
2001-05-23 15:26:42 +02:00
DDL_resolve_intl_type(request, field, NULL);
2001-12-24 03:51:06 +01:00
const USHORT dtype = field->fld_dtype;
if (dtype == dtype_blob) {
2001-05-23 15:26:42 +02:00
field->fld_dtype = dtype_quad;
2001-12-24 03:51:06 +01:00
}
put_dtype(request, field, true);
2001-05-23 15:26:42 +02:00
field->fld_dtype = dtype;
// Check for a default value, borrowed from define_domain
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_assignment);
dsql_nod* node = (host_param) ? host_param->nod_arg[e_dfl_default] : 0;
if (node)
{
2003-09-02 01:22:22 +02:00
node = PASS1_node(request, node, false);
GEN_expr(request, node);
}
else
{
// Initialize variable to NULL
request->append_uchar(blr_null);
}
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_variable);
request->append_ushort(variable->var_variable_number);
2001-05-23 15:26:42 +02:00
}
static void put_local_variables(dsql_req* request, dsql_nod* parameters,
2003-10-16 10:51:06 +02:00
SSHORT locals)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p u t _ l o c a l _ v a r i a b l e s
*
**************************************
*
* Function
* Emit dyn for the local variables declared
* in a procedure or trigger.
*
**************************************/
2001-12-24 03:51:06 +01:00
if (parameters)
{
dsql_nod** ptr = parameters->nod_arg;
for (const dsql_nod* const* const end = ptr + parameters->nod_count;
ptr < end; ptr++)
2001-12-24 03:51:06 +01:00
{
dsql_nod* parameter = *ptr;
if (parameter->nod_type == nod_def_field)
2001-12-24 03:51:06 +01:00
{
dsql_fld* field = (dsql_fld*) parameter->nod_arg[e_dfl_field];
dsql_nod** rest = ptr;
while ((++rest) != end)
2001-12-24 03:51:06 +01:00
{
if ((*rest)->nod_type == nod_def_field)
{
dsql_fld* rest_field = (dsql_fld*) (*rest)->nod_arg[e_dfl_field];
if (!strcmp(field->fld_name, rest_field->fld_name))
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -637,
isc_arg_gds, isc_dsql_duplicate_spec,
isc_arg_string, field->fld_name, 0);
}
2001-12-24 03:51:06 +01:00
}
dsql_nod* var_node =
MAKE_variable(field, field->fld_name, VAR_output, 0, 0,
locals);
*ptr = var_node;
2004-02-02 12:02:12 +01:00
dsql_var* variable = (dsql_var*) var_node->nod_arg[e_var_variable];
put_local_variable(request, variable, parameter);
// fld_length is calculated inside put_local_variable(),
// so we copy here the length
var_node->nod_desc.dsc_length = field->fld_length;
locals++;
}
else if (parameter->nod_type == nod_cursor)
{
PASS1_statement(request, parameter, true);
GEN_statement(request, parameter);
}
2001-05-23 15:26:42 +02:00
}
}
}
static void put_msg_field( dsql_req* request, dsql_fld* field)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p u t _ m s g _ f i e l d
*
**************************************
*
* Function
* Write out message field data type
*
**************************************/
2001-12-24 03:51:06 +01:00
const USHORT dtype = field->fld_dtype;
if (dtype == dtype_blob) {
2001-05-23 15:26:42 +02:00
field->fld_dtype = dtype_quad;
2001-12-24 03:51:06 +01:00
}
put_dtype(request, field, true);
2001-05-23 15:26:42 +02:00
field->fld_dtype = dtype;
2001-12-24 03:51:06 +01:00
// add slot for null flag (parameter2)
request->append_uchar(blr_short);
request->append_uchar(0);
2001-05-23 15:26:42 +02:00
}
static dsql_nod* replace_field_names(dsql_nod* input,
dsql_nod* search_fields,
dsql_nod* replace_fields,
bool null_them)
2001-05-23 15:26:42 +02:00
{
2004-02-02 12:02:12 +01:00
/**************************************
2001-05-23 15:26:42 +02:00
*
* r e p l a c e _ f i e l d _ n a m e s
*
**************************************
*
* Function
* Given an input node tree, find any field name nodes
* and replace them according to the mapping provided.
* Used to create view WITH CHECK OPTION.
*
**************************************/
2001-12-24 03:51:06 +01:00
if (!input || MemoryPool::blk_type(input) != dsql_type_nod) {
2001-05-23 15:26:42 +02:00
return input;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
const dsql_nod* const* const endo = input->nod_arg + input->nod_count;
2001-05-23 15:26:42 +02:00
for (dsql_nod** ptr = input->nod_arg; ptr < endo; ++ptr)
2001-12-24 03:51:06 +01:00
{
2001-05-23 15:26:42 +02:00
if ((*ptr)->nod_type == nod_select_expr)
2001-12-24 03:51:06 +01:00
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_subquery_err,
// No subqueries permitted for VIEW WITH CHECK OPTION
2001-05-23 15:26:42 +02:00
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if ((*ptr)->nod_type == nod_field_name)
{
// found a field node, check if it needs to be replaced
2001-05-23 15:26:42 +02:00
2003-11-10 10:16:38 +01:00
const dsql_str* field_name = (dsql_str*) (*ptr)->nod_arg[e_fln_name];
dsql_nod** search = search_fields->nod_arg;
const dsql_nod* const* const end = search + search_fields->nod_count;
dsql_nod** replace = NULL;
2001-12-24 03:51:06 +01:00
if (replace_fields) {
2001-05-23 15:26:42 +02:00
replace = replace_fields->nod_arg;
2001-12-24 03:51:06 +01:00
}
bool found = false;
for (; search < end; search++, (replace_fields) ? replace++ : NULL)
{
const dsql_str* replace_name = 0;
2001-05-23 15:26:42 +02:00
if (replace_fields) {
2003-11-10 10:16:38 +01:00
replace_name = (dsql_str*) (*replace)->nod_arg[e_fln_name];
2001-05-23 15:26:42 +02:00
}
dsql_nod* field_node = *search;
dsql_fld* field = (dsql_fld*) field_node->nod_arg[e_fld_field];
2001-12-24 03:51:06 +01:00
TEXT* search_name = field->fld_name;
if (!strcmp((SCHAR *) field_name->str_data,
(SCHAR *) search_name))
{
found = true;
if (replace_fields) {
2001-05-23 15:26:42 +02:00
(*ptr)->nod_arg[e_fln_name] = (*replace)->nod_arg[e_fln_name];
2001-12-24 03:51:06 +01:00
}
(*ptr)->nod_arg[e_fln_context] = (dsql_nod*) MAKE_cstring(NEW_CONTEXT);
2001-05-23 15:26:42 +02:00
}
if (null_them &&
replace_fields &&
!strcmp((SCHAR *) field_name->str_data,
2001-12-24 03:51:06 +01:00
(SCHAR *) replace_name->str_data))
{
found = true;
}
2001-05-23 15:26:42 +02:00
}
if (null_them && !found) {
(*ptr) = MAKE_node(nod_null, (int) 0);
}
}
else
2001-12-24 03:51:06 +01:00
{
// recursively go through the input tree
// looking for field name nodes
2001-05-23 15:26:42 +02:00
replace_field_names(*ptr, search_fields, replace_fields,
null_them);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
return input;
}
static void reset_context_stack( dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* r e s e t _ c o n t e x t _ s t a c k
*
**************************************
*
* Function
* Get rid of any predefined contexts created
2001-05-23 15:26:42 +02:00
* for a view or trigger definition.
*
**************************************/
request->req_context->clear();
2001-05-23 15:26:42 +02:00
request->req_context_number = 0;
}
static void save_field(dsql_req* request, const TEXT* field_name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s a v e _ f i e l d
*
**************************************
*
* Function
* Save the name of a field in the relation or view currently
* being defined. This is done to support definition
* of triggers which will depend on the metadata created
2001-05-23 15:26:42 +02:00
* in this request.
*
**************************************/
tsql* tdsql = DSQL_get_thread_data();
2001-05-23 15:26:42 +02:00
dsql_rel* relation = request->req_relation;
2001-12-24 03:51:06 +01:00
if (!relation) {
2001-05-23 15:26:42 +02:00
return;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
dsql_fld* field = FB_NEW_RPT(*tdsql->getDefaultPool(), strlen(field_name) + 1) dsql_fld;
2001-05-23 15:26:42 +02:00
strcpy(field->fld_name, field_name);
field->fld_next = relation->rel_fields;
relation->rel_fields = field;
}
2003-11-10 10:16:38 +01:00
static void save_relation( dsql_req* request, const dsql_str* relation_name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s a v e _ r e l a t i o n
*
**************************************
*
* Function
* Save the name of the relation or view currently
* being defined. This is done to support definition
* of triggers which will depend on the metadata created
2001-05-23 15:26:42 +02:00
* in this request.
*
**************************************/
tsql* tdsql = DSQL_get_thread_data();
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (request->req_flags & REQ_save_metadata) {
2001-05-23 15:26:42 +02:00
return;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
request->req_flags |= REQ_save_metadata;
2001-12-24 03:51:06 +01:00
dsql_nod* ddl_node = request->req_ddl_node;
dsql_rel* relation;
2001-05-23 15:26:42 +02:00
if (ddl_node->nod_type == nod_mod_relation)
{
relation = METD_get_relation(request, relation_name);
}
else
{
relation = FB_NEW_RPT(*tdsql->getDefaultPool(), relation_name->str_length) dsql_rel;
2001-05-23 15:26:42 +02:00
relation->rel_name = relation->rel_data;
relation->rel_owner =
relation->rel_data + relation_name->str_length + 1;
strcpy(relation->rel_name, (SCHAR *) relation_name->str_data);
*relation->rel_owner = 0;
}
request->req_relation = relation;
}
static void set_statistics( dsql_req* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s e t _ s t a t i s t i c s
*
**************************************
*
* Function
* Alter an index/.. statistics
*
**************************************/
dsql_nod* ddl_node = request->req_ddl_node;
2003-11-10 10:16:38 +01:00
const dsql_str* index_name = (dsql_str*) ddl_node->nod_arg[e_stat_name];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_mod_idx, index_name->str_data);
request->append_uchar(isc_dyn_idx_statistic);
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void stuff_default_blr( dsql_req* request,
2003-10-16 10:51:06 +02:00
const TEXT* default_buff,
2001-12-24 03:51:06 +01:00
USHORT buff_size)
2001-05-23 15:26:42 +02:00
{
/********************************************
*
* s t u f f _ d e f a u l t _ b l r
*
********************************************
* Function:
* The default_blr is passed in default_buffer. It is of the form:
* blr_version4 blr_literal ..... blr_eoc.
* strip the blr_version4 and blr_eoc verbs and stuff the remaining
* blr in the blr stream in the request.
*
*********************************************/
2003-11-04 00:59:24 +01:00
fb_assert((*default_buff == blr_version4) || (*default_buff == blr_version5));
2001-05-23 15:26:42 +02:00
2004-02-13 12:15:49 +01:00
USHORT i;
for (i = 1; i < buff_size - 1; ++i)
2003-10-16 10:51:06 +02:00
{
2001-12-24 03:51:06 +01:00
request->append_uchar(default_buff[i]);
}
2001-05-23 15:26:42 +02:00
2003-11-04 00:59:24 +01:00
fb_assert(default_buff[i] == blr_eoc);
2001-05-23 15:26:42 +02:00
}
static void stuff_matching_blr(dsql_req* request, const dsql_nod* for_columns,
const dsql_nod* prim_columns)
2001-05-23 15:26:42 +02:00
{
/********************************************
*
* s t u f f _ m a t c h i n g _ b l r
*
********************************************
*
* Function
* Generate blr to express: foreign_key == primary_key
* ie., for_key.column_1 = prim_key.column_1 and
* for_key.column_2 = prim_key.column_2 and .... so on..
2001-05-23 15:26:42 +02:00
*
**************************************/
// count of foreign key columns
2003-11-04 00:59:24 +01:00
fb_assert(prim_columns->nod_count == for_columns->nod_count);
fb_assert(prim_columns->nod_count != 0);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_boolean);
if (prim_columns->nod_count > 1) {
request->append_uchar(blr_and);
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
USHORT num_fields = 0;
const dsql_nod* const* for_key_flds = for_columns->nod_arg;
const dsql_nod* const* prim_key_flds = prim_columns->nod_arg;
2001-05-23 15:26:42 +02:00
do {
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_eql);
2003-11-10 10:16:38 +01:00
const dsql_str* for_key_fld_name_str = (dsql_str*) (*for_key_flds)->nod_arg[1];
const dsql_str* prim_key_fld_name_str = (dsql_str*) (*prim_key_flds)->nod_arg[1];
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_field);
request->append_uchar(2);
request->append_cstring(0, for_key_fld_name_str->str_data);
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_field);
request->append_uchar(0);
request->append_cstring(0, prim_key_fld_name_str->str_data);
2001-05-23 15:26:42 +02:00
num_fields++;
2003-04-08 02:31:20 +02:00
if (prim_columns->nod_count - num_fields >= 2) {
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_and);
}
2001-05-23 15:26:42 +02:00
for_key_flds++;
prim_key_flds++;
2001-12-24 03:51:06 +01:00
} while (num_fields < for_columns->nod_count);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_end);
2001-05-23 15:26:42 +02:00
}
static void stuff_trg_firing_cond(dsql_req* request,
const dsql_nod* prim_columns)
2001-05-23 15:26:42 +02:00
{
/********************************************
*
* s t u f f _ t r g _ f i r i n g _ c o n d
*
********************************************
*
* Function
* Generate blr to express: if (old.primary_key != new.primary_key).
* do a column by column comparison.
*
**************************************/
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_if);
if (prim_columns->nod_count > 1) {
request->append_uchar(blr_or);
}
USHORT num_fields = 0;
const dsql_nod* const* prim_key_flds = prim_columns->nod_arg;
2001-12-24 03:51:06 +01:00
2001-05-23 15:26:42 +02:00
do {
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_neq);
2001-05-23 15:26:42 +02:00
2003-11-10 10:16:38 +01:00
const dsql_str* prim_key_fld_name_str = (dsql_str*) (*prim_key_flds)->nod_arg[1];
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_field);
request->append_uchar(0);
request->append_cstring(0, prim_key_fld_name_str->str_data);
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_field);
request->append_uchar(1);
request->append_cstring(0, prim_key_fld_name_str->str_data);
2001-05-23 15:26:42 +02:00
num_fields++;
2003-04-08 02:31:20 +02:00
if (prim_columns->nod_count - num_fields >= 2)
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_or);
2001-05-23 15:26:42 +02:00
prim_key_flds++;
2001-12-24 03:51:06 +01:00
} while (num_fields < prim_columns->nod_count);
2001-05-23 15:26:42 +02:00
}
static void modify_field(dsql_req* request,
dsql_nod* element,
2001-12-24 03:51:06 +01:00
SSHORT position,
2003-11-10 10:16:38 +01:00
const dsql_str* relation_name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* m o d i f y _ f i e l d
*
**************************************
*
* Function
* Modify a field, either as part of an
* alter table or alter domain statement.
*
**************************************/
dsql_fld* field = (dsql_fld*) element->nod_arg[e_dfl_field];
request->append_cstring(isc_dyn_mod_sql_fld, field->fld_name);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// add the field to the relation being defined for parsing purposes
dsql_rel* relation = request->req_relation;
2003-10-16 10:51:06 +02:00
if (relation != NULL)
2001-12-24 03:51:06 +01:00
{
2001-05-23 15:26:42 +02:00
field->fld_next = relation->rel_fields;
relation->rel_fields = field;
}
dsql_nod* domain_node = element->nod_arg[e_mod_fld_type_dom_name];
2003-10-16 10:51:06 +02:00
if (domain_node)
2001-12-24 03:51:06 +01:00
{
dsql_nod* node1 = domain_node->nod_arg[e_dom_name];
2003-11-10 10:16:38 +01:00
const dsql_str* domain_name = (dsql_str*) node1->nod_arg[e_fln_name];
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_fld_source, domain_name->str_data);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// Get the domain information
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (!METD_get_domain(request, field, domain_name->str_data))
{
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -607,
isc_arg_gds, isc_dsql_command_err,
isc_arg_gds, isc_dsql_domain_not_found,
// Specified domain or source field does not exist
isc_arg_string, domain_name->str_data,
2001-05-23 15:26:42 +02:00
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
DDL_resolve_intl_type(request, field, NULL);
}
2001-12-24 03:51:06 +01:00
else
{
if (relation_name) {
2003-11-08 00:27:24 +01:00
request->append_cstring(isc_dyn_rel_name, relation_name->str_data);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
DDL_resolve_intl_type2(request, field, NULL, true);
put_field(request, field, false);
2001-05-23 15:26:42 +02:00
}
2003-11-08 00:27:24 +01:00
request->append_uchar(isc_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void set_nod_value_attributes( dsql_nod* node, const dsql_fld* field)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s e t _ n o d _ v a l u e _ a t t r i b u t e s
*
**************************************
*
* Function
* Examine all the children of the argument node:
* if any is a nod_dom_value, set its dtype, size, and scale
* to those of the field argument
*
**************************************/
2003-10-16 10:51:06 +02:00
for (ULONG child_number = 0; child_number < node->nod_count; ++child_number)
2001-12-24 03:51:06 +01:00
{
dsql_nod* child = node->nod_arg[child_number];
2001-12-24 03:51:06 +01:00
if (child && MemoryPool::blk_type(child) == dsql_type_nod)
{
if (nod_dom_value == child->nod_type)
{
2003-11-04 00:59:24 +01:00
fb_assert(field->fld_dtype <= MAX_UCHAR);
2001-05-23 15:26:42 +02:00
child->nod_desc.dsc_dtype = (UCHAR) field->fld_dtype;
child->nod_desc.dsc_length = field->fld_length;
2003-11-04 00:59:24 +01:00
fb_assert(field->fld_scale <= MAX_SCHAR);
2001-05-23 15:26:42 +02:00
child->nod_desc.dsc_scale = (SCHAR) field->fld_scale;
}
else if ((nod_constant != child->nod_type) &&
2001-12-24 03:51:06 +01:00
(child->nod_count > 0))
{
2001-05-23 15:26:42 +02:00
/* A nod_constant can have nod_arg entries which are not really
pointers to other nodes, but rather integer values, so
it is not safe to scan through its children. Fortunately,
it cannot have a nod_dom_value as a child in any case, so
we lose nothing by skipping it.
*/
set_nod_value_attributes(child, field);
}
} // if it's a node
2004-03-07 08:58:55 +01:00
} // for (child_number ...
2001-05-23 15:26:42 +02:00
return;
}
// BEGIN dsql_req METHODS.
// Write out a string of blr as part of a ddl string,
// as in a view or computed field definition.
//
void dsql_req::begin_blr(UCHAR verb)
{
if (verb) {
append_uchar(verb);
}
req_base_offset = req_blr_data.getCount();
// put in a place marker for the size of the blr, since it is unknown
append_ushort(0);
append_uchar((req_flags & REQ_blr_version4) ? blr_version4 : blr_version5);
}
// Complete the stuffing of a piece of
// blr by going back and inserting the length.
//
void dsql_req::end_blr()
{
append_uchar(blr_eoc);
// go back and stuff in the proper length
UCHAR* blr_base = &req_blr_data[req_base_offset];
const ULONG length = (req_blr_data.getCount() - req_base_offset) - 2;
2004-04-10 02:25:22 +02:00
if (length > 0xFFFF) {
// TODO : need appropriate error message, like "too long BLR"
ERRD_post(isc_invalid_blr, isc_arg_number, (SLONG) length,
0);
2004-04-10 02:25:22 +02:00
}
*blr_base++ = (UCHAR) length;
*blr_base = (UCHAR) (length >> 8);
}
void dsql_req::append_number(UCHAR verb, SSHORT number)
{
/**************************************
*
* Input
* blr_ptr: current position of blr being generated
* verb: blr byte of which number is an argument
* number: value to be written to blr
* Function
* Write out a numeric valued attribute.
*
**************************************/
if (verb) {
append_uchar(verb);
}
append_ushort_with_length(number);
}
//
// Write out a string valued attribute.
//
void dsql_req::append_cstring(UCHAR verb, const char* string)
{
const USHORT length = string ? strlen(string) : 0;
append_string(verb, string, length);
}
//
// Write out a string valued attribute.
//
void dsql_req::append_string(UCHAR verb, const char* string, USHORT length)
{
// TMN: Doesn't this look pretty awkward? If we are given
// a verb, the length is a ushort, else it's uchar.
if (verb) {
append_uchar(verb);
append_ushort(length);
}
else {
fb_assert(length <= MAX_UCHAR);
append_uchar(length);
}
if (string) {
for (; *string && length--; string++) {
append_uchar(*string);
}
}
}
void dsql_req::append_uchar(UCHAR byte)
2001-12-24 03:51:06 +01:00
{
req_blr_data.add(byte);
2001-12-24 03:51:06 +01:00
}
void dsql_req::append_uchars(UCHAR byte, UCHAR count)
2001-12-24 03:51:06 +01:00
{
for (int i = 0; i < count; ++i) {
2001-12-24 03:51:06 +01:00
append_uchar(byte);
}
}
void dsql_req::append_ushort(USHORT val)
2001-12-24 03:51:06 +01:00
{
append_uchar(val);
append_uchar(val >> 8);
}
void dsql_req::append_ulong(ULONG val)
2001-12-24 03:51:06 +01:00
{
append_ushort(val);
append_ushort(val >> 16);
}
void dsql_req::append_ushort_with_length(USHORT val)
2001-12-24 03:51:06 +01:00
{
// append an USHORT value, prepended with the USHORT length of an USHORT
append_ushort(2);
append_ushort(val);
}
void dsql_req::append_ulong_with_length(ULONG val)
2001-12-24 03:51:06 +01:00
{
// append an ULONG value, prepended with the USHORT length of an ULONG
append_ushort(4);
append_ulong(val);
}
void dsql_req::append_file_length(ULONG length)
2001-12-24 03:51:06 +01:00
{
2003-11-08 00:27:24 +01:00
append_uchar(isc_dyn_file_length);
2001-12-24 03:51:06 +01:00
append_ulong_with_length(length);
}
void dsql_req::append_file_start(ULONG start)
2001-12-24 03:51:06 +01:00
{
2003-11-08 00:27:24 +01:00
append_uchar(isc_dyn_file_start);
2001-12-24 03:51:06 +01:00
append_ulong_with_length(start);
}
//
// common code factored out
//
void dsql_req::generate_unnamed_trigger_beginning( bool on_update_trigger,
const char* prim_rel_name,
const dsql_nod* prim_columns,
const char* for_rel_name,
const dsql_nod* for_columns)
2001-12-24 03:51:06 +01:00
{
// no trigger name. It is generated by the engine
2003-11-08 00:27:24 +01:00
append_string(isc_dyn_def_trigger, "", 0);
2001-12-24 03:51:06 +01:00
2003-11-08 00:27:24 +01:00
append_number(isc_dyn_trg_type,
2001-12-24 03:51:06 +01:00
(SSHORT) (on_update_trigger ? POST_MODIFY_TRIGGER :
POST_ERASE_TRIGGER));
2003-11-08 00:27:24 +01:00
append_uchar(isc_dyn_sql_object);
append_number(isc_dyn_trg_sequence, 1);
append_number(isc_dyn_trg_inactive, 0);
append_cstring(isc_dyn_rel_name, prim_rel_name);
2001-12-24 03:51:06 +01:00
// the trigger blr
2003-11-08 00:27:24 +01:00
begin_blr(isc_dyn_trg_blr);
2001-12-24 03:51:06 +01:00
/* for ON UPDATE TRIGGER only: generate the trigger firing condition:
if prim_key.old_value != prim_key.new value.
Note that the key could consist of multiple columns */
if (on_update_trigger) {
stuff_trg_firing_cond(this, prim_columns);
append_uchars(blr_begin, 2);
}
append_uchar(blr_for);
append_uchar(blr_rse);
// the context for the prim. key relation
append_uchar(1);
append_uchar(blr_relation);
append_cstring(0, for_rel_name);
// the context for the foreign key relation
append_uchar(2);
// generate the blr for: foreign_key == primary_key
stuff_matching_blr(this, for_columns, prim_columns);
append_uchar(blr_modify);
append_uchar(2);
append_uchar(2);
append_uchar(blr_begin);
}