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

6105 lines
166 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): ______________________________________.
*
2003-10-15 00:22:32 +02:00
* $Id: ddl.cpp,v 1.69 2003-10-14 22:22:32 brodsom 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
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/ib_stdio.h"
#include <string.h>
#include "../dsql/dsql.h"
#include "../jrd/gds.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 "gen/codes.h"
2001-05-23 15:26:42 +02:00
#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/thd_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 check_array_or_blob(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, DSQL_NOD, DSQL_NOD, 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, DSQL_FLD);
static void define_domain(DSQL_REQ);
static void define_exception(DSQL_REQ, NOD_TYPE);
static void define_field(DSQL_REQ, DSQL_NOD, SSHORT, STR);
static void define_filter(DSQL_REQ);
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, DSQL_NOD, DSQL_NOD, DSQL_NOD, const char*, const char*, bool);
static void define_set_default_trg(DSQL_REQ, DSQL_NOD, DSQL_NOD, 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, DSQL_NOD, DSQL_NOD, 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, DSQL_NOD, DSQL_NOD, DSQL_NOD, const char*, const char*);
static void make_index_trg_ref_int(DSQL_REQ, DSQL_NOD, DSQL_NOD, DSQL_NOD, const char*, const char*);
static void modify_database(DSQL_REQ);
static void modify_domain(DSQL_REQ);
static void modify_field(DSQL_REQ, DSQL_NOD, SSHORT, STR);
static void modify_index(DSQL_REQ);
static void modify_privilege(DSQL_REQ, NOD_TYPE, SSHORT, UCHAR *, DSQL_NOD, DSQL_NOD, STR);
static SCHAR modify_privileges(DSQL_REQ, NOD_TYPE, SSHORT, DSQL_NOD, DSQL_NOD, DSQL_NOD);
static void modify_relation(DSQL_REQ);
static void process_role_nm_list(DSQL_REQ, SSHORT, DSQL_NOD, DSQL_NOD, NOD_TYPE);
static void put_descriptor(DSQL_REQ, DSC *);
static void put_dtype(DSQL_REQ, const dsql_fld*, bool);
static void put_field(DSQL_REQ, DSQL_FLD, bool);
static void put_local_variable(DSQL_REQ, VAR, DSQL_NOD);
static SSHORT 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, SCHAR *);
static void save_relation(DSQL_REQ, STR);
static void set_statistics(DSQL_REQ);
static void stuff_default_blr(DSQL_REQ, TEXT *, USHORT);
static void stuff_matching_blr(DSQL_REQ, DSQL_NOD, DSQL_NOD);
static void stuff_trg_firing_cond(DSQL_REQ, DSQL_NOD);
static void set_nod_value_attributes(DSQL_NOD, DSQL_FLD);
2001-05-23 15:26:42 +02:00
#ifdef BLKCHK
#undef BLKCHK
#endif
#ifdef DEV_BUILD
2003-02-25 01:05:06 +01:00
static inline void BLKCHK(const void* p, 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-09-28 02:36:28 +02:00
static inline void BLKCHK(const void* p, USHORT type){
}
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 char *OLD_CONTEXT = "OLD";
const char *NEW_CONTEXT = "NEW";
const char *TEMP_CONTEXT = "TEMP";
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 */
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 */
};
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
};
static inline bool hasOldContext(int value)
{
int val1 = ((value + 1) >> 1) & 3;
int val2 = ((value + 1) >> 3) & 3;
int val3 = ((value + 1) >> 5) & 3;
return (val1 && val1 != 1) || (val2 && val2 != 1) || (val3 && val3 != 1);
}
static inline bool hasNewContext(int value)
{
int val1 = ((value + 1) >> 1) & 3;
int val2 = ((value + 1) >> 3) & 3;
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.
*
**************************************/
2001-12-24 03:51:06 +01:00
2003-04-10 08:32:58 +02:00
ISC_STATUS s;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
TSQL tdsql = 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(reinterpret_cast<UCHAR*>(request->req_blr_string->str_data),
gds__trace_printer, NULL, 0);
}
2001-05-23 15:26:42 +02:00
#endif
USHORT length = request->req_blr -
reinterpret_cast<BLOB_PTR*>(request->req_blr_string->str_data);
2001-05-23 15:26:42 +02:00
THREAD_EXIT;
2003-08-30 03:54:25 +02:00
s = isc_ddl(tdsql->tsql_status, &request->req_dbb->dbb_database_handle,
&request->req_trans, length, request->req_blr_string->str_data);
2001-05-23 15:26:42 +02:00
THREAD_ENTER;
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
STR string = NULL;
2002-11-11 20:08:37 +01:00
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];
string = (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:
string = (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
if ((request->req_ddl_node->nod_type == nod_mod_procedure) ||
(request->req_ddl_node->nod_type == nod_del_procedure) ||
(request->req_ddl_node->nod_type == nod_replace_procedure) ||
(request->req_ddl_node->nod_type == nod_redef_procedure))
{
2002-06-29 08:56:51 +02:00
2001-05-23 15:26:42 +02:00
string = (STR) request->req_ddl_node->nod_arg[e_prc_name];
METD_drop_procedure(request, string);
}
2002-06-29 08:56:51 +02:00
/* Signal UDF for obsolescence */
if (request->req_ddl_node->nod_type == nod_del_udf) {
string = (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) {
2001-12-29 12:41:29 +01:00
Firebird::status_exception::raise(tdsql->tsql_status[1]);
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
request->append_uchar(gds_dyn_version_1);
2001-05-23 15:26:42 +02:00
generate_dyn(request, node);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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.
//
void DDL_resolve_intl_type(DSQL_REQ request, DSQL_FLD field, 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,
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
2001-05-23 15:26:42 +02:00
INTLSYM resolved_type;
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(gds_sqlerr, gds_arg_number, (SLONG) -204,
gds_arg_gds, gds_dsql_datatype_err,
gds_arg_gds, gds_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,
reinterpret_cast<STR>(field->fld_sub_type_name),
"RDB$FIELD_SUB_TYPE",
2001-05-23 15:26:42 +02:00
&blob_sub_type))
{
ERRD_post( gds_sqlerr,
2001-05-23 15:26:42 +02:00
gds_arg_number,
(SLONG) -204,
2001-05-23 15:26:42 +02:00
gds_arg_gds,
gds_dsql_datatype_err,
2001-05-23 15:26:42 +02:00
gds_arg_gds,
gds_dsql_blob_type_unknown,
2001-05-23 15:26:42 +02:00
gds_arg_string,
((STR) field->fld_sub_type_name)->str_data,
0);
}
field->fld_sub_type = blob_sub_type;
}
if (field->fld_character_set && (field->fld_sub_type == BLOB_untyped))
{
field->fld_sub_type = BLOB_text;
}
if (field->fld_character_set && (field->fld_sub_type != BLOB_text))
{
ERRD_post( gds_sqlerr,
2001-05-23 15:26:42 +02:00
gds_arg_number,
(SLONG) -204,
2001-05-23 15:26:42 +02:00
gds_arg_gds,
gds_dsql_datatype_err,
2001-05-23 15:26:42 +02:00
gds_arg_gds,
gds_collation_requires_text,
2001-05-23 15:26:42 +02:00
0);
}
if (collation_name)
{
ERRD_post( gds_sqlerr,
2001-05-23 15:26:42 +02:00
gds_arg_number,
(SLONG) -204,
2001-05-23 15:26:42 +02:00
gds_arg_gds,
gds_dsql_datatype_err,
2001-05-23 15:26:42 +02:00
gds_arg_gds,
gds_collation_requires_text,
2001-05-23 15:26:42 +02:00
0);
}
if (field->fld_sub_type != BLOB_text) {
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)
{
2002-06-29 08:56:51 +02:00
DSQL_REL relation = request->req_relation;
DSQL_FLD afield = field->fld_next;
2002-06-29 08:56:51 +02:00
USHORT bpc = 0;
while (afield) {
/* The first test is redundant. */
if (afield != field && afield->fld_relation
&& !strcmp (afield->fld_name, field->fld_name)) {
assert (afield->fld_relation == relation || !relation);
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;
}
}
2001-05-23 15:26:42 +02:00
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
2001-12-24 03:51:06 +01:00
STR dfl_charset = METD_get_default_charset(request);
if (dfl_charset)
{
2002-11-11 20:08:37 +01:00
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;
2001-12-24 03:51:06 +01:00
if (field->fld_flags & FLD_national) {
charset_name = NATIONAL_CHARACTER_SET;
2001-12-24 03:51:06 +01:00
} else if (field->fld_character_set) {
charset_name = ((STR) field->fld_character_set)->str_data;
2001-12-24 03:51:06 +01:00
} else {
charset_name = 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
// Find an intlsym for any specified character set name & collation name
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (charset_name)
{
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(gds_sqlerr, gds_arg_number, (SLONG) -204,
gds_arg_gds, gds_dsql_datatype_err,
gds_arg_gds, gds_charset_not_found, gds_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)
{
INTLSYM resolved_collation =
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(gds_sqlerr, gds_arg_number, (SLONG) -204,
gds_arg_gds, gds_dsql_datatype_err,
gds_arg_gds, gds_collation_not_found, gds_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(gds_sqlerr, gds_arg_number, (SLONG) -204, gds_arg_gds,
gds_dsql_datatype_err, gds_arg_gds,
gds_collation_not_for_charset, gds_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-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (field->fld_character_length)
{
2002-06-29 08:56:51 +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
}
2001-05-23 15:26:42 +02:00
if (field_length > (ULONG) MAX_COLUMN_SIZE)
2001-12-24 03:51:06 +01:00
{
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) -204,
gds_arg_gds, gds_dsql_datatype_err,
gds_arg_gds, gds_imp_exc,
gds_arg_gds, gds_field_name, gds_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
}
2001-12-24 03:51:06 +01:00
//
// 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)
2001-05-23 15:26:42 +02:00
{
2001-12-24 03:51:06 +01:00
if (verb) {
append_uchar(verb);
}
2001-05-23 15:26:42 +02:00
req_base_offset = req_blr - reinterpret_cast<BLOB_PTR*>(req_blr_string->str_data);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// 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);
2001-05-23 15:26:42 +02:00
}
static bool check_array_or_blob(DSQL_NOD node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c h e c k _ a r r a y _ o r _ b l o b
*
**************************************
*
* Functional description
* return TRUE if there is an array or blob in expression, else FALSE.
* 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_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
{
DSQL_MAP map = (DSQL_MAP) node->nod_arg[e_map_map];
2001-05-23 15:26:42 +02:00
return check_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 check_array_or_blob(node->nod_arg[0]);
case nod_cast:
2001-12-24 03:51:06 +01:00
{
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
}
2001-05-23 15:26:42 +02:00
return check_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:
2001-12-24 03:51:06 +01:00
if (check_array_or_blob(node->nod_arg[0])) {
return true;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
return check_array_or_blob(node->nod_arg[1]);
case nod_alias:
return check_array_or_blob(node->nod_arg[e_alias_value]);
case nod_udf:
2001-12-24 03:51:06 +01:00
{
UDF udf = (UDF) node->nod_arg[0];
if ((udf->udf_dtype == dtype_blob) || (udf->udf_dtype == dtype_array)) {
return true;
2001-12-24 03:51:06 +01:00
}
// parameters to UDF don't need checking,
// an 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
{
2002-11-11 20:08:37 +01:00
const DSQL_NOD* end = node->nod_arg + node->nod_count;
for (DSQL_NOD* ptr = node->nod_arg; ptr < end; ++ptr)
2001-12-24 03:51:06 +01:00
{
if (check_array_or_blob(*ptr)) {
return true;
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:
assert(FALSE);
return false;
2001-05-23 15:26:42 +02:00
}
}
static void check_constraint( DSQL_REQ request,
2002-11-11 20:08:37 +01:00
DSQL_NOD element,
bool delete_trigger_required)
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.
*
**************************************/
2002-11-11 20:08:37 +01:00
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
2002-11-11 20:08:37 +01: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
2002-11-11 20:08:37 +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] =
2002-11-11 20:08:37 +01:00
// (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-09-01 09:39:54 +02:00
MAKE_constant((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] =
2002-11-11 20:08:37 +01:00
// (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-09-01 09:39:54 +02:00
MAKE_constant((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] =
2002-11-11 20:08:37 +01:00
// (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-09-01 09:39:54 +02:00
MAKE_constant((STR) PRE_ERASE_TRIGGER, CONSTANT_SLONG);
2001-05-23 15:26:42 +02:00
define_constraint_trigger(request, element);
}
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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) {
2003-09-12 03:41:03 +02:00
ERRD_post (gds_sqlerr, gds_arg_number, (SLONG) -637,
gds_arg_gds, gds_dsql_duplicate_spec,
2003-09-13 12:26:47 +02:00
gds_arg_string, error_msg,
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)
2001-05-23 15:26:42 +02:00
{ /* Fields in the VIEW actually */
/* *************************************
*
* 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
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD temp, base_relation, base_and_node;
2001-12-24 03:51:06 +01:00
2002-11-11 20:08:37 +01: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
2002-11-11 20:08:37 +01: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
2002-11-11 20:08:37 +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] =
2002-11-11 20:08:37 +01:00
// (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-09-01 09:39:54 +02:00
MAKE_constant((STR) PRE_MODIFY_TRIGGER, CONSTANT_SLONG);
2001-05-23 15:26:42 +02:00
define_update_action(request, &base_and_node, &base_relation);
2002-11-11 20:08:37 +01:00
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;
rse->nod_arg[e_rse_streams] = temp = MAKE_node(nod_list, 1);
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] =
2002-11-11 20:08:37 +01:00
// (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-09-01 09:39:54 +02:00
MAKE_constant((STR) PRE_STORE_TRIGGER, CONSTANT_SLONG);
2001-05-23 15:26:42 +02:00
define_view_trigger(request, element, NULL, items);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end); // For triggers definition
2001-05-23 15:26:42 +02:00
}
static void define_computed(DSQL_REQ request,
2002-11-11 20:08:37 +01:00
DSQL_NOD relation_node,
DSQL_FLD field,
2002-11-11 20:08:37 +01:00
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
*
**************************************/
2002-11-11 20:08:37 +01: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
2001-12-24 03:51:06 +01:00
DSC save_desc;
2001-05-23 15:26:42 +02:00
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)
{
2001-05-23 15:26:42 +02:00
assert(field->fld_dtype <= MAX_UCHAR);
save_desc.dsc_dtype = (UCHAR) field->fld_dtype;
save_desc.dsc_length = field->fld_length;
assert(field->fld_scale <= MAX_SCHAR);
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);
2003-09-02 01:22:22 +02:00
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 (check_array_or_blob(input))
2001-12-24 03:51:06 +01:00
{
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_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
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_fld_computed_blr);
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
DSC desc;
2001-05-23 15:26:42 +02:00
MAKE_desc(&desc, input);
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
STR source = (STR) node->nod_arg[e_cmp_text];
2001-05-23 15:26:42 +02:00
assert(source->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_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 */
2002-11-11 20:08:37 +01:00
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;
}
STR trigger_name = (STR) node->nod_arg[e_cnstr_name];
assert(trigger_name->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_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
2002-11-11 20:08:37 +01:00
DSQL_NOD relation_node = node->nod_arg[e_cnstr_table];
2001-05-23 15:26:42 +02:00
STR relation_name = (STR) relation_node->nod_arg[e_rln_name];
assert(trigger_name->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_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
STR source = (STR) node->nod_arg[e_cnstr_source];
if (source)
{
assert(source->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_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
}
2002-11-11 20:08:37 +01:00
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
{
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_trg_sequence,
2003-04-08 02:31:20 +02:00
(SSHORT)(SLONG) (constant ? constant->nod_arg[0] : 0));
2001-05-23 15:26:42 +02:00
}
if ((constant = node->nod_arg[e_cnstr_type]) != NULL)
{
2003-04-08 02:31:20 +02:00
const SSHORT type = (SSHORT)(SLONG) constant->nod_arg[0];
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_trg_type, type);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_sql_object);
2001-05-23 15:26:42 +02:00
STR message = (STR) node->nod_arg[e_cnstr_message];
if (message)
{
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_def_trigger_msg, 0);
2001-05-23 15:26:42 +02:00
assert(message->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_dyn_trg_msg,
message->str_data,
2001-12-24 03:51:06 +01:00
(USHORT) message->str_length);
request->append_uchar(gds_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])
{
2001-12-24 03:51:06 +01:00
request->begin_blr(gds_dyn_trg_blr);
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
// FALSE for the delete_trigger_required flag. Hence, I thought I could
// 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".
2002-11-11 20:08:37 +01: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);
2002-11-11 20:08:37 +01: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);
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
2002-11-11 20:08:37 +01:00
DSQL_NOD actions = node->nod_arg[e_cnstr_actions];
DSQL_NOD* ptr;
DSQL_NOD* end;
2001-05-23 15:26:42 +02:00
for (ptr = actions->nod_arg, end = ptr + actions->nod_count;
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 */
if ((actions = node->nod_arg[e_cnstr_else]) != NULL)
{
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_begin);
2001-05-23 15:26:42 +02:00
for (ptr = actions->nod_arg, end = ptr + actions->nod_count;
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);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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.
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD ddl_node, elements, element, *ptr, *end;
2001-05-23 15:26:42 +02:00
STR name;
SLONG start = 0;
FIL file;
SSHORT number = 0;
SLONG temp_long;
SSHORT temp_short;
ddl_node = request->req_ddl_node;
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_mod_database);
2001-05-23 15:26:42 +02:00
/*
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_rel_sql_protection, 1);
2001-05-23 15:26:42 +02:00
*/
elements = ddl_node->nod_arg[e_database_initial_desc];
if (elements)
for (ptr = elements->nod_arg, end = ptr + elements->nod_count;
ptr < end; ptr++) {
element = *ptr;
switch (element->nod_type) {
case nod_file_length:
start = (SLONG) (element->nod_arg[0]) + 1;
break;
default:
break;
}
}
elements = ddl_node->nod_arg[e_database_rem_desc];
if (elements)
2001-12-24 03:51:06 +01:00
{
2001-05-23 15:26:42 +02:00
for (ptr = elements->nod_arg, end = ptr + elements->nod_count;
2001-12-24 03:51:06 +01:00
ptr < end; ptr++)
{
2001-05-23 15:26:42 +02:00
element = *ptr;
switch (element->nod_type) {
case nod_difference_file:
request->append_cstring(isc_dyn_def_difference,
((STR)element->nod_arg[0])->str_data);
break;
2001-05-23 15:26:42 +02:00
case nod_file_desc:
file = (FIL) element->nod_arg[0];
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_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);
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
start += file->fil_length;
break;
case nod_log_file_desc:
file = (FIL) element->nod_arg[0];
if (file->fil_flags & LOG_default) {
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_def_default_log);
2001-05-23 15:26:42 +02:00
break;
}
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_def_log_file,
file->fil_name->str_data);
2001-12-24 03:51:06 +01:00
request->append_file_length(file->fil_length);
request->append_uchar(gds_dyn_log_file_sequence);
request->append_ushort_with_length(number);
++number;
request->append_uchar(gds_dyn_log_file_partitions);
request->append_ushort_with_length(file->fil_partitions);
if (file->fil_flags & LOG_serial) {
request->append_uchar(gds_dyn_log_file_serial);
}
if (file->fil_flags & LOG_overflow) {
request->append_uchar(gds_dyn_log_file_overflow);
}
if (file->fil_flags & LOG_raw) {
request->append_uchar(gds_dyn_log_file_raw);
}
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_cache_file_desc:
file = (FIL) element->nod_arg[0];
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_def_cache_file,
file->fil_name->str_data);
2001-12-24 03:51:06 +01:00
request->append_file_length(file->fil_length);
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_group_commit_wait:
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_log_group_commit_wait);
2001-05-23 15:26:42 +02:00
temp_long = (SLONG) (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:
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_log_check_point_length);
2001-05-23 15:26:42 +02:00
temp_long = (SLONG) (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:
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_log_num_of_buffers);
2003-04-08 02:31:20 +02:00
temp_short = (SSHORT)(SLONG) (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:
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_log_buffer_size);
2003-04-08 02:31:20 +02:00
temp_short = (SSHORT)(SLONG) (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_dfl_charset:
name = (STR) element->nod_arg[0];
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_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
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void define_del_cascade_trg( DSQL_REQ request,
DSQL_NOD element,
DSQL_NOD for_columns,
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.
request->append_string( gds_dyn_def_trigger, "", 0);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_trg_type, (SSHORT) POST_ERASE_TRIGGER);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_sql_object);
request->append_number(gds_dyn_trg_sequence, (SSHORT) 1);
request->append_number(gds_dyn_trg_inactive, (SSHORT) 0);
request->append_cstring(gds_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
request->begin_blr(gds_dyn_trg_blr);
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
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void define_set_default_trg( DSQL_REQ request,
DSQL_NOD element,
DSQL_NOD for_columns,
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;
2002-11-11 20:08:37 +01:00
DSQL_NOD* for_key_flds = for_columns->nod_arg;
DSQL_NOD ddl_node = request->req_ddl_node;
2001-05-23 15:26:42 +02:00
do {
/* for every column in the foreign key .... */
2001-12-24 03:51:06 +01:00
STR for_key_fld_name_str = (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 */
2002-11-11 20:08:37 +01:00
DSQL_NOD elem = ddl_node->nod_arg[e_drl_elements];
DSQL_NOD* end = elem->nod_arg + elem->nod_count;
for (DSQL_NOD* ptr = elem->nod_arg; 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
}
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
/* Now, we have the right column in the parse tree. case (1) above */
2002-11-11 20:08:37 +01:00
DSQL_NOD default_node = elem->nod_arg[e_dfl_default];
2001-12-24 03:51:06 +01:00
if (default_node)
{
2001-05-23 15:26:42 +02:00
/* case (1-a) above: there is a col. level default */
GEN_expr(request, default_node);
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
{
TEXT* domain_name;
STR domain_name_str;
2002-11-11 20:08:37 +01:00
DSQL_NOD domain_node;
DSQL_NOD tmp_node;
2001-12-24 03:51:06 +01:00
2001-05-23 15:26:42 +02:00
if (!(domain_node = elem->nod_arg[e_dfl_domain]) ||
!(tmp_node = domain_node->nod_arg[e_dom_name]) ||
!(domain_name_str = (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 */
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, sizeof(default_val));
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)
{
2001-05-23 15:26:42 +02:00
/* case 2: see if the column/domain has already been created */
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, sizeof(default_val));
2001-12-24 03:51:06 +01:00
} else {
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
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void define_dimensions( DSQL_REQ request, 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
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD elements = field->fld_ranges;
2001-12-24 03:51:06 +01:00
USHORT dims = elements->nod_count / 2;
2001-05-23 15:26:42 +02:00
if (dims > MAX_ARRAY_DIMENSIONS)
{
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) -604,
gds_arg_gds, gds_dsql_max_arr_dim_exceeded, 0);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_fld_dimensions, (SSHORT) dims);
2001-05-23 15:26:42 +02:00
SSHORT position = 0;
2002-11-11 20:08:37 +01:00
DSQL_NOD* ptr = elements->nod_arg;
DSQL_NOD* end = ptr + elements->nod_count;
2001-05-23 15:26:42 +02:00
for (; ptr < end; ++ptr, ++position)
{
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_def_dimension, position);
2002-11-11 20:08:37 +01:00
DSQL_NOD element = *ptr++;
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_dim_lower);
SLONG lrange = (SLONG) (element->nod_arg[0]);
request->append_ulong_with_length(lrange);
2001-05-23 15:26:42 +02:00
element = *ptr;
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_dim_upper);
SLONG hrange = (SLONG) (element->nod_arg[0]);
request->append_ulong_with_length(hrange);
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
if (lrange >= hrange)
{
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) -604,
gds_arg_gds, gds_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
2002-11-11 20:08:37 +01: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
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_def_global_fld, field->fld_name);
2001-05-23 15:26:42 +02:00
DDL_resolve_intl_type(request, field,
(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
2002-11-11 20:08:37 +01: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);
2001-12-24 03:51:06 +01:00
request->begin_blr(gds_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
2001-12-24 03:51:06 +01:00
STR string = (STR) element->nod_arg[e_dom_default_source];
2001-05-23 15:26:42 +02:00
if (string)
{
assert(string->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_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)
{
2002-11-11 20:08:37 +01:00
DSQL_NOD* ptr = node->nod_arg;
DSQL_NOD* 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)
{
2002-11-11 20:08:37 +01:00
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
{
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_fld_not_null);
null_flag = true;
2001-05-23 15:26:42 +02:00
}
else
{
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) -637,
gds_arg_gds, gds_dsql_duplicate_spec,
2001-05-23 15:26:42 +02:00
gds_arg_string, "NOT NULL", 0);
}
}
else if (node1->nod_type == nod_def_constraint)
{
if (check_flag)
{
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) -637,
gds_arg_gds, gds_dsql_duplicate_spec,
2001-05-23 15:26:42 +02:00
gds_arg_string, "DOMAIN CHECK CONSTRAINT",
0);
}
2001-12-24 03:51:06 +01:00
check_flag = true;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
STR string = (STR) node1->nod_arg[e_cnstr_source];
2001-05-23 15:26:42 +02:00
if (string)
{
assert(string->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_dyn_fld_validation_source,
string->str_data,
string->str_length);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
request->begin_blr(gds_dyn_fld_validation_blr);
2001-05-23 15:26:42 +02:00
/* Set any VALUE nodes to the type of the domain being defined. */
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
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
}
}
}
}
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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.
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD ddl_node;
2001-05-23 15:26:42 +02:00
STR text, name;
ddl_node = request->req_ddl_node;
name = (STR) ddl_node->nod_arg[e_xcp_name];
text = (STR) ddl_node->nod_arg[e_xcp_text];
if (op == nod_def_exception)
request->append_cstring(gds_dyn_def_exception, name->str_data);
2001-05-23 15:26:42 +02:00
else if (op == nod_mod_exception)
request->append_cstring(gds_dyn_mod_exception, name->str_data);
2001-05-23 15:26:42 +02:00
else
request->append_cstring(gds_dyn_del_exception, name->str_data);
2001-05-23 15:26:42 +02:00
if (op != nod_del_exception) {
assert(text->str_length <= MAX_USHORT);
request->append_string(gds_dyn_xcp_msg, text->str_data, text->str_length);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
}
}
static void define_field(
DSQL_REQ request,
2002-11-11 20:08:37 +01:00
DSQL_NOD element, SSHORT position, 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.
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD domain_node, node, node1, *ptr;
DSQL_FLD field;
2001-05-23 15:26:42 +02:00
DSQL_REL relation;
STR string, domain_name;
bool cnstrt_flag = false;
2002-11-11 20:08:37 +01:00
DSQL_NOD computed_node;
2001-12-24 03:51:06 +01:00
bool default_null_flag = false;
2001-05-23 15:26:42 +02:00
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 */
if ((relation = request->req_relation) != NULL) {
field->fld_next = relation->rel_fields;
relation->rel_fields = field;
}
if (domain_node = element->nod_arg[e_dfl_domain]) {
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_def_local_fld, field->fld_name);
2001-05-23 15:26:42 +02:00
node1 = domain_node->nod_arg[e_dom_name];
domain_name = (STR) node1->nod_arg[e_fln_name];
request->append_cstring(gds_dyn_fld_source, domain_name->str_data);
2001-05-23 15:26:42 +02:00
/* Get the domain information */
if (!(METD_get_domain(request, field, domain_name->str_data)))
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_dsql_domain_not_found,
2002-06-29 08:56:51 +02:00
gds_arg_string, domain_name->str_data,
2001-05-23 15:26:42 +02:00
/* Specified domain or source field does not exist */
0);
DDL_resolve_intl_type( request,
field,
reinterpret_cast<STR>(element->nod_arg[e_dfl_collate]));
if (element->nod_arg[e_dfl_collate]) {
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_fld_collation,
2001-05-23 15:26:42 +02:00
field->fld_collation_id);
}
}
2001-12-24 03:51:06 +01:00
else
{
request->append_cstring(gds_dyn_def_sql_fld, field->fld_name);
if (relation_name) {
request->append_cstring(gds_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;
computed_node = element->nod_arg[e_dfl_computed];
define_computed(request,
request->req_ddl_node->nod_arg[e_drl_name], field,
computed_node);
}
DDL_resolve_intl_type(request, field,
reinterpret_cast<STR>(element->nod_arg[e_dfl_collate]));
put_field(request, field, false);
2001-05-23 15:26:42 +02:00
}
if (position != -1)
2001-12-24 03:51:06 +01:00
request->append_number(gds_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
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
node = element->nod_arg[e_dfl_default];
if (node)
{
2003-09-02 01:22:22 +02:00
node = PASS1_node(request, node, false);
2001-12-24 03:51:06 +01:00
request->begin_blr(gds_dyn_fld_default_value);
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();
string = (STR) element->nod_arg[e_dfl_default_source];
if (string)
{
2001-05-23 15:26:42 +02:00
assert(string->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_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
/* check for constraints */
2001-12-24 03:51:06 +01:00
if (node = element->nod_arg[e_dfl_constraint])
{
2002-11-11 20:08:37 +01:00
DSQL_NOD* end_ptr = node->nod_arg + node->nod_count;
2001-12-24 03:51:06 +01:00
for (ptr = node->nod_arg; ptr < end_ptr; ++ptr)
{
if ((*ptr)->nod_type == nod_rel_constraint)
{
2001-05-23 15:26:42 +02:00
string = (STR) (*ptr)->nod_arg[e_rct_name];
node1 = (*ptr)->nod_arg[e_rct_type];
2001-12-24 03:51:06 +01:00
if (node1->nod_type == nod_null)
{
if (default_null_flag)
{
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) -204,
2001-05-23 15:26:42 +02:00
gds_arg_gds, isc_bad_default_value,
gds_arg_gds, isc_invalid_clause,
gds_arg_string, "default null not null", 0);
2001-12-24 03:51:06 +01:00
}
request->append_uchar(gds_dyn_fld_not_null);
if (!cnstrt_flag) {
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end); /* For field definition */
cnstrt_flag = true;
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_rel_constraint,
string ? string->str_data : 0);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_fld_not_null);
request->append_uchar(gds_dyn_end); /* For NOT NULL Constraint definition */
2001-05-23 15:26:42 +02:00
}
else if (node1->nod_type == nod_primary
2001-12-24 03:51:06 +01:00
|| node1->nod_type == nod_unique)
{
if (!cnstrt_flag)
2001-12-24 03:51:06 +01:00
{
request->append_uchar(gds_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;
request->append_cstring(gds_dyn_rel_constraint, constraint_name);
2002-11-11 20:08:37 +01:00
DSQL_NOD index = node1->nod_arg[e_pri_index];
assert(index);
const char* index_name = constraint_name;
string = (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)
{
request->append_cstring(gds_dyn_def_primary_key, index_name);
2001-12-24 03:51:06 +01:00
}
else if (node1->nod_type == nod_unique)
{
request->append_cstring(gds_dyn_def_unique, index_name);
}
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_idx_unique, 1);
if (index->nod_arg[e_idx_asc_dsc])
{
request->append_number(gds_dyn_idx_type, 1);
}
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_fld_name, field->fld_name);
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
}
else if (node1->nod_type == nod_foreign) {
if (!cnstrt_flag) {
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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;
request->append_cstring(gds_dyn_rel_constraint, constraint_name);
2003-01-17 13:40:01 +01:00
foreign_key(request, node1, constraint_name);
2001-05-23 15:26:42 +02:00
}
else if (node1->nod_type == nod_def_constraint) {
if (!cnstrt_flag) {
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end); /* For field definition */
cnstrt_flag = true;
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_rel_constraint,
string ? string->str_data : 0);
2001-05-23 15:26:42 +02:00
check_constraint(request, node1,
false /* No delete trigger */ );
2001-05-23 15:26:42 +02:00
}
}
}
}
if (!cnstrt_flag) {
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
}
2001-05-23 15:26:42 +02:00
}
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.
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD *ptr, filter_node;
2001-05-23 15:26:42 +02:00
filter_node = request->req_ddl_node;
ptr = filter_node->nod_arg;
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_def_filter,
((STR) (ptr[e_filter_name]))->str_data);
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_filter_in_subtype,
2003-04-08 02:31:20 +02:00
(SSHORT)(SLONG) ((ptr[e_filter_in_type])->nod_arg[0]));
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_filter_out_subtype,
2003-04-08 02:31:20 +02:00
(SSHORT)(SLONG) ((ptr[e_filter_out_type])->nod_arg[0]));
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_func_entry_point,
((STR) (ptr[e_filter_entry_pt]))->str_data);
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_func_module_name,
((STR) (ptr[e_filter_module]))->str_data);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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.
*
**************************************/
2001-12-24 03:51:06 +01:00
STR gen_name = (STR) request->req_ddl_node->nod_arg[e_gen_name];
request->append_cstring(gds_dyn_def_generator, gen_name->str_data);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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.
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD ddl_node, relation_node, field_list, *ptr, *end;
2001-05-23 15:26:42 +02:00
STR relation_name, index_name;
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_begin);
2001-05-23 15:26:42 +02:00
ddl_node = request->req_ddl_node;
2002-11-11 20:08:37 +01:00
relation_node = (DSQL_NOD) ddl_node->nod_arg[e_idx_table];
2001-05-23 15:26:42 +02:00
relation_name = (STR) relation_node->nod_arg[e_rln_name];
field_list = ddl_node->nod_arg[e_idx_fields];
index_name = (STR) ddl_node->nod_arg[e_idx_name];
request->append_cstring(gds_dyn_def_idx, index_name->str_data);
request->append_cstring(gds_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)
for (ptr = field_list->nod_arg, end = ptr + field_list->nod_count;
ptr < end; ptr++)
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_fld_name,
((STR) (*ptr)->nod_arg[1])->str_data);
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-12-24 03:51:06 +01:00
if (ddl_node->nod_arg[e_idx_unique]) {
request->append_number(gds_dyn_idx_unique, 1);
}
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]) {
request->append_number(gds_dyn_idx_type, 1);
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end); /* of define index */
request->append_uchar(gds_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.
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD ddl_node, action_node, insert_node;
DSQL_NOD select_node, select_expr, from_list, relation_node;
DSQL_NOD fields_node, values_node, field_node, value_node;
DSQL_NOD *ptr, *end, *ptr2, *end2;
2001-12-24 03:51:06 +01:00
DLLS field_stack, value_stack;
2001-05-23 15:26:42 +02:00
DSQL_REL relation;
DSQL_FLD field;
2001-05-23 15:26:42 +02:00
ddl_node = request->req_ddl_node;
/* check whether this is an updatable view definition */
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 */
action_node = MAKE_node(nod_list, (int) 1);
action_node->nod_arg[0] = insert_node =
MAKE_node(nod_insert, (int) e_ins_count);
/* use the relation referenced in the select statement to insert into */
relation_node = MAKE_node(nod_relation_name, (int) e_rln_count);
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];
2002-11-11 20:08:37 +01:00
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)
{
relation =
METD_get_relation(request,
reinterpret_cast<STR>(relation_node->nod_arg[e_rln_name]));
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);
2002-11-11 20:08:37 +01:00
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 */
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 */
if (field_node->nod_type == nod_field_name) {
field_node->nod_arg[e_fln_context] =
2002-11-11 20:08:37 +01:00
(DSQL_NOD) MAKE_cstring(TEMP_CONTEXT);
2001-05-23 15:26:42 +02:00
LLS_PUSH(field_node, &field_stack);
value_node = MAKE_node(nod_field_name, (int) e_fln_count);
value_node->nod_arg[e_fln_name] = (*ptr2)->nod_arg[e_fln_name];
value_node->nod_arg[e_fln_context] =
2002-11-11 20:08:37 +01:00
(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
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD parameters, parameter, *ptr, *end;
DSQL_PRC procedure;
DSQL_FLD field, *field_ptr;
2001-12-24 03:51:06 +01:00
SSHORT position;
2001-05-23 15:26:42 +02:00
VAR variable;
2001-12-24 03:51:06 +01:00
TSQL tdsql = GET_THREAD_DATA;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
SSHORT inputs = 0;
SSHORT outputs = 0;
SSHORT locals = 0;
2002-11-11 20:08:37 +01:00
DSQL_NOD procedure_node = request->req_ddl_node;
2001-12-24 03:51:06 +01:00
STR procedure_name = (STR) procedure_node->nod_arg[e_prc_name];
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)
{
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_def_procedure,
procedure_name->str_data);
2001-12-24 03:51:06 +01:00
request->append_number(gds_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
{
request->append_cstring(gds_dyn_mod_procedure,
procedure_name->str_data);
2001-12-24 03:51:06 +01:00
procedure = METD_get_procedure(request, procedure_name);
if (procedure)
{
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)
{
request->append_cstring(gds_dyn_delete_parameter,
2001-05-23 15:26:42 +02:00
field->fld_name);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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)
{
request->append_cstring(gds_dyn_delete_parameter,
2001-05-23 15:26:42 +02:00
field->fld_name);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
}
}
}
2001-12-24 03:51:06 +01:00
STR source = (STR) procedure_node->nod_arg[e_prc_source];
if (source)
{
2001-05-23 15:26:42 +02:00
assert(source->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_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);
procedure = FB_NEW_RPT(*tdsql->tsql_default, 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 */
field_ptr = &procedure->prc_inputs;
2001-12-24 03:51:06 +01:00
if (parameters = procedure_node->nod_arg[e_prc_inputs])
{
2001-05-23 15:26:42 +02:00
position = 0;
for (ptr = parameters->nod_arg, end = ptr + parameters->nod_count;
2001-12-24 03:51:06 +01:00
ptr < end; ptr++)
{
2001-05-23 15:26:42 +02:00
parameter = *ptr;
field = (DSQL_FLD) parameter->nod_arg[e_dfl_field];
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_def_parameter, field->fld_name);
request->append_number(gds_dyn_prm_number, position);
request->append_number(gds_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
*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 */
*field_ptr = field;
field_ptr = &field->fld_next;
position++;
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
request->append_number(gds_dyn_prc_inputs, position);
2001-05-23 15:26:42 +02:00
}
inputs = position;
}
/* Terminate the input list */
*field_ptr = NULL;
/* now do the output parameters */
field_ptr = &procedure->prc_outputs;
2001-12-24 03:51:06 +01:00
if (parameters = procedure_node->nod_arg[e_prc_outputs])
{
2001-05-23 15:26:42 +02:00
position = 0;
2001-12-24 03:51:06 +01:00
end = parameters->nod_arg + parameters->nod_count;
for (ptr = parameters->nod_arg; ptr < end; ++ptr)
{
2001-05-23 15:26:42 +02:00
parameter = *ptr;
field = (DSQL_FLD) parameter->nod_arg[e_dfl_field];
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_def_parameter, field->fld_name);
request->append_number(gds_dyn_prm_number, position);
request->append_number(gds_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++;
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
request->append_number(gds_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;
2001-12-24 03:51:06 +01:00
request->begin_blr(gds_dyn_prc_blr);
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];
for (ptr = parameters->nod_arg, end = ptr + parameters->nod_count;
2001-12-24 03:51:06 +01:00
ptr < end; ptr++)
{
2001-05-23 15:26:42 +02:00
parameter = *ptr;
variable = (VAR) parameter->nod_arg[e_var_variable];
field = variable->var_field;
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];
for (ptr = parameters->nod_arg, end = ptr + parameters->nod_count;
2001-12-24 03:51:06 +01:00
ptr < end; ptr++)
{
2001-05-23 15:26:42 +02:00
parameter = *ptr;
variable = (VAR) parameter->nod_arg[e_var_variable];
field = variable->var_field;
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];
for (ptr = parameters->nod_arg, end = ptr + parameters->nod_count;
2001-12-24 03:51:06 +01:00
ptr < end; ptr++)
{
2001-05-23 15:26:42 +02:00
parameter = *ptr;
variable = (VAR) parameter->nod_arg[e_var_variable];
put_local_variable(request, variable, 0);
2001-05-23 15:26:42 +02:00
}
}
locals = put_local_variables(request, procedure_node->nod_arg[e_prc_dcls],
locals);
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_stall);
2001-05-23 15:26:42 +02:00
/* 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;
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, 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
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_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
{
STR string = (STR) element->nod_arg[e_rct_name];
const char* constraint_name = string ? string->str_data : 0;
2001-05-23 15:26:42 +02:00
request->append_cstring(gds_dyn_rel_constraint, constraint_name);
2001-05-23 15:26:42 +02:00
DSQL_NOD node = element->nod_arg[e_rct_type];
if (node->nod_type == nod_unique || node->nod_type == nod_primary) {
2003-01-17 13:40:01 +01:00
make_index(request, node, node->nod_arg[0], 0, 0, constraint_name);
} else if (node->nod_type == nod_foreign) {
2003-01-17 13:40:01 +01:00
foreign_key(request, node, constraint_name);
} else if (node->nod_type == nod_def_constraint) {
check_constraint(request, node, false /* No delete trigger */ );
}
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
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD ddl_node, elements, element, *ptr, *end, relation_node;
2001-05-23 15:26:42 +02:00
STR relation_name, external_file;
SSHORT position;
ddl_node = request->req_ddl_node;
relation_node = ddl_node->nod_arg[e_drl_name];
relation_name = (STR) relation_node->nod_arg[e_rln_name];
request->append_cstring(gds_dyn_def_rel, relation_name->str_data);
2001-05-23 15:26:42 +02:00
if (external_file = (STR) ddl_node->nod_arg[e_drl_ext_file])
2001-12-24 03:51:06 +01:00
{
request->append_cstring(gds_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);
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_rel_sql_protection, 1);
2001-05-23 15:26:42 +02:00
/* now do the actual metadata definition */
elements = ddl_node->nod_arg[e_drl_elements];
for (ptr = elements->nod_arg, end = ptr + elements->nod_count, position =
0; ptr < end; ptr++) {
element = *ptr;
switch (element->nod_type) {
case nod_def_field:
define_field(request, element, position, relation_name);
position++;
break;
case nod_rel_constraint:
define_rel_constraint(request, element);
break;
default:
break;
}
}
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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
{
2001-12-24 03:51:06 +01:00
STR gen_name = (STR) request->req_ddl_node->nod_arg[e_gen_name];
request->append_cstring(isc_dyn_def_sql_role, gen_name->str_data);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void define_set_null_trg(DSQL_REQ request,
DSQL_NOD element,
DSQL_NOD for_columns,
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)
* The on_upd_trg parameter == TRUE is an update trigger.
*
*****************************************************/
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
2001-05-23 15:26:42 +02:00
assert(prim_columns->nod_count == for_columns->nod_count);
assert(prim_columns->nod_count != 0);
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;
2002-11-11 20:08:37 +01:00
DSQL_NOD* for_key_flds = for_columns->nod_arg;
2001-05-23 15:26:42 +02:00
do {
2001-12-24 03:51:06 +01:00
STR for_key_fld_name_str = (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
request->append_uchar(gds_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
{
2002-11-11 20:08:37 +01:00
DSQL_NOD shadow_node = request->req_ddl_node;
DSQL_NOD* 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(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_dsql_shadow_number_err, 0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2003-04-08 02:31:20 +02:00
request->append_number(gds_dyn_def_shadow, (SSHORT)(SLONG) (ptr[e_shadow_number]));
request->append_cstring(gds_dyn_def_file, ((STR) (ptr[e_shadow_name]))->str_data);
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_shadow_man_auto,
2003-04-08 02:31:20 +02:00
(SSHORT)(SLONG) ((ptr[e_shadow_man_auto])->nod_arg[0]));
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_shadow_conditional,
2003-04-08 02:31:20 +02:00
(SSHORT)(SLONG) ((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
2001-12-24 03:51:06 +01:00
SLONG length = (SLONG) ptr[e_shadow_length];
request->append_file_length(length);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2002-11-11 20:08:37 +01:00
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
{
2002-11-11 20:08:37 +01:00
DSQL_NOD* end = elements->nod_arg + elements->nod_count;
2001-12-24 03:51:06 +01:00
for (ptr = elements->nod_arg; ptr < end; ++ptr)
{
2002-11-11 20:08:37 +01:00
DSQL_NOD element = *ptr;
2001-12-24 03:51:06 +01:00
FIL file = (FIL) element->nod_arg[0];
request->append_cstring(gds_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(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_dsql_file_length_err,
2001-05-23 15:26:42 +02:00
gds_arg_number, (SLONG) file->fil_name->str_data,
/* Preceding file did not specify length, so %s must include starting page number */
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
SLONG start = file->fil_start;
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);
request->append_uchar(gds_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
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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
{
2001-12-24 03:51:06 +01:00
STR relation_name;
2002-11-11 20:08:37 +01:00
DSQL_NOD temp, constant, relation_node;
2001-05-23 15:26:42 +02:00
USHORT trig_type;
2001-12-24 03:51:06 +01:00
TSQL tdsql = 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;
2001-12-24 03:51:06 +01:00
STR trigger_name = (STR) node->nod_arg[e_trg_name];
2001-05-23 15:26:42 +02:00
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
{
2001-05-23 15:26:42 +02:00
assert(trigger_name->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_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];
relation_name = (STR) relation_node->nod_arg[e_rln_name];
assert(relation_name->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_dyn_rel_name,
relation_name->str_data,
relation_name->str_length);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_sql_object);
2001-05-23 15:26:42 +02:00
}
else // nod_mod_trigger
{
2001-05-23 15:26:42 +02:00
assert(node->nod_type == nod_mod_trigger);
assert(trigger_name->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_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. */
2001-12-24 03:51:06 +01:00
relation_name =
METD_get_trigger_relation( request,
trigger_name,
&trig_type);
if (!relation_name)
{
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) -204,
gds_arg_gds, gds_dsql_trigger_err, gds_arg_gds,
gds_random, gds_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->tsql_default, 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;
2002-11-11 20:08:37 +01:00
relation_node->nod_arg[e_rln_name] = (DSQL_NOD) relation_name;
2001-05-23 15:26:42 +02:00
}
}
2001-12-24 03:51:06 +01:00
STR source = (STR) node->nod_arg[e_trg_source];
2002-11-11 20:08:37 +01:00
DSQL_NOD actions = (node->nod_arg[e_trg_actions]) ?
2001-05-23 15:26:42 +02:00
node->nod_arg[e_trg_actions]->nod_arg[1] : NULL;
if (source && actions) {
assert(source->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_dyn_trg_source,
source->str_data,
source->str_length);
2001-05-23 15:26:42 +02:00
}
if (constant = node->nod_arg[e_trg_active])
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_trg_inactive,
2003-04-08 02:31:20 +02:00
(SSHORT)(SLONG) constant->nod_arg[0]);
2001-05-23 15:26:42 +02:00
if (constant = node->nod_arg[e_trg_position])
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_trg_sequence,
2003-04-08 02:31:20 +02:00
(SSHORT)(SLONG) constant->nod_arg[0]);
2001-05-23 15:26:42 +02:00
if (constant = node->nod_arg[e_trg_type]) {
2003-04-08 02:31:20 +02:00
request->append_number(gds_dyn_trg_type, (SSHORT)(SLONG) constant->nod_arg[0]);
trig_type = (USHORT)(ULONG) constant->nod_arg[0];
2001-05-23 15:26:42 +02:00
}
else {
assert(node->nod_type == nod_mod_trigger);
}
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
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] =
2002-11-11 20:08:37 +01:00
(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] =
2002-11-11 20:08:37 +01:00
(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
2001-12-24 03:51:06 +01:00
request->begin_blr(gds_dyn_trg_blr);
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[0], 0);
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 obvious conflict
// with trigger messages (nod_abort) is wrong,
// although the fact that they use the same BLR code
// is still a potential dangerous and must be fixed.
// Hopefully, system triggers are never recompiled.
request->append_uchar(blr_label);
request->append_uchar(0);
request->req_loop_level = 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;
}
if (temp = node->nod_arg[e_trg_messages])
2001-12-24 03:51:06 +01:00
{
2002-11-11 20:08:37 +01:00
DSQL_NOD* end = temp->nod_arg + temp->nod_count;
for (DSQL_NOD* ptr = temp->nod_arg; ptr < end; ++ptr)
2001-12-24 03:51:06 +01:00
{
2002-11-11 20:08:37 +01:00
DSQL_NOD message = *ptr;
2003-04-08 02:31:20 +02:00
SSHORT number = (SSHORT)(SLONG) message->nod_arg[e_msg_number];
2001-12-24 03:51:06 +01:00
if (message->nod_type == nod_del_trigger_msg)
{
request->append_number(gds_dyn_delete_trigger_msg, number);
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
else
{
STR message_text = (STR) message->nod_arg[e_msg_text];
if (message->nod_type == nod_def_trigger_msg) {
request->append_number(gds_dyn_def_trigger_msg, number);
} else {
request->append_number(gds_dyn_mod_trigger_msg, number);
}
2001-05-23 15:26:42 +02:00
assert(message_text->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_dyn_trg_msg,
message_text->str_data,
message_text->str_length);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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.
*
**************************************/
DSQL_NOD *end, *ret_val_ptr, *param_node;
DSQL_FLD field;
2001-05-23 15:26:42 +02:00
SSHORT position, blob_position;
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;
const char* udf_name = ((STR) (ptr[e_udf_name]))->str_data;
const STR func_entry_point_name = reinterpret_cast<STR>(ptr[e_udf_entry_pt]);
const STR func_module_name = reinterpret_cast<STR>(ptr[e_udf_module]);
request->append_cstring(gds_dyn_def_function, udf_name);
request->append_cstring(gds_dyn_func_entry_point, func_entry_point_name->str_data);
request->append_cstring(gds_dyn_func_module_name, func_module_name->str_data);
2001-05-23 15:26:42 +02:00
ret_val_ptr = ptr[e_udf_return_value]->nod_arg;
if (field = (DSQL_FLD) ret_val_ptr[0]) {
2001-05-23 15:26:42 +02:00
2002-06-29 08:56:51 +02:00
// CVC: This is case of "returns <type> [by value|reference]"
2001-05-23 15:26:42 +02:00
/* Some data types can not be returned as value */
2003-04-08 02:31:20 +02:00
if (((int)(SLONG) (ret_val_ptr[1]->nod_arg[0]) == 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(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_return_mode_err,
2001-05-23 15:26:42 +02:00
/* Return mode by value not allowed for this data type */
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(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_extern_func_err,
2001-05-23 15:26:42 +02:00
/* External functions can not have more than 10 parameters */
/* Or 9 if the function returns a BLOB */
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
request->append_number(gds_dyn_func_return_argument, blob_position);
2001-05-23 15:26:42 +02:00
}
else
2001-12-24 03:51:06 +01:00
{
request->append_number(gds_dyn_func_return_argument, (SSHORT) 0);
}
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>"
2003-04-08 02:31:20 +02:00
position = (SSHORT)(SLONG) (ret_val_ptr[1]->nod_arg[0]);
2001-05-23 15:26:42 +02:00
/* Function modifies an argument whose value is the function return value */
2002-06-29 08:56:51 +02:00
if (!arguments || position > arguments->nod_count || position < 1) {
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) -607,
2002-06-29 08:56:51 +02:00
gds_arg_gds, isc_dsql_udf_return_pos_err, /*gds__extern_func_err, */
gds_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
2001-05-23 15:26:42 +02:00
/* External functions can not have more than 10 parameters */
/* Not strictly correct -- return position error */
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
request->append_number(gds_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)
{
2002-06-29 08:56:51 +02:00
/* CVC: This is case of "returns <type> [by value|reference]" */
2001-12-24 03:51:06 +01:00
if (field->fld_dtype == dtype_blob)
{
2002-06-29 08:56:51 +02:00
/* CVC: I need to test returning blobs by descriptor before allowing the change there. For now, I ignore the return type specification. */
2003-09-12 03:41:03 +02:00
bool free_it = ((SSHORT)(SLONG) ret_val_ptr[1]->nod_arg[0] < 0);
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_def_function_arg, blob_position);
request->append_number(gds_dyn_func_mechanism,
2003-04-08 02:31:20 +02:00
(SSHORT)(SLONG) ((free_it ? -1 : 1) * 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
{
request->append_number(gds_dyn_def_function_arg, (SSHORT) 0);
request->append_number(gds_dyn_func_mechanism,
2003-04-08 02:31:20 +02:00
(SSHORT)(SLONG) (ret_val_ptr[1]->nod_arg[0]));
2001-05-23 15:26:42 +02:00
}
request->append_cstring(gds_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);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
position = 1;
}
assert(position == 1);
2002-06-29 08:56:51 +02:00
/* CVC: This for all params, including the case of "returns parameter <N>" */
2001-05-23 15:26:42 +02:00
if (arguments)
2001-12-24 03:51:06 +01:00
{
2001-05-23 15:26:42 +02:00
for (ptr = arguments->nod_arg, 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(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_extern_func_err,
2001-05-23 15:26:42 +02:00
/* External functions can not have more than 10 parameters */
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
/*field = (DSQL_FLD) *ptr; */
2002-06-29 08:56:51 +02:00
param_node = (*ptr)->nod_arg;
field = (DSQL_FLD) param_node [e_udf_param_field];
2002-06-29 08:56:51 +02:00
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_def_function_arg, (SSHORT) position);
2001-05-23 15:26:42 +02:00
2002-06-29 08:56:51 +02:00
if (param_node [e_udf_param_type]) {
2003-04-08 02:31:20 +02:00
SSHORT arg_mechanism = (SSHORT)(SLONG) (param_node [e_udf_param_type]->nod_arg [0]);
2002-06-29 08:56:51 +02:00
request->append_number(gds_dyn_func_mechanism, arg_mechanism);
}
else if (field->fld_dtype == dtype_blob) {
request->append_number(gds_dyn_func_mechanism,
(SSHORT) FUN_blob_struct);
}
else {
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_func_mechanism,
2001-05-23 15:26:42 +02:00
(SSHORT) FUN_reference);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
request->append_cstring(gds_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);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void define_update_action(
DSQL_REQ request,
2002-11-11 20:08:37 +01:00
DSQL_NOD * base_and_node, DSQL_NOD * base_relation)
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.
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD ddl_node, eql_node, and_node, old_and;
DSQL_NOD select_node, select_expr, from_list, relation_node;
DSQL_NOD fields_node, values_node, field_node, value_node, old_value_node;
DSQL_NOD *ptr, *end, *ptr2, *end2;
DSQL_NOD iand_node, or_node, anull_node, bnull_node;
2001-12-24 03:51:06 +01:00
DLLS field_stack;
2001-05-23 15:26:42 +02:00
DSQL_REL relation;
DSQL_FLD field;
2001-05-23 15:26:42 +02:00
SSHORT and_arg = 0;
ddl_node = request->req_ddl_node;
/* check whether this is an updatable view definition */
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;
/* use the relation referenced in the select statement for rse*/
relation_node = MAKE_node(nod_relation_name, (int) e_rln_count);
relation_node->nod_arg[e_rln_name] =
from_list->nod_arg[0]->nod_arg[e_rln_name];
2002-11-11 20:08:37 +01:00
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 */
values_node = ddl_node->nod_arg[e_view_fields];
if (!(fields_node = select_expr->nod_arg[e_sel_list]))
{
relation =
METD_get_relation(request,
reinterpret_cast<STR>(relation_node->nod_arg[e_rln_name]));
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] =
2002-11-11 20:08:37 +01:00
(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 */
ptr = fields_node->nod_arg;
end = ptr + fields_node->nod_count;
ptr2 = values_node->nod_arg;
end2 = ptr2 + values_node->nod_count;
field_stack = NULL;
and_node = MAKE_node(nod_and, (int) 2);
and_arg = 0;
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 comparisons */
if (field_node->nod_type == nod_field_name) {
field_node->nod_arg[e_fln_context] =
2002-11-11 20:08:37 +01:00
(DSQL_NOD) MAKE_cstring(TEMP_CONTEXT);
2001-05-23 15:26:42 +02:00
value_node = MAKE_node(nod_field_name, (int) e_fln_count);
value_node->nod_arg[e_fln_name] = (*ptr2)->nod_arg[e_fln_name];
value_node->nod_arg[e_fln_context] =
2002-11-11 20:08:37 +01:00
(DSQL_NOD) MAKE_cstring(NEW_CONTEXT);
2001-05-23 15:26:42 +02:00
old_value_node = MAKE_node(nod_field_name, (int) e_fln_count);
old_value_node->nod_arg[e_fln_name] =
(*ptr2)->nod_arg[e_fln_name];
old_value_node->nod_arg[e_fln_context] =
2002-11-11 20:08:37 +01:00
(DSQL_NOD) MAKE_cstring(OLD_CONTEXT);
2001-05-23 15:26:42 +02:00
eql_node = MAKE_node(nod_eql, (int) 2);
eql_node->nod_arg[0] = old_value_node;
eql_node->nod_arg[1] = field_node;
anull_node = MAKE_node(nod_missing, 1);
anull_node->nod_arg[0] = old_value_node;
bnull_node = MAKE_node(nod_missing, 1);
bnull_node->nod_arg[0] = field_node;
iand_node = MAKE_node(nod_and, (int) 2);
iand_node->nod_arg[0] = anull_node;
iand_node->nod_arg[1] = bnull_node;
or_node = MAKE_node(nod_or, (int) 2);
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 {
old_and = and_node;
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 {
old_and = and_node;
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,
DSQL_NOD element,
DSQL_NOD for_columns,
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
2001-05-23 15:26:42 +02:00
assert(prim_columns->nod_count == for_columns->nod_count);
assert(prim_columns->nod_count != 0);
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;
2002-11-11 20:08:37 +01:00
DSQL_NOD* for_key_flds = for_columns->nod_arg;
DSQL_NOD* prim_key_flds = prim_columns->nod_arg;
2001-05-23 15:26:42 +02:00
do {
2001-12-24 03:51:06 +01:00
STR for_key_fld_name_str = (STR) (*for_key_flds)->nod_arg[1];
STR prim_key_fld_name_str = (STR) (*prim_key_flds)->nod_arg[1];
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
request->append_uchar(gds_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.
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD node, select, select_expr, rse, field_node;
DSQL_NOD check, relation_node;
DSQL_NOD view_fields, *ptr, *end;
DSQL_NOD items, *i_ptr, *i_end;
2001-05-23 15:26:42 +02:00
DSQL_REL relation;
DSQL_FLD field;
DSQL_CTX context;
2001-05-23 15:26:42 +02:00
STR view_name, field_name, source;
SSHORT position;
bool updatable = true;
2001-05-23 15:26:42 +02:00
TEXT *field_string;
2001-12-24 03:51:06 +01:00
DLLS temp;
2001-05-23 15:26:42 +02:00
node = request->req_ddl_node;
view_name = (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)
{
request->append_cstring(gds_dyn_def_view,
view_name->str_data);
request->append_number(gds_dyn_rel_sql_protection, 1);
save_relation(request, view_name);
}
else // op == nod_mod_view
{
request->append_cstring(gds_dyn_mod_view,
view_name->str_data);
relation = METD_get_relation(request, view_name);
if (relation)
{
for (field = relation->rel_fields; field;
field = field->fld_next)
{
request->append_cstring(gds_dyn_delete_local_fld,
field->fld_name);
request->append_uchar(gds_dyn_end);
}
}
else
{
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) -607,
/* gds_arg_gds, gds__dsql_command_err,
gds_arg_gds, gds__dsql_view_not_found, */
gds_arg_gds, 336068783L,
gds_arg_string, view_name->str_data,
gds_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++;
select = node->nod_arg[e_view_select];
select_expr = select->nod_arg[0];
rse = PASS1_rse(request, select_expr, select->nod_arg[1], 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
2001-12-24 03:51:06 +01:00
request->begin_blr(gds_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. */
source = (STR) node->nod_arg[e_view_source];
assert(source->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_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*/
2003-08-15 01:34:37 +02:00
while (request->req_dt_context) {
context = reinterpret_cast<DSQL_CTX>(LLS_POP(&request->req_dt_context));
LLS_PUSH(context, &request->req_context);
}
2002-06-29 08:56:51 +02:00
while (request->req_union_context) {
context = reinterpret_cast<DSQL_CTX>(LLS_POP(&request->req_union_context));
LLS_PUSH(context, &request->req_context);
2002-06-29 08:56:51 +02:00
}
2001-12-24 03:51:06 +01:00
for (temp = request->req_context; temp; temp = temp->lls_next)
{
context = (DSQL_CTX) temp->lls_object;
2001-12-24 03:51:06 +01:00
if (relation = context->ctx_relation)
{
request->append_cstring(gds_dyn_view_relation, relation->rel_name);
request->append_number(gds_dyn_view_context, context->ctx_context);
request->append_cstring(gds_dyn_view_context_name,
2001-05-23 15:26:42 +02:00
context->ctx_alias ? context->ctx_alias : relation->
rel_name);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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 */
items = rse->nod_arg[e_rse_items];
i_ptr = items->nod_arg;
i_end = i_ptr + items->nod_count;
ptr = end = NULL;
if ((view_fields = node->nod_arg[e_view_fields]) != NULL) {
ptr = view_fields->nod_arg;
end = ptr + view_fields->nod_count;
}
/* 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 */
for (position = 0; i_ptr < i_end; i_ptr++, position++) {
field_node = *i_ptr;
/* check if this is a field or an expression */
field = NULL;
context = NULL;
if (field_node->nod_type == nod_field) {
field = (DSQL_FLD) field_node->nod_arg[e_fld_field];
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 */
if (!ptr && !field)
2001-12-24 03:51:06 +01:00
{
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_specify_field_err,
2001-05-23 15:26:42 +02:00
/* must specify field name for view select expression */
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-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)
{
field_name = (STR) (*ptr)->nod_arg[1];
field_string = (TEXT *) field_name->str_data;
}
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)
{
request->append_cstring(gds_dyn_def_local_fld, field_string);
request->append_cstring(gds_dyn_fld_base_fld, field->fld_name);
request->append_number(gds_dyn_view_context, context->ctx_context);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
else
{
request->append_cstring(gds_dyn_def_sql_fld, field_string);
2001-05-23 15:26:42 +02:00
MAKE_desc(&field_node->nod_desc, field_node);
put_descriptor(request, &field_node->nod_desc);
2001-12-24 03:51:06 +01:00
request->begin_blr(gds_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();
request->append_number(gds_dyn_view_context, (SSHORT) 0);
2001-05-23 15:26:42 +02:00
}
save_field(request, field_string);
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_fld_position, position);
request->append_uchar(gds_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(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_num_field_err,
2001-05-23 15:26:42 +02:00
/* number of fields does not match select list */
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
2001-12-24 03:51:06 +01:00
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(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_col_name_err,
2001-05-23 15:26:42 +02:00
/* Only simple column names permitted for VIEW WITH CHECK OPTION */
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(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_table_view_err,
2001-05-23 15:26:42 +02:00
/* Only one table allowed for VIEW WITH CHECK OPTION */
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(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_table_view_err,
2001-05-23 15:26:42 +02:00
/* Only one table allowed for VIEW WITH CHECK OPTION */
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(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_where_err,
2001-05-23 15:26:42 +02:00
/* No where clause for VIEW WITH CHECK OPTION */
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(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_distinct_err,
2001-05-23 15:26:42 +02:00
/* DISTINCT, GROUP or HAVING not permitted for VIEW WITH CHECK OPTION */
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
relation_node = MAKE_node(nod_relation_name, e_rln_count);
2002-11-11 20:08:37 +01:00
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;
2002-11-11 20:08:37 +01:00
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 */
create_view_triggers(request, check, rse->nod_arg[e_rse_items]);
}
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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)
2001-05-23 15:26:42 +02:00
{ /* The fields in VIEW actually */
/**************************************
*
* 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.
*
**************************************/
2001-12-24 03:51:06 +01:00
STR trigger_name, relation_name;
2002-11-11 20:08:37 +01:00
DSQL_NOD temp_rse, temp, ddl_node, actions, *ptr, *end, constant;
DSQL_NOD relation_node;
2001-05-23 15:26:42 +02:00
USHORT trig_type;
2002-11-11 20:08:37 +01:00
DSQL_NOD action_node, condition, select, select_expr, view_fields;
DSQL_CTX context, sav_context = 0;
2001-12-24 03:51:06 +01:00
DLLS stack;
2001-05-23 15:26:42 +02:00
TSQL tdsql;
tdsql = GET_THREAD_DATA;
ddl_node = request->req_ddl_node;
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
*/
select_expr = select->nod_arg[0]->nod_arg[0];
view_fields = ddl_node->nod_arg[e_view_fields];
/* 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;
trigger_name = (STR) node->nod_arg[e_cnstr_name];
2001-12-24 03:51:06 +01:00
if (node->nod_type == nod_def_constraint)
{
2001-05-23 15:26:42 +02:00
assert(trigger_name->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_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];
relation_name = (STR) relation_node->nod_arg[e_rln_name];
assert(relation_name->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_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
2001-12-24 03:51:06 +01:00
constant = node->nod_arg[e_cnstr_position];
if (constant)
{
request->append_number(gds_dyn_trg_sequence,
2003-04-08 02:31:20 +02:00
(SSHORT)(SLONG) (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];
if (constant)
{
2003-04-08 02:31:20 +02:00
trig_type = (USHORT)(ULONG) constant->nod_arg[0];
2001-12-24 03:51:06 +01:00
request->append_number(gds_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;
}
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_sql_object);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
STR message = (STR) node->nod_arg[e_cnstr_message];
if (message)
{
request->append_number(gds_dyn_def_trigger_msg, 0);
2001-05-23 15:26:42 +02:00
assert(message->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_dyn_trg_msg,
message->str_data,
message->str_length);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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])
{
request->begin_blr(gds_dyn_trg_blr);
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) {
/* If an alias is specified for the single base table involved,
save and then add the context */
stack = request->req_context;
context = (DSQL_CTX) stack->lls_object;
2001-05-23 15:26:42 +02:00
if (context->ctx_alias) {
sav_context = FB_NEW(*tdsql->tsql_default) dsql_ctx;
2001-05-23 15:26:42 +02:00
*sav_context = *context;
}
}
reset_context_stack(request);
temp = relation_node->nod_arg[e_rln_alias];
2002-11-11 20:08:37 +01: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);
2002-11-11 20:08:37 +01: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);
relation_node->nod_arg[e_rln_alias] = temp;
if (sav_context) {
sav_context->ctx_context = request->req_context_number++;
context->ctx_scope_level = request->req_scope_level;
LLS_PUSH(sav_context, &request->req_context);
}
if (trig_type == PRE_MODIFY_TRIGGER) {
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_for);
2001-05-23 15:26:42 +02:00
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);
condition = MAKE_node(nod_not, 1);
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) {
condition = MAKE_node(nod_not, 1);
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 */
actions = node->nod_arg[e_cnstr_actions];
for (ptr = actions->nod_arg, end = ptr + actions->nod_count;
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);
2001-05-23 15:26:42 +02:00
for (ptr = actions->nod_arg, end = ptr + actions->nod_count;
2001-12-24 03:51:06 +01:00
ptr < end; ptr++)
{
action_node = PASS1_statement(request, *ptr, false);
2001-12-24 03:51:06 +01:00
if (action_node->nod_type == nod_modify)
{
2001-05-23 15:26:42 +02:00
temp_rse = action_node->nod_arg[e_mod_rse];
temp_rse->nod_arg[e_rse_first] =
2003-09-01 09:39:54 +02:00
MAKE_constant((STR) 1, CONSTANT_SLONG);
2001-05-23 15:26:42 +02:00
}
GEN_statement(request, action_node);
}
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_end); /* of begin */
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
request->append_uchar(blr_end); /* of if */
if (trig_type == PRE_MODIFY_TRIGGER) {
request->append_uchar(blr_end); /* of for */
}
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);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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,
2002-11-11 20:08:37 +01:00
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().
*
**************************************/
STR string = (STR) node->nod_arg [e_prc_name];
assert (string);
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;
}
}
request->append_cstring(gds_dyn_delete_procedure, string->str_data);
2002-06-29 08:56:51 +02:00
request->append_uchar(gds_dyn_end);
}
static void delete_relation_view (
DSQL_REQ request,
2002-11-11 20:08:37 +01:00
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().
*
**************************************/
STR string = 0;
DSQL_REL relation = 0;
if (node->nod_type == nod_redef_relation) {
2002-11-11 20:08:37 +01:00
DSQL_NOD relation_node = node->nod_arg [e_alt_name];
2002-06-29 08:56:51 +02:00
assert (relation_node);
string = (STR) relation_node->nod_arg [e_rln_name];
}
else {
string = (STR) node->nod_arg [e_alt_name];
}
assert (string);
relation = METD_get_relation (request, string);
if (node->nod_type == nod_del_relation ||
node->nod_type == nod_redef_relation) {
if (!relation && !silent_deletion ||
relation && (relation->rel_flags & REL_view)) {
ERRD_post (gds_sqlerr, gds_arg_number, (SLONG) -607,
2002-06-29 08:56:51 +02:00
/* gds_arg_gds, gds__dsql_command_err,
gds_arg_gds, gds__dsql_table_not_found, */
gds_arg_gds, 336068783L,
gds_arg_string, string->str_data,
gds_arg_end);
}
}
else { /* node->nod_type == nod_del_view, nod_redef_view */
if (!relation && !silent_deletion ||
relation && !(relation->rel_flags & REL_view)) {
ERRD_post (gds_sqlerr, gds_arg_number, (SLONG) -607,
2002-06-29 08:56:51 +02:00
/* gds_arg_gds, gds__dsql_command_err,
gds_arg_gds, gds__dsql_view_not_found, */
gds_arg_gds, 336068783L,
gds_arg_string, string->str_data,
gds_arg_end);
}
}
if (relation) {
request->append_cstring(gds_dyn_delete_rel, string->str_data);
2002-06-29 08:56:51 +02:00
request->append_uchar(gds_dyn_end);
}
}
2001-12-24 03:51:06 +01:00
//
// Complete the stuffing of a piece of
// blr by going back and inserting the length.
//
void dsql_req::end_blr()
2001-05-23 15:26:42 +02:00
{
2001-12-24 03:51:06 +01:00
append_uchar(blr_eoc);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
// go back and stuff in the proper length
2001-05-23 15:26:42 +02:00
char* blr_base = req_blr_string->str_data + req_base_offset;
USHORT length = (SSHORT) (reinterpret_cast<char*>(req_blr) - blr_base) - 2;
2001-05-23 15:26:42 +02:00
*blr_base++ = (UCHAR) length;
*blr_base = (UCHAR) (length >> 8);
}
static void foreign_key( DSQL_REQ request, DSQL_NOD element, const char* index_name)
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.
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD relation2_node;
DSQL_NOD columns1, columns2;
2001-05-23 15:26:42 +02:00
STR relation2;
columns1 = element->nod_arg[e_for_columns];
relation2_node = element->nod_arg[e_for_reftable];
relation2 = (STR) relation2_node->nod_arg[e_rln_name];
/* If there is a referenced table name but no referenced field names, the
primary key of the referenced table designates the referenced fields. */
2001-12-24 03:51:06 +01:00
if (!(columns2 = element->nod_arg[e_for_refcolumns]))
{
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(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_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(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_key_field_count_err,
2001-05-23 15:26:42 +02:00
/* foreign key field count does not match primary key */
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.
*
**************************************/
STR string;
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-10-01 20:11:23 +02:00
stuff(request, gds_dyn_begin);
2003-10-05 08:33:56 +02:00
delete_relation_view(request, node, true); // silent.
define_relation (request);
2003-10-01 20:11:23 +02:00
stuff(request, gds_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-10-01 20:11:23 +02:00
stuff(request, gds_dyn_begin);
2003-10-05 08:33:56 +02:00
delete_relation_view(request, node, true); // silent.
define_view(request, node->nod_type);
2003-10-01 20:11:23 +02:00
stuff(request, gds_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-10-01 20:11:23 +02:00
stuff(request, gds_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);
stuff(request, gds_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:
string = (STR) node->nod_arg[0];
request->append_cstring(gds_dyn_delete_global_fld, string->str_data);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_del_index:
string = (STR) node->nod_arg[0];
request->append_cstring(gds_dyn_delete_idx, string->str_data);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
break;
2002-06-29 08:56:51 +02:00
/* CVC: Handling drop table and drop view properly. */
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:
string = (STR) node->nod_arg[0];
request->append_cstring(gds_dyn_delete_trigger, string->str_data);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_del_role:
string = (STR) node->nod_arg[0];
request->append_cstring(isc_dyn_del_sql_role, string->str_data);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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:
string = (STR) node->nod_arg[0];
request->append_cstring(isc_dyn_delete_generator, string->str_data);
2002-06-29 08:56:51 +02:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_del_filter:
string = (STR) node->nod_arg[0];
request->append_cstring(gds_dyn_delete_filter, string->str_data);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_def_udf:
define_udf(request);
break;
case nod_del_udf:
string = (STR) node->nod_arg[0];
request->append_cstring(gds_dyn_delete_function, string->str_data);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_def_shadow:
define_shadow(request);
break;
case nod_del_shadow:
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_delete_shadow,
2003-04-08 02:31:20 +02:00
(SSHORT)(SLONG) (node->nod_arg[0]));
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD* uptr;
DSQL_NOD* uend;
2001-12-24 03:51:06 +01:00
bool process_grant_role = false;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
SSHORT option = FALSE;
2002-11-11 20:08:37 +01:00
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
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]) {
option = TRUE;
}
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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
{
2002-11-11 20:08:37 +01:00
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]) {
2001-05-23 15:26:42 +02:00
option = 2;
2001-12-24 03:51:06 +01:00
}
request->append_uchar(isc_dyn_begin);
2002-11-11 20:08:37 +01:00
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
}
}
}
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void make_index( 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
*
**************************************
*
* 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
2001-12-24 03:51:06 +01:00
assert(element->nod_type != nod_foreign);
2001-05-23 15:26:42 +02:00
2002-11-11 20:08:37 +01:00
DSQL_NOD index = element->nod_arg[e_pri_index];
assert(index);
STR string = (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)
{
request->append_cstring(gds_dyn_def_primary_key, index_name);
}
else if (element->nod_type == nod_unique)
{
request->append_cstring(gds_dyn_def_unique, index_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
request->append_number(gds_dyn_idx_unique, 1);
2001-05-23 15:26:42 +02:00
if (index->nod_arg[e_idx_asc_dsc])
{
request->append_number(gds_dyn_idx_type, 1);
}
2002-11-11 20:08:37 +01:00
const DSQL_NOD* end = columns->nod_arg + columns->nod_count;
for (DSQL_NOD* ptr = columns->nod_arg; ptr < end; ++ptr)
2001-12-24 03:51:06 +01:00
{
STR field_name = (STR) (*ptr)->nod_arg[1];
request->append_cstring(gds_dyn_fld_name,
field_name->str_data);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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
2001-05-23 15:26:42 +02:00
assert(element->nod_type == nod_foreign)
/* 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];
STR for_rel_name_str = (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
2002-11-11 20:08:37 +01:00
DSQL_NOD index = element->nod_arg[e_for_index];
assert(index);
2001-05-23 15:26:42 +02:00
STR string = (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
}
request->append_cstring(gds_dyn_def_foreign_key, index_name);
2001-05-23 15:26:42 +02:00
if (index->nod_arg[e_idx_asc_dsc])
{
request->append_number(gds_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];
2001-05-23 15:26:42 +02:00
assert(nod_for_action->nod_type == nod_ref_upd_del);
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)
{
2001-05-23 15:26:42 +02:00
assert(nod_ref_upd_action->nod_type == nod_ref_trig_action);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_foreign_key_update);
switch (nod_ref_upd_action->nod_flags)
{
2001-05-23 15:26:42 +02:00
case REF_ACTION_CASCADE:
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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:
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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:
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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:
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_foreign_key_none);
2001-05-23 15:26:42 +02:00
break;
default:
assert(0);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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)
{
2001-05-23 15:26:42 +02:00
assert(nod_ref_del_action->nod_type == nod_ref_trig_action);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_foreign_key_delete);
2001-05-23 15:26:42 +02:00
switch (nod_ref_del_action->nod_flags) {
case REF_ACTION_CASCADE:
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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:
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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:
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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:
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_foreign_key_none);
2001-05-23 15:26:42 +02:00
break;
default:
assert(0);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_foreign_key_none); /* just in case */
2001-05-23 15:26:42 +02:00
break;
/* Error */
}
}
}
2002-11-11 20:08:37 +01:00
DSQL_NOD* ptr;
DSQL_NOD* end = columns->nod_arg + columns->nod_count;
2001-12-24 03:51:06 +01:00
for (ptr = columns->nod_arg; ptr < end; ++ptr)
{
STR field_name = (STR) (*ptr)->nod_arg[1];
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_fld_name,
field_name->str_data);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_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
{
end = referenced_columns->nod_arg + referenced_columns->nod_count;
for (ptr = referenced_columns->nod_arg; ptr < end; ++ptr)
{
STR field_name = (STR) (*ptr)->nod_arg[1];
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_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
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD ddl_node, element, *ptr;
2001-05-23 15:26:42 +02:00
SLONG start = 0;
FIL file;
SSHORT number = 0;
SLONG temp_long;
SSHORT temp_short;
bool drop_log = false;
bool drop_cache = false;
bool drop_difference = false;
2001-05-23 15:26:42 +02:00
ddl_node = request->req_ddl_node;
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_mod_database);
2001-05-23 15:26:42 +02:00
/*
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_rel_sql_protection, 1);
2001-05-23 15:26:42 +02:00
*/
2002-11-11 20:08:37 +01:00
DSQL_NOD elements = ddl_node->nod_arg[e_adb_all];
DSQL_NOD* end = elements->nod_arg + elements->nod_count;
2001-12-24 03:51:06 +01:00
for (ptr = elements->nod_arg; ptr < end; ptr++)
{
2001-05-23 15:26:42 +02:00
element = *ptr;
switch (element->nod_type) {
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) {
request->append_uchar(gds_dyn_drop_log);
}
if (drop_cache) {
request->append_uchar(gds_dyn_drop_cache);
}
if (drop_difference) {
request->append_uchar(isc_dyn_drop_difference);
}
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++)
{
2001-05-23 15:26:42 +02:00
element = *ptr;
switch (element->nod_type) {
case nod_file_desc:
file = (FIL) element->nod_arg[0];
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_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);
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
start += file->fil_length;
break;
case nod_log_file_desc:
file = (FIL) element->nod_arg[0];
if (file->fil_flags & LOG_default) {
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_def_default_log);
2001-05-23 15:26:42 +02:00
break;
}
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_def_log_file,
file->fil_name->str_data);
2001-12-24 03:51:06 +01:00
request->append_file_length(file->fil_length);
request->append_uchar(gds_dyn_log_file_sequence);
request->append_ushort_with_length(number);
2001-05-23 15:26:42 +02:00
number++;
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_log_file_partitions);
request->append_ushort_with_length(file->fil_partitions);
if (file->fil_flags & LOG_serial) {
request->append_uchar(gds_dyn_log_file_serial);
}
if (file->fil_flags & LOG_overflow) {
request->append_uchar(gds_dyn_log_file_overflow);
}
if (file->fil_flags & LOG_raw) {
request->append_uchar(gds_dyn_log_file_raw);
}
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_cache_file_desc:
file = (FIL) element->nod_arg[0];
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_def_cache_file,
file->fil_name->str_data);
2001-12-24 03:51:06 +01:00
request->append_file_length(file->fil_length);
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_group_commit_wait:
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_log_group_commit_wait);
2001-05-23 15:26:42 +02:00
temp_long = (SLONG) (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:
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_log_check_point_length);
2001-05-23 15:26:42 +02:00
temp_long = (SLONG) (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:
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_log_num_of_buffers);
2003-04-08 02:31:20 +02:00
temp_short = (SSHORT)(SLONG) (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:
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_log_buffer_size);
2003-04-08 02:31:20 +02:00
temp_short = (SSHORT)(SLONG) (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,
((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;
2001-05-23 15:26:42 +02:00
case nod_drop_log:
case nod_drop_cache:
break;
default:
break;
}
}
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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.
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD ddl_node, domain_node, ops, element, *ptr, *end;
2001-05-23 15:26:42 +02:00
STR string, domain_name;
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
ddl_node = request->req_ddl_node;
domain_node = ddl_node->nod_arg[e_alt_dom_name];
domain_name = (STR) domain_node->nod_arg[e_fln_name];
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_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)); */
USHORT rtop = FB_NELEM(repetition_count);
USHORT *p = repetition_count;
while (p < repetition_count + rtop) {
*p++ = 0;
}
2002-06-29 08:56:51 +02:00
2001-05-23 15:26:42 +02:00
ops = ddl_node->nod_arg[e_alt_dom_ops];
for (ptr = ops->nod_arg, end = ptr + ops->nod_count; ptr < end; ptr++)
{
element = *ptr;
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
{
2001-12-24 03:51:06 +01:00
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) -104,
gds_arg_gds, gds_command_end_err, /* Unexpected end of command */
0);
2001-05-23 15:26:42 +02:00
}
/* CVC End modification. */
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
request->begin_blr(gds_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();
string = (STR) element->nod_arg[e_dft_default_source];
if (string)
{
2001-05-23 15:26:42 +02:00
assert(string->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_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");
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_single_validation);
request->begin_blr(gds_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(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_dsql_domain_not_found,
2002-06-29 08:56:51 +02:00
gds_arg_string, domain_name->str_data,
2001-05-23 15:26:42 +02:00
/* Specified domain or source field does not exist */
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
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();
2001-05-23 15:26:42 +02:00
if ((string = (STR) element->nod_arg[e_cnstr_source]) != NULL) {
assert(string->str_length <= MAX_USHORT);
2001-12-24 03:51:06 +01:00
request->append_string( gds_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
2001-05-23 15:26:42 +02:00
STR new_dom_name;
new_dom_name = (STR) element->nod_arg[e_fln_name];
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_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");
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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");
request->append_uchar(gds_dyn_del_default);
2001-05-23 15:26:42 +02:00
break;
default:
break;
}
}
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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)
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD ddl_node, index_node;
2001-05-23 15:26:42 +02:00
STR index_name;
ddl_node = request->req_ddl_node;
index_node = ddl_node->nod_arg[e_alt_index];
index_name = (STR) index_node->nod_arg[e_alt_idx_name];
request->append_cstring(gds_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) {
request->append_number(gds_dyn_idx_inactive, 0);
} else if (index_node->nod_type == nod_idx_inactive) {
request->append_number(gds_dyn_idx_inactive, 1);
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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,
UCHAR* privs,
2002-11-11 20:08:37 +01:00
DSQL_NOD table,
DSQL_NOD user,
2001-12-24 03:51:06 +01:00
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) {
request->append_uchar(gds_dyn_grant);
} else {
request->append_uchar(gds_dyn_revoke);
}
2001-05-23 15:26:42 +02:00
/* stuff the privileges string */
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;
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);
STR name = (STR) table->nod_arg[0];
if (table->nod_type == nod_procedure_name) {
request->append_cstring(gds_dyn_prc_name, name->str_data);
} else {
request->append_cstring(gds_dyn_rel_name, name->str_data);
}
2001-05-23 15:26:42 +02:00
name = (STR) user->nod_arg[0];
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 {
request->append_cstring(gds_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:
request->append_cstring(gds_dyn_grant_proc, name->str_data);
2001-05-23 15:26:42 +02:00
break;
case nod_trig_obj:
request->append_cstring(gds_dyn_grant_trig, name->str_data);
2001-05-23 15:26:42 +02:00
break;
case nod_view_obj:
request->append_cstring(gds_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) {
request->append_cstring(gds_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))))
{
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_grant_options, option);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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,
2002-11-11 20:08:37 +01:00
DSQL_NOD privs,
DSQL_NOD table,
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];
SCHAR* p;
2002-11-11 20:08:37 +01:00
DSQL_NOD fields, *ptr, *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:
2001-07-12 07:46:06 +02:00
p = (privs->nod_type == nod_references) ? (SCHAR*) "R" : (SCHAR*) "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<UCHAR*>(p), table, user,
reinterpret_cast<STR>((*ptr)->nod_arg[1]));
}
2001-05-23 15:26:42 +02:00
return 0;
case nod_delete:
return 'D';
case nod_list:
p = privileges;
for (ptr = privs->nod_arg, end = ptr + privs->nod_count; ptr < end;
ptr++)
{
*p = modify_privileges(request, type, option, *ptr, table,
user);
if (*p) {
p++;
}
}
2001-05-23 15:26:42 +02:00
*p = 0;
p = privileges;
break;
default:
break;
}
if (*p) {
modify_privilege( request,
type,
option,
reinterpret_cast<UCHAR*>(p),
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
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD ddl_node, ops, element, *ptr, *end, relation_node, field_node;
2001-05-23 15:26:42 +02:00
STR relation_name, field_name;
TSQL tdsql;
tdsql = GET_THREAD_DATA;
ddl_node = request->req_ddl_node;
relation_node = ddl_node->nod_arg[e_alt_name];
relation_name = (STR) relation_node->nod_arg[e_rln_name];
request->append_cstring(gds_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
ops = ddl_node->nod_arg[e_alt_ops];
for (ptr = ops->nod_arg, end = ptr + ops->nod_count; ptr < end; ptr++) {
element = *ptr;
switch (element->nod_type) {
case nod_mod_field_name:
{
2002-11-11 20:08:37 +01:00
DSQL_NOD old_field, new_field;
2001-05-23 15:26:42 +02:00
STR old_field_name, new_field_name;
old_field = element->nod_arg[e_mod_fld_name_orig_name];
old_field_name = (STR) old_field->nod_arg[e_fln_name];
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_mod_local_fld,
old_field_name->str_data);
2001-05-23 15:26:42 +02:00
new_field = element->nod_arg[e_mod_fld_name_new_name];
new_field_name = (STR) new_field->nod_arg[e_fln_name];
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_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);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
break;
}
case nod_mod_field_pos:
{
SSHORT constant;
2002-11-11 20:08:37 +01:00
DSQL_NOD const_node;
2001-05-23 15:26:42 +02:00
field_node = element->nod_arg[e_mod_fld_pos_orig_name];
field_name = (STR) field_node->nod_arg[e_fln_name];
request->append_cstring(gds_dyn_mod_local_fld, field_name->str_data);
2001-05-23 15:26:42 +02:00
const_node = element->nod_arg[e_mod_fld_pos_new_position];
2002-06-29 08:56:51 +02:00
/* CVC: Since now the parser accepts pos=1..N, let's subtract one here. */
2003-04-08 02:31:20 +02:00
constant = (SSHORT)(SLONG) const_node->nod_arg [0] - 1;
2002-06-29 08:56:51 +02:00
2001-12-24 03:51:06 +01:00
request->append_cstring(gds_dyn_rel_name,
relation_name->str_data);
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_fld_position, constant);
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
break;
}
case nod_mod_field_type:
modify_field(request, element, (SSHORT) - 1, relation_name);
break;
case nod_def_field:
define_field(request, element, (SSHORT) - 1, relation_name);
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];
field_name = (STR) field_node->nod_arg[e_fln_name];
if ((element->nod_arg[1])->nod_type == nod_cascade)
2001-12-24 03:51:06 +01:00
{
2001-05-23 15:26:42 +02:00
/* Unsupported DSQL construct */
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) -901,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_dsql_construct_err, 0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
assert((element->nod_arg[1])->nod_type == nod_restrict);
request->append_cstring(gds_dyn_delete_local_fld, field_name->str_data);
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
break;
case nod_delete_rel_constraint:
field_name = (STR) element->nod_arg[0];
request->append_cstring(gds_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;
}
}
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_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;
2001-12-29 12:41:29 +01:00
Firebird::status_exception::raise(tdsql->tsql_status[1]);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
static void process_role_nm_list( DSQL_REQ request,
2001-12-24 03:51:06 +01:00
SSHORT option,
2002-11-11 20:08:37 +01:00
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
*
**************************************/
STR role_nm, user_nm;
2001-12-24 03:51:06 +01:00
if (type == nod_grant) {
request->append_uchar(isc_dyn_grant);
} else {
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
role_nm = (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
user_nm = (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
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void put_descriptor(DSQL_REQ request, 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.
*
**************************************/
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_fld_type, blr_dtypes[desc->dsc_dtype]);
if (desc->dsc_dtype == dtype_varying) {
request->append_number(gds_dyn_fld_length,
2001-05-23 15:26:42 +02:00
(SSHORT) (desc->dsc_length - sizeof(USHORT)));
2001-12-24 03:51:06 +01:00
} else {
request->append_number(gds_dyn_fld_length, desc->dsc_length);
}
request->append_number(gds_dyn_fld_scale, desc->dsc_scale);
request->append_number(gds_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 */
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 {
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.
*
**************************************/
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_fld_type, blr_dtypes[field->fld_dtype]);
if (field->fld_dtype == dtype_blob)
{
request->append_number(gds_dyn_fld_sub_type, field->fld_sub_type);
request->append_number(gds_dyn_fld_scale, 0);
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
}
request->append_number(gds_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 == BLOB_text) {
request->append_number(gds_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) {
request->append_number(gds_dyn_fld_sub_type, field->fld_sub_type);
}
request->append_number(gds_dyn_fld_scale, 0);
if (field->fld_dtype == dtype_varying)
{
2002-06-29 08:56:51 +02:00
/* CVC: Fix the assertion */
assert((field->fld_length) <= MAX_SSHORT);
2001-12-24 03:51:06 +01:00
request->append_number(gds_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
{
request->append_number(gds_dyn_fld_length, field->fld_length);
}
if (!(request->req_dbb->dbb_flags & DBB_v3))
{
request->append_number(gds_dyn_fld_char_length,
2001-05-23 15:26:42 +02:00
field->fld_character_length);
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_fld_character_set,
2001-05-23 15:26:42 +02:00
field->fld_character_set_id);
if (!udf_flag)
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_fld_collation,
2001-05-23 15:26:42 +02:00
field->fld_collation_id);
}
}
else {
2001-12-24 03:51:06 +01:00
request->append_number(gds_dyn_fld_scale, field->fld_scale);
request->append_number(gds_dyn_fld_length, field->fld_length);
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
}
}
}
static void put_local_variable( DSQL_REQ request, 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);
2002-11-11 20:08:37 +01:00
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 SSHORT put_local_variables(DSQL_REQ request, DSQL_NOD parameters, 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)
{
2002-11-11 20:08:37 +01:00
DSQL_NOD* ptr = parameters->nod_arg;
for (DSQL_NOD* end = ptr + parameters->nod_count; ptr < end; ptr++)
2001-12-24 03:51:06 +01:00
{
2002-11-11 20:08:37 +01:00
DSQL_NOD parameter = *ptr;
DSQL_FLD field = (DSQL_FLD) parameter->nod_arg[e_dfl_field];
2002-11-11 20:08:37 +01:00
DSQL_NOD* rest = ptr;
2001-12-24 03:51:06 +01:00
while ((++rest) != end)
{
DSQL_FLD rest_field = (DSQL_FLD) (*rest)->nod_arg[e_dfl_field];
2001-05-23 15:26:42 +02:00
if (!strcmp(field->fld_name, rest_field->fld_name))
2001-12-24 03:51:06 +01:00
{
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) -637,
gds_arg_gds, gds_dsql_duplicate_spec,
2001-05-23 15:26:42 +02:00
gds_arg_string, field->fld_name, 0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
2002-11-11 20:08:37 +01:00
DSQL_NOD var_node =
2001-05-23 15:26:42 +02:00
MAKE_variable(field, field->fld_name, VAR_output, 0, 0,
locals);
2001-12-24 03:51:06 +01:00
*ptr = var_node;
VAR variable = (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;
2001-05-23 15:26:42 +02:00
locals++;
}
}
return locals;
}
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
}
void dsql_req::append_number(UCHAR verb, SSHORT number)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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.
*
**************************************/
2001-12-24 03:51:06 +01:00
if (verb) {
append_uchar(verb);
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
append_ushort_with_length(number);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
//
// Write out a string valued attribute.
//
void dsql_req::append_cstring(UCHAR verb, const char* string)
2001-05-23 15:26:42 +02:00
{
2001-12-24 03:51:06 +01:00
const USHORT length = string ? strlen(string) : 0;
append_string(verb, string, length);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
//
// Write out a string valued attribute.
//
void dsql_req::append_string(UCHAR verb, const char* string, USHORT length)
2001-05-23 15:26:42 +02:00
{
2001-12-24 03:51:06 +01:00
// TMN: Doesn't this look pretty awkward? If we are given
// a verb, the length is a ushort, else it's uchar.
2001-05-23 15:26:42 +02:00
if (verb) {
2001-12-24 03:51:06 +01:00
append_uchar(verb);
append_ushort(length);
}
else {
append_uchar(length);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
if (string) {
for (; *string && length--; string++) {
append_uchar(*string);
}
}
2001-05-23 15:26:42 +02:00
}
2002-11-11 20:08:37 +01: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
{
/* *************************************
*
* 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
2002-11-11 20:08:37 +01:00
const DSQL_NOD* endo = input->nod_arg + input->nod_count;
2001-05-23 15:26:42 +02:00
2002-11-11 20:08:37 +01: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(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_subquery_err,
2001-05-23 15:26:42 +02:00
/* No subqueries permitted for VIEW WITH CHECK OPTION */
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
2001-12-24 03:51:06 +01:00
STR field_name = (STR) (*ptr)->nod_arg[e_fln_name];
2002-11-11 20:08:37 +01:00
DSQL_NOD* search = search_fields->nod_arg;
DSQL_NOD* end = search + search_fields->nod_count;
DSQL_NOD* replace;
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)
{
STR replace_name;
2001-05-23 15:26:42 +02:00
if (replace_fields) {
replace_name = (STR) (*replace)->nod_arg[e_fln_name];
}
2002-11-11 20:08:37 +01: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
}
2002-11-11 20:08:37 +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.
*
**************************************/
2001-12-24 03:51:06 +01:00
while (request->req_context) {
2001-05-23 15:26:42 +02:00
LLS_POP(&request->req_context);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
request->req_context_number = 0;
}
static void save_field(DSQL_REQ request, 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.
*
**************************************/
2001-12-24 03:51:06 +01:00
TSQL tdsql = GET_THREAD_DATA;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
DSQL_REL relation = request->req_relation;
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->tsql_default, 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;
}
static void save_relation( DSQL_REQ request, 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.
*
**************************************/
2001-12-24 03:51:06 +01:00
TSQL tdsql = 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
2002-11-11 20:08:37 +01:00
DSQL_NOD ddl_node = request->req_ddl_node;
2001-12-24 03:51:06 +01:00
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->tsql_default, 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
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD ddl_node;
2001-05-23 15:26:42 +02:00
STR index_name;
ddl_node = request->req_ddl_node;
index_name = (STR) ddl_node->nod_arg[e_stat_name];
request->append_cstring(gds_dyn_mod_idx, index_name->str_data);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_idx_statistic);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void stuff_default_blr( DSQL_REQ request,
2001-12-24 03:51:06 +01:00
TEXT* default_buff,
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.
*
*********************************************/
unsigned int i;
assert((*default_buff == blr_version4)
|| (*default_buff == blr_version5));
2001-12-24 03:51:06 +01:00
for (i = 1; ((i < buff_size) && (default_buff[i] != blr_eoc)); i++) {
request->append_uchar(default_buff[i]);
}
2001-05-23 15:26:42 +02:00
assert(default_buff[i] == blr_eoc);
}
static void stuff_matching_blr(DSQL_REQ request, DSQL_NOD for_columns, 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 */
assert(prim_columns->nod_count == for_columns->nod_count);
assert(prim_columns->nod_count != 0);
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;
2002-11-11 20:08:37 +01:00
DSQL_NOD* for_key_flds = for_columns->nod_arg;
DSQL_NOD* 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);
STR for_key_fld_name_str = (STR) (*for_key_flds)->nod_arg[1];
STR prim_key_fld_name_str = (STR) (*prim_key_flds)->nod_arg[1];
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, 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;
2002-11-11 20:08:37 +01:00
DSQL_NOD* 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
2001-12-24 03:51:06 +01:00
STR prim_key_fld_name_str = (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,
2002-11-11 20:08:37 +01:00
DSQL_NOD element,
2001-12-24 03:51:06 +01:00
SSHORT position,
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.
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD domain_node;
DSQL_FLD field;
2001-05-23 15:26:42 +02:00
DSQL_REL relation;
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
if ((relation = request->req_relation) != NULL)
{
2001-05-23 15:26:42 +02:00
field->fld_next = relation->rel_fields;
relation->rel_fields = field;
}
2001-12-24 03:51:06 +01:00
if (domain_node = element->nod_arg[e_mod_fld_type_dom_name])
{
2002-11-11 20:08:37 +01:00
DSQL_NOD node1;
2001-05-23 15:26:42 +02:00
STR domain_name;
node1 = domain_node->nod_arg[e_dom_name];
domain_name = (STR) node1->nod_arg[e_fln_name];
request->append_cstring(gds_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(gds_sqlerr, gds_arg_number, (SLONG) -607,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_dsql_domain_not_found,
2001-05-23 15:26:42 +02:00
/* Specified domain or source field does not exist */
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) {
request->append_cstring(gds_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
}
2001-12-24 03:51:06 +01:00
request->append_uchar(gds_dyn_end);
2001-05-23 15:26:42 +02:00
}
static void set_nod_value_attributes( DSQL_NOD node, 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
*
**************************************/
ULONG child_number;
2001-12-24 03:51:06 +01:00
for (child_number = 0; child_number < node->nod_count; ++child_number)
{
2002-11-11 20:08:37 +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)
{
2001-05-23 15:26:42 +02:00
assert(field->fld_dtype <= MAX_UCHAR);
child->nod_desc.dsc_dtype = (UCHAR) field->fld_dtype;
child->nod_desc.dsc_length = field->fld_length;
assert(field->fld_scale <= MAX_SCHAR);
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 */
} /* for (child_number ... */
return;
}
void dsql_req::append_uchar(UCHAR byte)
2001-12-24 03:51:06 +01:00
{
if (req_blr < req_blr_yellow) {
*req_blr++ = byte;
} else {
GEN_expand_buffer(this, byte);
}
}
void dsql_req::append_uchars(UCHAR byte, UCHAR count)
2001-12-24 03:51:06 +01:00
{
for (int i=0; i< count ; ++i) {
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
{
append_uchar(gds_dyn_file_length);
append_ulong_with_length(length);
}
void dsql_req::append_file_start(ULONG start)
2001-12-24 03:51:06 +01:00
{
append_uchar(gds_dyn_file_start);
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,
dsql_nod* prim_columns,
const char* for_rel_name,
dsql_nod* for_columns)
2001-12-24 03:51:06 +01:00
{
// no trigger name. It is generated by the engine
append_string(gds_dyn_def_trigger, "", 0);
append_number(gds_dyn_trg_type,
(SSHORT) (on_update_trigger ? POST_MODIFY_TRIGGER :
POST_ERASE_TRIGGER));
append_uchar(gds_dyn_sql_object);
append_number(gds_dyn_trg_sequence, 1);
append_number(gds_dyn_trg_inactive, 0);
append_cstring(gds_dyn_rel_name, prim_rel_name);
// the trigger blr
begin_blr(gds_dyn_trg_blr);
/* 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);
}