2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: Dynamic SQL runtime support
|
|
|
|
* MODULE: ddl.c
|
|
|
|
* 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): ______________________________________.
|
|
|
|
*
|
2002-04-04 07:35:21 +02:00
|
|
|
* $Id: ddl.cpp,v 1.7 2002-04-04 05:35:21 bellardo 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-10 19:35:13 +02:00
|
|
|
*
|
|
|
|
* 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++
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
2001-07-30 01:43:24 +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 "../dsql/node.h"
|
2001-07-30 01:43:24 +02:00
|
|
|
#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"
|
2001-07-30 01:43:24 +02:00
|
|
|
#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"
|
|
|
|
|
|
|
|
#if defined(DEBUG) && !(defined REQUESTER && defined SUPERCLIENT)
|
|
|
|
#include "../gpre/prett_proto.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
} // extern "C"
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#define BLOB_BUFFER_SIZE 4096 /* to read in blr blob for default values */
|
|
|
|
|
|
|
|
static USHORT check_array_or_blob(NOD);
|
|
|
|
static void check_constraint(REQ, NOD, SSHORT);
|
|
|
|
static void create_view_triggers(REQ, NOD, NOD);
|
|
|
|
static void define_computed(REQ, NOD, FLD, NOD);
|
|
|
|
static void define_constraint_trigger(REQ, NOD);
|
|
|
|
static void define_database(REQ);
|
|
|
|
static void define_del_cascade_trg(REQ, NOD, NOD, NOD, TEXT *, TEXT *);
|
2001-12-24 03:51:06 +01:00
|
|
|
//static void define_del_default_trg(REQ, NOD, NOD, NOD, TEXT *, TEXT *);
|
2001-05-23 15:26:42 +02:00
|
|
|
static void define_dimensions(REQ, FLD);
|
|
|
|
static void define_domain(REQ);
|
|
|
|
static void define_exception(REQ, NOD_TYPE);
|
|
|
|
static void define_field(REQ, NOD, SSHORT, STR);
|
|
|
|
static void define_filter(REQ);
|
|
|
|
static void define_generator(REQ);
|
|
|
|
static void define_role(REQ);
|
|
|
|
static void define_index(REQ);
|
|
|
|
static NOD define_insert_action(REQ);
|
|
|
|
static void define_procedure(REQ, NOD_TYPE);
|
|
|
|
static void define_rel_constraint(REQ, NOD);
|
|
|
|
static void define_relation(REQ);
|
2001-12-24 03:51:06 +01:00
|
|
|
static void define_set_null_trg(REQ, NOD, NOD, NOD, TEXT*, TEXT*, bool);
|
|
|
|
static void define_set_default_trg(REQ, NOD, NOD, NOD, TEXT*, TEXT*, bool);
|
2001-05-23 15:26:42 +02:00
|
|
|
static void define_shadow(REQ);
|
|
|
|
static void define_trigger(REQ, NOD);
|
|
|
|
static void define_udf(REQ);
|
|
|
|
static void define_update_action(REQ, NOD *, NOD *);
|
|
|
|
static void define_upd_cascade_trg(REQ, NOD, NOD, NOD, TEXT *, TEXT *);
|
|
|
|
static void define_view(REQ);
|
|
|
|
static void define_view_trigger(REQ, NOD, NOD, NOD);
|
|
|
|
static void foreign_key(REQ, NOD);
|
|
|
|
static void generate_dyn(REQ, NOD);
|
|
|
|
static void grant_revoke(REQ);
|
|
|
|
static void make_index(REQ, NOD, NOD, NOD, SCHAR *);
|
|
|
|
static void make_index_trg_ref_int(REQ, NOD, NOD, NOD, SCHAR *);
|
|
|
|
static void modify_database(REQ);
|
|
|
|
static void modify_domain(REQ);
|
|
|
|
static void modify_field(REQ, NOD, SSHORT, STR);
|
|
|
|
static void modify_index(REQ);
|
|
|
|
static void modify_privilege(REQ, NOD_TYPE, SSHORT, UCHAR *, NOD, NOD, STR);
|
|
|
|
static void process_role_nm_list(REQ, SSHORT, NOD, NOD, NOD_TYPE);
|
|
|
|
static SCHAR modify_privileges(REQ, NOD_TYPE, SSHORT, NOD, NOD, NOD);
|
|
|
|
static void modify_relation(REQ);
|
|
|
|
static void put_descriptor(REQ, DSC *);
|
|
|
|
static void put_dtype(REQ, FLD, USHORT);
|
|
|
|
static void put_field(REQ, FLD, BOOLEAN);
|
|
|
|
static void put_local_variable(REQ, VAR);
|
|
|
|
static SSHORT put_local_variables(REQ, NOD, SSHORT);
|
|
|
|
static void put_msg_field(REQ, FLD);
|
|
|
|
static NOD replace_field_names(NOD, NOD, NOD, SSHORT);
|
|
|
|
static void reset_context_stack(REQ);
|
|
|
|
static void save_field(REQ, SCHAR *);
|
|
|
|
static void save_relation(REQ, STR);
|
|
|
|
static void set_statistics(REQ);
|
|
|
|
static void stuff_default_blr(REQ, TEXT *, USHORT);
|
|
|
|
static void stuff_matching_blr(REQ, NOD, NOD);
|
|
|
|
static void stuff_trg_firing_cond(REQ, NOD);
|
|
|
|
static void set_nod_value_attributes(NOD, FLD);
|
|
|
|
|
|
|
|
#ifdef BLKCHK
|
|
|
|
#undef BLKCHK
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef DEV_BUILD
|
2001-12-24 03:51:06 +01:00
|
|
|
static inline void BLKCHK(const void* p, USHORT type)
|
|
|
|
{
|
|
|
|
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
|
|
|
|
#define BLKCHK(blk, typ)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define PRE_STORE_TRIGGER 1
|
|
|
|
#define POST_STORE_TRIGGER 2
|
|
|
|
#define PRE_MODIFY_TRIGGER 3
|
|
|
|
#define POST_MODIFY_TRIGGER 4
|
|
|
|
#define PRE_ERASE_TRIGGER 5
|
|
|
|
#define POST_ERASE_TRIGGER 6
|
|
|
|
|
|
|
|
#define OLD_CONTEXT "OLD"
|
|
|
|
#define NEW_CONTEXT "NEW"
|
|
|
|
#define TEMP_CONTEXT "TEMP"
|
|
|
|
|
|
|
|
#define DEFAULT_BUFFER 2048
|
|
|
|
|
|
|
|
#define DEFAULT_BLOB_SEGMENT_SIZE 80 /* bytes */
|
|
|
|
|
|
|
|
|
|
|
|
static CONST USHORT blr_dtypes[] = {
|
|
|
|
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 */
|
|
|
|
};
|
|
|
|
|
|
|
|
static CONST UCHAR nonnull_validation_blr[] = {
|
|
|
|
blr_version5,
|
|
|
|
blr_not,
|
|
|
|
blr_missing,
|
|
|
|
blr_fid, 0, 0, 0,
|
|
|
|
blr_eoc
|
|
|
|
};
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
ASSERT_FILENAME
|
|
|
|
|
|
|
|
void DDL_execute(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
|
2001-07-10 19:35:13 +02:00
|
|
|
* to interpret dyn string and perform
|
2001-05-23 15:26:42 +02:00
|
|
|
* metadata updates.
|
|
|
|
*
|
|
|
|
**************************************/
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
STR string;
|
|
|
|
STATUS s;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
TSQL tdsql = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
#if !(defined REQUESTER && defined SUPERCLIENT)
|
|
|
|
if (DSQL_debug > 0)
|
2001-12-24 03:51:06 +01:00
|
|
|
PRETTY_print_dyn(reinterpret_cast<char*>(
|
|
|
|
request->req_blr_string->str_data),
|
|
|
|
NULL,
|
|
|
|
"%4d %s\n",
|
|
|
|
NULL);
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT length = request->req_blr - request->req_blr_string->str_data;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
THREAD_EXIT;
|
|
|
|
|
|
|
|
s = isc_ddl(GDS_VAL(tdsql->tsql_status),
|
2001-12-24 03:51:06 +01:00
|
|
|
reinterpret_cast<void**>(GDS_REF(request->req_dbb->dbb_database_handle)),
|
|
|
|
reinterpret_cast<void**>(GDS_REF(request->req_trans)),
|
2001-05-23 15:26:42 +02:00
|
|
|
length,
|
2001-12-24 03:51:06 +01:00
|
|
|
reinterpret_cast<char*>(GDS_VAL(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
|
|
|
|
|
|
|
if ((request->req_ddl_node->nod_type == nod_mod_relation) ||
|
2001-12-24 03:51:06 +01:00
|
|
|
(request->req_ddl_node->nod_type == nod_del_relation))
|
|
|
|
{
|
|
|
|
if (request->req_ddl_node->nod_type == nod_mod_relation)
|
|
|
|
{
|
|
|
|
NOD relation_node = request->req_ddl_node->nod_arg[e_alt_name];
|
2001-05-23 15:26:42 +02:00
|
|
|
string = (STR) relation_node->nod_arg[e_rln_name];
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
else {
|
2001-05-23 15:26:42 +02:00
|
|
|
string = (STR) request->req_ddl_node->nod_arg[e_alt_name];
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
METD_drop_relation(request, string);
|
|
|
|
}
|
|
|
|
|
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) ||
|
2001-12-24 03:51:06 +01:00
|
|
|
(request->req_ddl_node->nod_type == nod_del_procedure))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
string = (STR) request->req_ddl_node->nod_arg[e_prc_name];
|
|
|
|
METD_drop_procedure(request, string);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
void DDL_generate(REQ request, 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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
int DDL_ids(REQ request)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* D D L _ i d s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Determine whether ids or names should be
|
|
|
|
* referenced when generating blr for fields
|
|
|
|
* and relations.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD ddl_node = request->req_ddl_node;
|
|
|
|
|
|
|
|
if (!ddl_node) {
|
2001-05-23 15:26:42 +02:00
|
|
|
return TRUE;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (ddl_node->nod_type == nod_def_view ||
|
|
|
|
ddl_node->nod_type == nod_def_constraint ||
|
|
|
|
ddl_node->nod_type == nod_def_trigger ||
|
|
|
|
ddl_node->nod_type == nod_mod_trigger ||
|
|
|
|
ddl_node->nod_type == nod_def_procedure ||
|
|
|
|
ddl_node->nod_type == nod_def_computed ||
|
2001-12-24 03:51:06 +01:00
|
|
|
ddl_node->nod_type == nod_mod_procedure)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
void DDL_put_field_dtype(REQ request, FLD field, USHORT use_subtype)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2001-07-10 19:35:13 +02:00
|
|
|
* D D L _ p u t _ f i e l d _ d t y p e
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Emit blr that describes a descriptor.
|
|
|
|
* Note that this depends on the same STUFF variant
|
|
|
|
* as used in gen.c
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
put_dtype(request, field, use_subtype);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DDL_resolve_intl_type( REQ request, FLD field, STR collation_name)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* D D L _ r e s o l v e _ i n t l _ t y p e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
|
|
|
* If the field is defined with a character set or collation,
|
|
|
|
* resolve the names to a subtype now.
|
|
|
|
*
|
|
|
|
* Also resolve the field length & whatnot.
|
|
|
|
*
|
|
|
|
* 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;
|
|
|
|
ULONG field_length;
|
|
|
|
|
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
|
|
|
{
|
2001-07-30 01:43:24 +02: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),
|
2001-07-12 07:46:06 +02:00
|
|
|
(UCHAR *)("RDB$FIELD_SUB_TYPE"),
|
2001-05-23 15:26:42 +02:00
|
|
|
&blob_sub_type))
|
|
|
|
{
|
2001-07-30 01:43:24 +02:00
|
|
|
ERRD_post( gds_sqlerr,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_number,
|
|
|
|
(SLONG) - 204,
|
|
|
|
gds_arg_gds,
|
2001-07-30 01:43:24 +02:00
|
|
|
gds_dsql_datatype_err,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_gds,
|
2001-07-30 01:43:24 +02:00
|
|
|
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))
|
|
|
|
{
|
2001-07-30 01:43:24 +02:00
|
|
|
ERRD_post( gds_sqlerr,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_number,
|
|
|
|
(SLONG) - 204,
|
|
|
|
gds_arg_gds,
|
2001-07-30 01:43:24 +02:00
|
|
|
gds_dsql_datatype_err,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_gds,
|
2001-07-30 01:43:24 +02:00
|
|
|
gds_collation_requires_text,
|
2001-05-23 15:26:42 +02:00
|
|
|
0);
|
|
|
|
}
|
|
|
|
if (collation_name)
|
|
|
|
{
|
2001-07-30 01:43:24 +02:00
|
|
|
ERRD_post( gds_sqlerr,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_number,
|
|
|
|
(SLONG) - 204,
|
|
|
|
gds_arg_gds,
|
2001-07-30 01:43:24 +02:00
|
|
|
gds_dsql_datatype_err,
|
2001-05-23 15:26:42 +02:00
|
|
|
gds_arg_gds,
|
2001-07-30 01:43:24 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
field->fld_character_set = (NOD) dfl_charset;
|
|
|
|
}
|
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.
|
|
|
|
*/
|
2001-12-24 03:51:06 +01:00
|
|
|
if (field->fld_character_length)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
field_length = field->fld_character_length;
|
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
|
|
|
{
|
2001-07-30 01:43:24 +02: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;
|
|
|
|
};
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
UCHAR* charset_name;
|
|
|
|
|
|
|
|
if (field->fld_flags & FLD_national) {
|
2001-05-23 15:26:42 +02:00
|
|
|
charset_name = (UCHAR *) NATIONAL_CHARACTER_SET;
|
2001-12-24 03:51:06 +01:00
|
|
|
} else if (field->fld_character_set) {
|
2001-05-23 15:26:42 +02:00
|
|
|
charset_name = (UCHAR *) ((STR) field->fld_character_set)->str_data;
|
2001-12-24 03:51:06 +01:00
|
|
|
} else {
|
2001-05-23 15:26:42 +02:00
|
|
|
charset_name = (UCHAR *) NULL;
|
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,
|
2001-12-24 03:51:06 +01:00
|
|
|
(USHORT) strlen(reinterpret_cast<char*>(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
|
2001-07-30 01:43:24 +02:00
|
|
|
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
|
2001-07-30 01:43:24 +02:00
|
|
|
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
|
|
|
{
|
2001-07-30 01:43:24 +02: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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (field->fld_character_length)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
field_length = (ULONG) resolved_type->intlsym_bytes_per_char *
|
|
|
|
field->fld_character_length;
|
|
|
|
|
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
|
|
|
{
|
2001-07-30 01:43:24 +02: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;
|
|
|
|
};
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
field->fld_ttype = resolved_type->intlsym_ttype;
|
2001-05-23 15:26:42 +02:00
|
|
|
field->fld_character_set_id = resolved_type->intlsym_charset_id;
|
2001-12-24 03:51:06 +01:00
|
|
|
field->fld_collation_id = resolved_type->intlsym_collate_id;
|
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 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
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
req_base_offset = req_blr - 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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static USHORT check_array_or_blob(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
|
2001-07-10 19:35:13 +02:00
|
|
|
* 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:
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case nod_map:
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
|
|
|
MAP map = (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
|
|
|
{
|
|
|
|
FLD fld = (FLD) node->nod_arg[e_cast_target];
|
|
|
|
if ((fld->fld_dtype == dtype_blob) || (fld->fld_dtype == dtype_array)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
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])) {
|
2001-05-23 15:26:42 +02:00
|
|
|
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)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
return TRUE;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
// parameters to UDF don't need checking,
|
|
|
|
// an blob or array can be passed
|
2001-05-23 15:26:42 +02:00
|
|
|
return FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case nod_extract:
|
|
|
|
case nod_list:
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
|
|
|
const NOD* end = node->nod_arg + node->nod_count;
|
|
|
|
for (NOD* ptr = node->nod_arg; ptr < end; ++ptr)
|
|
|
|
{
|
|
|
|
if (check_array_or_blob(*ptr)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
return TRUE;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
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
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
return TRUE;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert(FALSE);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void check_constraint( REQ request,
|
|
|
|
NOD element,
|
|
|
|
SSHORT 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.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD ddl_node = request->req_ddl_node;
|
|
|
|
|
|
|
|
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
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD list_node = MAKE_node(nod_list, (int) 1);
|
|
|
|
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
|
|
|
|
|
|
|
NOD* errorcode_node = &list_node->nod_arg[0]->nod_arg[0];
|
2001-05-23 15:26:42 +02:00
|
|
|
*errorcode_node = (NOD) MAKE_cstring("check_constraint");
|
|
|
|
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] =
|
|
|
|
// (NOD) MAKE_cstring ("insert violates CHECK constraint on table");
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
element->nod_arg[e_cnstr_type] =
|
|
|
|
MAKE_constant((STR) PRE_STORE_TRIGGER, 1);
|
|
|
|
define_constraint_trigger(request, element);
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
// create the UPDATE trigger
|
|
|
|
|
|
|
|
// element->nod_arg [e_cnstr_message] =
|
|
|
|
// (NOD) MAKE_cstring ("update violates CHECK constraint on table");
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
element->nod_arg[e_cnstr_type] =
|
|
|
|
MAKE_constant((STR) PRE_MODIFY_TRIGGER, 1);
|
|
|
|
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] =
|
|
|
|
// (NOD) MAKE_cstring ("delete violates CHECK constraint on table");
|
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
element->nod_arg[e_cnstr_type] =
|
|
|
|
MAKE_constant((STR) PRE_ERASE_TRIGGER, 1);
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void create_view_triggers(REQ request, NOD element, NOD items)
|
2001-05-23 15:26:42 +02:00
|
|
|
{ /* Fields in the VIEW actually */
|
|
|
|
/* *************************************
|
|
|
|
*
|
2001-07-10 19:35:13 +02:00
|
|
|
* c r e a t e _ v i e w _ t r i g g e r s
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
|
|
|
* Generate triggers to implement the WITH CHECK OPTION
|
|
|
|
* clause for a VIEW
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD temp, base_relation, base_and_node;
|
|
|
|
|
|
|
|
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
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD list_node = MAKE_node(nod_list, (int) 1);
|
|
|
|
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
|
|
|
|
|
|
|
NOD* errorcode_node = &list_node->nod_arg[0]->nod_arg[0];
|
2001-05-23 15:26:42 +02:00
|
|
|
*errorcode_node = (NOD) MAKE_cstring("check_constraint");
|
|
|
|
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] =
|
|
|
|
// (NOD) MAKE_cstring ("update violates CHECK constraint on view");
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
element->nod_arg[e_cnstr_type] =
|
|
|
|
MAKE_constant((STR) PRE_MODIFY_TRIGGER, 1);
|
|
|
|
define_update_action(request, &base_and_node, &base_relation);
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
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] =
|
|
|
|
// (NOD) MAKE_cstring ("insert violates CHECK constraint on view");
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
element->nod_arg[e_cnstr_type] =
|
|
|
|
MAKE_constant((STR) PRE_STORE_TRIGGER, 1);
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void define_computed(REQ request,
|
|
|
|
NOD relation_node,
|
|
|
|
FLD field,
|
|
|
|
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
|
2001-07-10 19:35:13 +02:00
|
|
|
* Create the ddl to define a computed field
|
|
|
|
* or an expression index.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
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);
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD input = PASS1_node(request, node->nod_arg[e_cmp_expr], 0);
|
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
|
|
|
{
|
2001-07-30 01:43:24 +02: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,
|
|
|
|
reinterpret_cast<char*>(source->str_data),
|
|
|
|
(USHORT) source->str_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void define_constraint_trigger(REQ request, NOD node)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
/* make the "define trigger" node the current request ddl node so
|
|
|
|
that generating of BLR will be appropriate for trigger */
|
|
|
|
|
|
|
|
NOD ddl_node = request->req_ddl_node;
|
|
|
|
|
|
|
|
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,
|
|
|
|
reinterpret_cast<char*>(trigger_name->str_data),
|
|
|
|
(USHORT) trigger_name->str_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
NOD relation_node = node->nod_arg[e_cnstr_table];
|
|
|
|
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,
|
|
|
|
reinterpret_cast<char*>(relation_name->str_data),
|
|
|
|
(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,
|
|
|
|
reinterpret_cast<char*>(source->str_data),
|
|
|
|
(USHORT) source->str_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD constant = node->nod_arg[e_cnstr_position];
|
|
|
|
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,
|
2001-05-23 15:26:42 +02:00
|
|
|
(SSHORT) (constant ? constant->nod_arg[0] : 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((constant = node->nod_arg[e_cnstr_type]) != NULL)
|
|
|
|
{
|
|
|
|
const SSHORT type = (SSHORT) 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,
|
|
|
|
reinterpret_cast<char*>(message->str_data),
|
|
|
|
(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);
|
|
|
|
}
|
|
|
|
relation_node->nod_arg[e_rln_alias] = (NOD) MAKE_cstring(OLD_CONTEXT);
|
|
|
|
PASS1_make_context(request, relation_node);
|
|
|
|
relation_node->nod_arg[e_rln_alias] = (NOD) MAKE_cstring(NEW_CONTEXT);
|
|
|
|
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,
|
|
|
|
PASS1_node(request, node->nod_arg[e_cnstr_condition], 0));
|
|
|
|
|
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
|
|
|
|
NOD actions = node->nod_arg[e_cnstr_actions];
|
|
|
|
NOD* ptr;
|
|
|
|
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, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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, 0));
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
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( REQ request)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e f i n e _ d a t a b a s e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
2001-07-10 19:35:13 +02:00
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
NOD ddl_node, elements, element, *ptr, *end;
|
|
|
|
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_file_desc:
|
|
|
|
file = (FIL) element->nod_arg[0];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_def_file,
|
|
|
|
reinterpret_cast<char*>(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,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast <
|
|
|
|
char *>(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,
|
|
|
|
reinterpret_cast<char*>(file->fil_name->str_data));
|
|
|
|
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);
|
2001-05-23 15:26:42 +02:00
|
|
|
temp_short = (SSHORT) (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);
|
2001-05-23 15:26:42 +02:00
|
|
|
temp_short = (SSHORT) (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,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(name->str_data));
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void define_del_cascade_trg( REQ request,
|
|
|
|
NOD element,
|
|
|
|
NOD for_columns,
|
|
|
|
NOD prim_columns,
|
|
|
|
TEXT* prim_rel_name,
|
|
|
|
TEXT* 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
|
|
|
|
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
|
|
|
static void define_set_default_trg( REQ request,
|
|
|
|
NOD element,
|
|
|
|
NOD for_columns,
|
|
|
|
NOD prim_columns,
|
|
|
|
TEXT* prim_rel_name,
|
|
|
|
TEXT* 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
|
2001-07-10 19:35:13 +02:00
|
|
|
* define "on delete|update set default" trigger (for
|
2001-05-23 15:26:42 +02:00
|
|
|
* referential integrity) along with its blr
|
|
|
|
*
|
|
|
|
*****************************************************/
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
UCHAR 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;
|
|
|
|
NOD* for_key_flds = for_columns->nod_arg;
|
|
|
|
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
|
2001-07-10 19:35:13 +02:00
|
|
|
default value from the system tables by calling:
|
2001-05-23 15:26:42 +02:00
|
|
|
METD_get_col_default(). */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
BOOLEAN found_default = FALSE;
|
|
|
|
bool search_for_default = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* search the parse tree to find the column */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD elem = ddl_node->nod_arg[e_drl_elements];
|
|
|
|
NOD* end = elem->nod_arg + elem->nod_count;
|
|
|
|
for (NOD* ptr = elem->nod_arg; ptr < end; ++ptr)
|
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
|
|
|
FLD field = (FLD) elem->nod_arg[e_dfl_field];
|
|
|
|
if (strcmp(field->fld_name,
|
|
|
|
reinterpret_cast<char*>(for_key_fld_name_str->str_data)))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Now, we have the right column in the parse tree. case (1) above */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD default_node = elem->nod_arg[e_dfl_default];
|
|
|
|
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;
|
|
|
|
NOD domain_node;
|
|
|
|
NOD tmp_node;
|
|
|
|
|
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 =
|
2001-12-24 03:51:06 +01:00
|
|
|
reinterpret_cast<char*>(domain_name_str->str_data)))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-10 19:35:13 +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,
|
2001-12-24 03:51:06 +01:00
|
|
|
reinterpret_cast<char*>(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
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
stuff_default_blr(request,
|
|
|
|
reinterpret_cast<char*>(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,
|
2001-12-24 03:51:06 +01:00
|
|
|
reinterpret_cast<char*>(for_key_fld_name_str->str_data),
|
2001-05-23 15:26:42 +02:00
|
|
|
&found_default,
|
|
|
|
reinterpret_cast<char*>(default_val),
|
|
|
|
sizeof(default_val));
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (found_default) {
|
2001-05-23 15:26:42 +02:00
|
|
|
stuff_default_blr(request,
|
|
|
|
reinterpret_cast<char*>(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,
|
|
|
|
reinterpret_cast<char*>(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();
|
|
|
|
|
|
|
|
// 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( REQ request, FLD field)
|
|
|
|
{
|
|
|
|
/*****************************************
|
|
|
|
*
|
|
|
|
* d e f i n e _ d i m e n s i o n s
|
|
|
|
*
|
|
|
|
*****************************************
|
|
|
|
*
|
|
|
|
* Function
|
2001-07-10 19:35:13 +02:00
|
|
|
* Define dimensions of an array
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD elements = field->fld_ranges;
|
|
|
|
USHORT dims = elements->nod_count / 2;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (dims > MAX_ARRAY_DIMENSIONS)
|
|
|
|
{
|
2001-07-30 01:43:24 +02:00
|
|
|
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;
|
|
|
|
NOD* ptr = elements->nod_arg;
|
|
|
|
NOD* end = ptr + elements->nod_count;
|
|
|
|
for (; ptr < end; ++ptr, ++position)
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_number(gds_dyn_def_dimension, position);
|
|
|
|
NOD element = *ptr++;
|
|
|
|
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)
|
|
|
|
{
|
2001-07-30 01:43:24 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void define_domain(REQ request)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e f i n e _ d o m a i n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
2001-07-10 19:35:13 +02:00
|
|
|
* 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
|
|
|
|
|
|
|
NOD element = request->req_ddl_node;
|
|
|
|
FLD field = (FLD) element->nod_arg[e_dom_name];
|
|
|
|
|
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-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
|
|
|
NOD node = element->nod_arg[e_dom_default];
|
2001-05-23 15:26:42 +02:00
|
|
|
if (node)
|
|
|
|
{
|
|
|
|
node = PASS1_node(request, node, 0);
|
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,
|
|
|
|
reinterpret_cast<char*>(string->str_data),
|
|
|
|
(USHORT) 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)
|
|
|
|
{
|
|
|
|
NOD* ptr = node->nod_arg;
|
|
|
|
NOD* end_ptr = ptr + node->nod_count;
|
|
|
|
for (; ptr < end_ptr; ++ptr)
|
|
|
|
{
|
|
|
|
if ((*ptr)->nod_type == nod_rel_constraint)
|
|
|
|
{
|
|
|
|
NOD node1 = (*ptr)->nod_arg[e_rct_type];
|
|
|
|
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
|
|
|
|
{
|
2001-07-30 01:43:24 +02: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, "NOT NULL", 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (node1->nod_type == nod_def_constraint)
|
|
|
|
{
|
|
|
|
if (check_flag)
|
|
|
|
{
|
2001-07-30 01:43:24 +02: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, "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,
|
|
|
|
reinterpret_cast<char*>(string->str_data),
|
|
|
|
(USHORT) 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],
|
|
|
|
0));
|
|
|
|
|
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( REQ request, NOD_TYPE op)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e f i n e _ e x c e p t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
|
|
|
* Generate ddl to create an exception code.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
NOD ddl_node;
|
|
|
|
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)
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_def_exception,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(name->str_data));
|
|
|
|
else if (op == nod_mod_exception)
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_mod_exception,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(name->str_data));
|
|
|
|
else
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_del_exception,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(name->str_data));
|
|
|
|
|
|
|
|
if (op != nod_del_exception) {
|
|
|
|
assert(text->str_length <= MAX_USHORT);
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_string( gds_dyn_xcp_msg,
|
|
|
|
reinterpret_cast<char*>(text->str_data),
|
|
|
|
(USHORT) text->str_length);
|
|
|
|
request->append_uchar(gds_dyn_end);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void define_field(
|
|
|
|
REQ request,
|
|
|
|
NOD element, SSHORT position, STR relation_name)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
**************************************/
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD domain_node, node, node1, *ptr;
|
2001-05-23 15:26:42 +02:00
|
|
|
FLD field;
|
|
|
|
DSQL_REL relation;
|
|
|
|
STR string, domain_name;
|
|
|
|
USHORT cnstrt_flag = FALSE;
|
|
|
|
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 = (FLD) element->nod_arg[e_dfl_field];
|
|
|
|
|
|
|
|
/* 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];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_fld_source,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(domain_name->str_data));
|
|
|
|
|
|
|
|
/* Get the domain information */
|
|
|
|
|
|
|
|
if (!(METD_get_domain(request, field, domain_name->str_data)))
|
2001-07-30 01:43:24 +02:00
|
|
|
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);
|
|
|
|
|
|
|
|
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,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
node = PASS1_node(request, node, 0);
|
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,
|
|
|
|
reinterpret_cast<char*>(string->str_data),
|
|
|
|
(USHORT) 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])
|
|
|
|
{
|
|
|
|
NOD* end_ptr = node->nod_arg + node->nod_count;
|
|
|
|
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)
|
|
|
|
{
|
2001-07-30 01:43:24 +02:00
|
|
|
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);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (cnstrt_flag == FALSE) {
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_uchar(gds_dyn_end); /* For field definition */
|
2001-05-23 15:26:42 +02:00
|
|
|
cnstrt_flag = TRUE;
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_rel_constraint,
|
|
|
|
reinterpret_cast<char*>((string) ?
|
|
|
|
string->str_data : NULL));
|
|
|
|
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 == FALSE)
|
|
|
|
{
|
|
|
|
request->append_uchar(gds_dyn_end); /* For field definition */
|
2001-05-23 15:26:42 +02:00
|
|
|
cnstrt_flag = TRUE;
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_rel_constraint,
|
|
|
|
reinterpret_cast<char*>((string) ? string->str_data : NULL));
|
|
|
|
if (node1->nod_type == nod_primary) {
|
|
|
|
request->append_uchar(gds_dyn_def_primary_key);
|
|
|
|
} else if (node1->nod_type == nod_unique) {
|
|
|
|
request->append_uchar(gds_dyn_def_unique);
|
|
|
|
}
|
|
|
|
request->append_ushort(0); /* So index name is generated */
|
|
|
|
request->append_number(gds_dyn_idx_unique, 1);
|
|
|
|
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 == FALSE) {
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_uchar(gds_dyn_end); /* For field definition */
|
2001-05-23 15:26:42 +02:00
|
|
|
cnstrt_flag = TRUE;
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_rel_constraint,
|
|
|
|
reinterpret_cast<char*>((string) ? string->str_data : NULL));
|
2001-05-23 15:26:42 +02:00
|
|
|
foreign_key(request, node1);
|
|
|
|
}
|
|
|
|
else if (node1->nod_type == nod_def_constraint) {
|
|
|
|
if (cnstrt_flag == FALSE) {
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_uchar(gds_dyn_end); /* For field definition */
|
2001-05-23 15:26:42 +02:00
|
|
|
cnstrt_flag = TRUE;
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_rel_constraint,
|
|
|
|
reinterpret_cast<char*>((string) ? string->str_data : NULL));
|
2001-05-23 15:26:42 +02:00
|
|
|
check_constraint(request, node1,
|
|
|
|
FALSE /* No delete trigger */ );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (cnstrt_flag == FALSE) {
|
|
|
|
request->append_uchar(gds_dyn_end);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void define_filter( REQ request)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e f i n e _ f i l t e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
|
|
|
* define a filter to the database.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
NOD *ptr, filter_node;
|
|
|
|
|
|
|
|
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,
|
|
|
|
reinterpret_cast<char*>(((STR) (ptr[e_filter_name]))->str_data));
|
|
|
|
request->append_number(gds_dyn_filter_in_subtype,
|
2001-05-23 15:26:42 +02:00
|
|
|
(SSHORT) ((ptr[e_filter_in_type])->nod_arg[0]));
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_number(gds_dyn_filter_out_subtype,
|
2001-05-23 15:26:42 +02:00
|
|
|
(SSHORT) ((ptr[e_filter_out_type])->nod_arg[0]));
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_func_entry_point,
|
|
|
|
reinterpret_cast<char*>(((STR) (ptr[e_filter_entry_pt]))->str_data));
|
|
|
|
request->append_cstring(gds_dyn_func_module_name,
|
|
|
|
reinterpret_cast<char*>(((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( REQ request)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void define_index(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.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
NOD ddl_node, relation_node, field_list, *ptr, *end;
|
|
|
|
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;
|
|
|
|
relation_node = (NOD) ddl_node->nod_arg[e_idx_table];
|
|
|
|
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];
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_def_idx,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(index_name->str_data));
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_rel_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(relation_name->str_data));
|
|
|
|
|
2001-07-10 19:35:13 +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,
|
|
|
|
reinterpret_cast<char*>(((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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static NOD define_insert_action( REQ request)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e f i n e _ i n s e r t _ a c t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
2001-07-10 19:35:13 +02:00
|
|
|
* Define an action statement which, given a view
|
2001-05-23 15:26:42 +02:00
|
|
|
* definition, will store a record from
|
2001-07-10 19:35:13 +02:00
|
|
|
* a view of a single relation into the
|
2001-05-23 15:26:42 +02:00
|
|
|
* base relation.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
NOD ddl_node, action_node, insert_node;
|
|
|
|
NOD select_node, select_expr, from_list, relation_node;
|
|
|
|
NOD fields_node, values_node, field_node, value_node;
|
|
|
|
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;
|
|
|
|
FLD field;
|
|
|
|
|
|
|
|
ddl_node = request->req_ddl_node;
|
|
|
|
|
|
|
|
/* check whether this is an updatable view definition */
|
|
|
|
|
|
|
|
if (ddl_node->nod_type != nod_def_view ||
|
|
|
|
!(select_node = ddl_node->nod_arg[e_view_select]) ||
|
2001-07-10 19:35:13 +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_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];
|
|
|
|
relation_node->nod_arg[e_rln_alias] = (NOD) MAKE_cstring(TEMP_CONTEXT);
|
|
|
|
|
2001-07-10 19:35:13 +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);
|
|
|
|
field_node->nod_arg[e_fln_name] = (NOD)MAKE_cstring(field->fld_name);
|
|
|
|
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] =
|
|
|
|
(NOD) MAKE_cstring(TEMP_CONTEXT);
|
|
|
|
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] =
|
|
|
|
(NOD) MAKE_cstring(NEW_CONTEXT);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void define_procedure( REQ request, NOD_TYPE op)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e f i n e _ p r o c e d u r e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
|
|
|
* Create DYN to store a procedure
|
|
|
|
*
|
|
|
|
**************************************/
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD parameters, parameter, *ptr, *end;
|
2001-05-23 15:26:42 +02:00
|
|
|
PRC procedure;
|
|
|
|
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;
|
|
|
|
NOD procedure_node = request->req_ddl_node;
|
|
|
|
STR procedure_name = (STR) procedure_node->nod_arg[e_prc_name];
|
|
|
|
|
|
|
|
if (op == nod_def_procedure)
|
|
|
|
{
|
|
|
|
request->append_cstring(gds_dyn_def_procedure,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
request->append_cstring(gds_dyn_mod_procedure,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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,
|
|
|
|
reinterpret_cast<char*>(source->str_data),
|
|
|
|
(USHORT) source->str_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Fill req_procedure to allow procedure to self reference */
|
2001-12-24 03:51:06 +01:00
|
|
|
procedure = new(*tdsql->tsql_default,
|
|
|
|
strlen(reinterpret_cast<char*>(procedure_name->str_data))) 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 = (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, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
DDL_resolve_intl_type(request, field, NULL);
|
|
|
|
put_field(request, field, FALSE);
|
|
|
|
|
|
|
|
*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 = (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);
|
|
|
|
|
|
|
|
*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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2001-05-23 15:26:42 +02:00
|
|
|
request->req_loop_number = 1;
|
|
|
|
GEN_statement(request,
|
|
|
|
PASS1_statement(request,
|
|
|
|
procedure_node->nod_arg[e_prc_body], 1));
|
|
|
|
request->req_type = REQ_DDL;
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_uchar(blr_end);
|
2001-05-23 15:26:42 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void define_rel_constraint( REQ request, NOD element)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2001-07-10 19:35:13 +02:00
|
|
|
* d e f i n e _ r e l _ c o n s t r a i n t
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
|
|
|
* Define a constraint , either as part of a create
|
|
|
|
* table or an alter table statement.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
NOD node;
|
|
|
|
STR string;
|
|
|
|
|
|
|
|
string = (STR) element->nod_arg[e_rct_name];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_rel_constraint,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast <
|
|
|
|
char *>((string) ? string->str_data : NULL));
|
|
|
|
node = element->nod_arg[e_rct_type];
|
|
|
|
|
|
|
|
if (node->nod_type == nod_unique || node->nod_type == nod_primary)
|
|
|
|
make_index(request, node, node->nod_arg[0], 0, 0);
|
|
|
|
else if (node->nod_type == nod_foreign)
|
|
|
|
foreign_key(request, node);
|
|
|
|
else if (node->nod_type == nod_def_constraint)
|
|
|
|
check_constraint(request, node, FALSE /* No delete trigger */ );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void define_relation( REQ request)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e f i n e _ r e l a t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
|
|
|
* Create an SQL table, relying on DYN to generate
|
2001-07-10 19:35:13 +02:00
|
|
|
* global fields for the local fields.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
NOD ddl_node, elements, element, *ptr, *end, relation_node;
|
|
|
|
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];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_def_rel,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(relation_name->str_data));
|
|
|
|
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,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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(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,
|
|
|
|
reinterpret_cast<char*>(gen_name->str_data));
|
|
|
|
request->append_uchar(gds_dyn_end);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void define_set_null_trg(REQ request,
|
|
|
|
NOD element,
|
|
|
|
NOD for_columns,
|
|
|
|
NOD prim_columns,
|
|
|
|
TEXT* prim_rel_name,
|
|
|
|
TEXT* 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;
|
|
|
|
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,
|
|
|
|
reinterpret_cast<char*>(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
|
|
|
|
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(REQ request)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD shadow_node = request->req_ddl_node;
|
|
|
|
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
|
|
|
{
|
2001-07-30 01:43:24 +02: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
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_number(gds_dyn_def_shadow, (SSHORT) (ptr[e_shadow_number]));
|
|
|
|
request->append_cstring(gds_dyn_def_file,
|
|
|
|
reinterpret_cast<char*>(((STR) (ptr[e_shadow_name]))->str_data));
|
|
|
|
request->append_number(gds_dyn_shadow_man_auto,
|
2001-05-23 15:26:42 +02:00
|
|
|
(SSHORT) ((ptr[e_shadow_man_auto])->nod_arg[0]));
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_number(gds_dyn_shadow_conditional,
|
2001-05-23 15:26:42 +02:00
|
|
|
(SSHORT) ((ptr[e_shadow_conditional])->nod_arg[0]));
|
|
|
|
|
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);
|
|
|
|
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
|
|
|
{
|
|
|
|
NOD* end = elements->nod_arg + elements->nod_count;
|
|
|
|
for (ptr = elements->nod_arg; ptr < end; ++ptr)
|
|
|
|
{
|
|
|
|
NOD element = *ptr;
|
|
|
|
FIL file = (FIL) element->nod_arg[0];
|
|
|
|
request->append_cstring(gds_dyn_def_file,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(file->fil_name->str_data));
|
|
|
|
|
|
|
|
if (!length && !file->fil_start)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-07-30 01:43:24 +02: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.
|
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
static void define_trigger( REQ request, NOD node)
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
STR relation_name;
|
|
|
|
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
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (node->nod_type == nod_def_trigger)
|
|
|
|
{
|
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,
|
|
|
|
reinterpret_cast<char*>(trigger_name->str_data),
|
|
|
|
(USHORT) 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,
|
|
|
|
reinterpret_cast<char*>(relation_name->str_data),
|
|
|
|
(USHORT) relation_name->str_length);
|
|
|
|
request->append_uchar(gds_dyn_sql_object);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
else
|
|
|
|
{ /* if (node->nod_type == 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,
|
|
|
|
reinterpret_cast<char*>(trigger_name->str_data),
|
|
|
|
(USHORT) trigger_name->str_length);
|
|
|
|
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)
|
|
|
|
{
|
2001-07-30 01:43:24 +02:00
|
|
|
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 = new(*tdsql->tsql_default, e_rln_count) 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;
|
|
|
|
relation_node->nod_arg[e_rln_name] = (NOD) relation_name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
STR source = (STR) node->nod_arg[e_trg_source];
|
|
|
|
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,
|
|
|
|
reinterpret_cast<char*>(source->str_data),
|
|
|
|
(USHORT) 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,
|
2001-05-23 15:26:42 +02:00
|
|
|
(SSHORT) constant->nod_arg[0]);
|
|
|
|
|
|
|
|
if (constant = node->nod_arg[e_trg_position])
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_number(gds_dyn_trg_sequence,
|
2001-05-23 15:26:42 +02:00
|
|
|
(SSHORT) constant->nod_arg[0]);
|
|
|
|
|
|
|
|
if (constant = node->nod_arg[e_trg_type]) {
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_number(gds_dyn_trg_type, (SSHORT) constant->nod_arg[0]);
|
2001-05-23 15:26:42 +02:00
|
|
|
trig_type = (USHORT) constant->nod_arg[0];
|
|
|
|
}
|
|
|
|
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 ((trig_type != PRE_STORE_TRIGGER)
|
|
|
|
&& (trig_type != POST_STORE_TRIGGER)) {
|
|
|
|
relation_node->nod_arg[e_rln_alias] =
|
|
|
|
(NOD) MAKE_cstring(OLD_CONTEXT);
|
|
|
|
PASS1_make_context(request, relation_node);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
request->req_context_number++;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (trig_type != PRE_ERASE_TRIGGER && trig_type != POST_ERASE_TRIGGER)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
relation_node->nod_arg[e_rln_alias] =
|
|
|
|
(NOD) MAKE_cstring(NEW_CONTEXT);
|
|
|
|
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++;
|
|
|
|
GEN_statement(request, PASS1_statement(request, actions, 1));
|
|
|
|
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
|
|
|
{
|
|
|
|
NOD* end = temp->nod_arg + temp->nod_count;
|
|
|
|
for (NOD* ptr = temp->nod_arg; ptr < end; ++ptr)
|
|
|
|
{
|
|
|
|
NOD message = *ptr;
|
|
|
|
SSHORT number = (SSHORT) message->nod_arg[e_msg_number];
|
|
|
|
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,
|
|
|
|
reinterpret_cast<char*>(message_text->str_data),
|
|
|
|
(USHORT) message_text->str_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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void define_udf( REQ request)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e f i n e _ u d f
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
|
|
|
* define a udf to the database.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
NOD *ptr, *end, *ret_val_ptr, arguments, udf_node;
|
|
|
|
UCHAR *udf_name;
|
|
|
|
FLD field;
|
|
|
|
SSHORT position, blob_position;
|
|
|
|
|
|
|
|
udf_node = request->req_ddl_node;
|
|
|
|
arguments = udf_node->nod_arg[e_udf_args];
|
|
|
|
ptr = udf_node->nod_arg;
|
|
|
|
udf_name = ((STR) (ptr[e_udf_name]))->str_data;
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_def_function,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(udf_name));
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_func_entry_point,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast <
|
|
|
|
char *>(((STR) (ptr[e_udf_entry_pt]))->str_data));
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_func_module_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast <
|
|
|
|
char *>(((STR) (ptr[e_udf_module]))->str_data));
|
|
|
|
|
|
|
|
ret_val_ptr = ptr[e_udf_return_value]->nod_arg;
|
|
|
|
|
|
|
|
|
|
|
|
if (field = (FLD) ret_val_ptr[0]) {
|
|
|
|
|
|
|
|
/* Some data types can not be returned as value */
|
|
|
|
|
|
|
|
if (((int) (ret_val_ptr[1]->nod_arg[0]) == FUN_value) &&
|
|
|
|
(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
|
|
|
{
|
2001-07-30 01:43:24 +02: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
|
|
|
{
|
2001-07-30 01:43:24 +02: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 {
|
|
|
|
position = (SSHORT) (ret_val_ptr[1]->nod_arg[0]);
|
|
|
|
/* Function modifies an argument whose value is the function return value */
|
|
|
|
|
|
|
|
if (!arguments || position > arguments->nod_count || position < 1)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-07-30 01:43:24 +02: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 */
|
|
|
|
/* 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)
|
|
|
|
{
|
|
|
|
if (field->fld_dtype == dtype_blob)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
BOOLEAN free_it = ((SSHORT) 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,
|
2001-05-23 15:26:42 +02:00
|
|
|
(SSHORT) ((free_it ? -1 : 1) * FUN_blob_struct));
|
|
|
|
/* 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,
|
2001-05-23 15:26:42 +02:00
|
|
|
(SSHORT) (ret_val_ptr[1]->nod_arg[0]));
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_function_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(udf_name));
|
|
|
|
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);
|
|
|
|
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
|
|
|
{
|
2001-07-30 01:43:24 +02: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 = (FLD) * ptr;
|
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
|
|
|
|
|
|
|
if (field->fld_dtype == dtype_blob)
|
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_blob_struct);
|
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
|
|
|
{
|
|
|
|
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
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_function_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(udf_name));
|
|
|
|
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(
|
|
|
|
REQ request,
|
|
|
|
NOD * base_and_node, NOD * base_relation)
|
|
|
|
{
|
|
|
|
/* *************************************
|
|
|
|
*
|
|
|
|
* d e f i n e _ u p d a t e _ a c t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
2001-07-10 19:35:13 +02:00
|
|
|
* 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
|
2001-07-10 19:35:13 +02:00
|
|
|
* a view of a single relation into the
|
2001-05-23 15:26:42 +02:00
|
|
|
* base relation.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
NOD ddl_node, eql_node, and_node, old_and;
|
|
|
|
NOD select_node, select_expr, from_list, relation_node;
|
|
|
|
NOD fields_node, values_node, field_node, value_node, old_value_node;
|
|
|
|
NOD *ptr, *end, *ptr2, *end2;
|
|
|
|
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;
|
|
|
|
FLD field;
|
|
|
|
SSHORT and_arg = 0;
|
|
|
|
|
|
|
|
ddl_node = request->req_ddl_node;
|
|
|
|
|
|
|
|
/* check whether this is an updatable view definition */
|
|
|
|
|
|
|
|
if (ddl_node->nod_type != nod_def_view ||
|
|
|
|
!(select_node = ddl_node->nod_arg[e_view_select]) ||
|
2001-07-10 19:35:13 +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_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];
|
|
|
|
relation_node->nod_arg[e_rln_alias] = (NOD) MAKE_cstring(TEMP_CONTEXT);
|
|
|
|
*base_relation = relation_node;
|
|
|
|
|
2001-07-10 19:35:13 +02:00
|
|
|
/* 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] =
|
|
|
|
(NOD) MAKE_cstring(field->fld_name);
|
|
|
|
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] =
|
|
|
|
(NOD) MAKE_cstring(TEMP_CONTEXT);
|
|
|
|
|
|
|
|
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] =
|
|
|
|
(NOD) MAKE_cstring(NEW_CONTEXT);
|
|
|
|
|
|
|
|
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] =
|
|
|
|
(NOD) MAKE_cstring(OLD_CONTEXT);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void define_upd_cascade_trg( REQ request,
|
|
|
|
NOD element,
|
|
|
|
NOD for_columns,
|
|
|
|
NOD prim_columns,
|
|
|
|
TEXT* prim_rel_name,
|
|
|
|
TEXT* 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;
|
|
|
|
NOD* for_key_flds = for_columns->nod_arg;
|
|
|
|
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,
|
|
|
|
reinterpret_cast<char*>(prim_key_fld_name_str->str_data));
|
|
|
|
request->append_uchar(blr_field);
|
|
|
|
request->append_uchar(2);
|
|
|
|
request->append_cstring(0,
|
|
|
|
reinterpret_cast<char*>(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
|
|
|
|
|
|
|
|
// 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( REQ request)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
NOD node, select, select_expr, rse, field_node;
|
|
|
|
NOD check, relation_node;
|
|
|
|
NOD view_fields, *ptr, *end;
|
|
|
|
NOD items, *i_ptr, *i_end;
|
|
|
|
DSQL_REL relation;
|
|
|
|
FLD field;
|
|
|
|
CTX context;
|
|
|
|
STR view_name, field_name, source;
|
|
|
|
SSHORT position, updatable = TRUE;
|
|
|
|
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];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_def_view,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(view_name->str_data));
|
|
|
|
save_relation(request, view_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
|
|
|
|
|
|
|
/* 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]);
|
|
|
|
|
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,
|
|
|
|
reinterpret_cast<char*>(source->str_data),
|
|
|
|
(USHORT) source->str_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* define the view source relations from the request contexts */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
for (temp = request->req_context; temp; temp = temp->lls_next)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
context = (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 = (FLD) field_node->nod_arg[e_fld_field];
|
|
|
|
context = (CTX) field_node->nod_arg[e_fld_context];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
updatable = FALSE;
|
|
|
|
|
|
|
|
/* 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
|
|
|
{
|
2001-07-30 01:43:24 +02: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
|
|
|
}
|
|
|
|
if (ptr && ptr < end)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
field_name = (STR) (*ptr)->nod_arg[1];
|
|
|
|
field_string = (TEXT *) field_name->str_data;
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr != end)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-07-30 01:43:24 +02: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
|
|
|
{
|
2001-07-30 01:43:24 +02: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
|
|
|
{
|
2001-07-30 01:43:24 +02: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-07-10 19:35:13 +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
|
|
|
|
*/
|
|
|
|
else if (select_expr->nod_arg[0]->nod_arg[e_sel_from]->nod_count != 1)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-07-30 01:43:24 +02: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-07-10 19:35:13 +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
|
|
|
{
|
2001-07-30 01:43:24 +02: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
|
|
|
{
|
2001-07-30 01:43:24 +02: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);
|
|
|
|
relation_node->nod_arg[e_rln_name] = (NOD) view_name;
|
|
|
|
check->nod_arg[e_cnstr_table] = relation_node;
|
|
|
|
|
|
|
|
check->nod_arg[e_cnstr_source] = (NOD) source;
|
|
|
|
|
2001-07-10 19:35:13 +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( REQ request, NOD node, NOD rse, NOD items)
|
|
|
|
{ /* 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;
|
2001-05-23 15:26:42 +02:00
|
|
|
NOD temp_rse, temp, ddl_node, actions, *ptr, *end, constant;
|
|
|
|
NOD relation_node;
|
|
|
|
USHORT trig_type;
|
|
|
|
NOD action_node, condition, select, select_expr, view_fields;
|
|
|
|
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-07-10 19:35:13 +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->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,
|
|
|
|
reinterpret_cast<char*>(trigger_name->str_data),
|
|
|
|
(USHORT) 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,
|
|
|
|
reinterpret_cast<char*>(relation_name->str_data),
|
|
|
|
(USHORT) 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,
|
2001-05-23 15:26:42 +02:00
|
|
|
(SSHORT) (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)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
trig_type = (USHORT) 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,
|
|
|
|
reinterpret_cast<char*>(message->str_data),
|
|
|
|
(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
|
|
|
|
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 = (CTX) stack->lls_object;
|
|
|
|
if (context->ctx_alias) {
|
2001-12-24 03:51:06 +01:00
|
|
|
sav_context = new(*tdsql->tsql_default) ctx;
|
2001-05-23 15:26:42 +02:00
|
|
|
*sav_context = *context;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
reset_context_stack(request);
|
|
|
|
temp = relation_node->nod_arg[e_rln_alias];
|
|
|
|
relation_node->nod_arg[e_rln_alias] = (NOD) MAKE_cstring(OLD_CONTEXT);
|
|
|
|
PASS1_make_context(request, relation_node);
|
|
|
|
relation_node->nod_arg[e_rln_alias] = (NOD) MAKE_cstring(NEW_CONTEXT);
|
|
|
|
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];
|
|
|
|
temp->nod_arg[0] = PASS1_node(request, temp->nod_arg[0], 0);
|
|
|
|
temp = rse->nod_arg[e_rse_boolean];
|
|
|
|
rse->nod_arg[e_rse_boolean] = PASS1_node(request, temp, 0);
|
|
|
|
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);
|
2001-05-23 15:26:42 +02:00
|
|
|
GEN_expr(request, PASS1_node(request, condition->nod_arg[0], 0));
|
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);
|
2001-05-23 15:26:42 +02:00
|
|
|
GEN_expr(request, PASS1_node(request, condition->nod_arg[0], 0));
|
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
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
GEN_statement(request, PASS1_statement(request, *ptr, 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 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++)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
action_node = PASS1_statement(request, *ptr, 0);
|
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] =
|
|
|
|
MAKE_constant((STR) 1, 1);
|
|
|
|
}
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
//
|
|
|
|
// Complete the stuffing of a piece of
|
|
|
|
// blr by going back and inserting the length.
|
|
|
|
//
|
|
|
|
void 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
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
UCHAR* blr_base = req_blr_string->str_data + req_base_offset;
|
|
|
|
USHORT length = (SSHORT) (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( REQ request, NOD element)
|
|
|
|
{
|
|
|
|
/* *************************************
|
|
|
|
*
|
|
|
|
* f o r e i g n _ k e y
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
|
|
|
* Generate ddl to create a foreign key
|
|
|
|
* constraint.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
NOD relation2_node;
|
|
|
|
NOD columns1, columns2;
|
|
|
|
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
|
|
|
{
|
2001-07-30 01:43:24 +02: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
|
|
|
{
|
2001-07-30 01:43:24 +02: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],
|
|
|
|
reinterpret_cast<char*>(relation2->str_data));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void generate_dyn( REQ request, NOD node)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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;
|
|
|
|
|
|
|
|
case nod_def_view:
|
|
|
|
define_view(request);
|
|
|
|
break;
|
|
|
|
|
|
|
|
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:
|
|
|
|
define_procedure(request, node->nod_type);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_def_constraint:
|
|
|
|
define_constraint_trigger(request, node);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_def_trigger:
|
|
|
|
case nod_mod_trigger:
|
|
|
|
define_trigger(request, node);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_mod_relation:
|
|
|
|
modify_relation(request);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_del_domain:
|
|
|
|
string = (STR) node->nod_arg[0];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_delete_global_fld,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_delete_idx,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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_relation:
|
|
|
|
string = (STR) node->nod_arg[0];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_delete_rel,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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_procedure:
|
|
|
|
string = (STR) node->nod_arg[0];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_delete_procedure,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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_trigger:
|
|
|
|
string = (STR) node->nod_arg[0];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_delete_trigger,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(isc_dyn_del_sql_role,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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];
|
|
|
|
/**********FIX -- nothing like delete_generator exists as yet
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_def_generator, string->str_data);
|
2001-05-23 15:26:42 +02:00
|
|
|
STUFF (gds_dyn_end); */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_del_filter:
|
|
|
|
string = (STR) node->nod_arg[0];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_delete_filter,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_delete_function,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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,
|
2001-05-23 15:26:42 +02:00
|
|
|
(SSHORT) (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( REQ request)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g r a n t _ r e v o k e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Build DYN string for GRANT/REVOKE statements
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD table;
|
|
|
|
NOD users;
|
|
|
|
NOD* uptr;
|
|
|
|
NOD* uend;
|
|
|
|
bool process_grant_role = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
SSHORT option = FALSE;
|
|
|
|
NOD ddl_node = request->req_ddl_node;
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
table = ddl_node->nod_arg[e_grant_table];
|
|
|
|
users = ddl_node->nod_arg[e_grant_users];
|
|
|
|
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
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD role_list = ddl_node->nod_arg[0];
|
2001-05-23 15:26:42 +02:00
|
|
|
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);
|
|
|
|
|
|
|
|
NOD* role_end = role_list->nod_arg + role_list->nod_count;
|
|
|
|
for (NOD* role_ptr = role_list->nod_arg; role_ptr < role_end; ++role_ptr)
|
|
|
|
{
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void make_index( REQ request,
|
|
|
|
NOD element,
|
|
|
|
NOD columns,
|
|
|
|
NOD referenced_columns,
|
|
|
|
TEXT* relation_name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/* *************************************
|
|
|
|
*
|
|
|
|
* m a k e _ i n d e x
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
2001-07-10 19:35:13 +02:00
|
|
|
* 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
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
// stuff a 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
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (element->nod_type == nod_primary) {
|
|
|
|
request->append_uchar(gds_dyn_def_primary_key);
|
|
|
|
} else if (element->nod_type == nod_unique) {
|
|
|
|
request->append_uchar(gds_dyn_def_unique);
|
|
|
|
}
|
|
|
|
request->append_ushort(0);
|
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
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
const NOD* end = columns->nod_arg + columns->nod_count;
|
|
|
|
for (NOD* ptr = columns->nod_arg; ptr < end; ++ptr)
|
|
|
|
{
|
|
|
|
STR field_name = (STR) (*ptr)->nod_arg[1];
|
|
|
|
request->append_cstring(gds_dyn_fld_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void make_index_trg_ref_int( REQ request,
|
|
|
|
NOD element,
|
|
|
|
NOD columns,
|
|
|
|
NOD referenced_columns,
|
|
|
|
TEXT* relation_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-07-10 19:35:13 +02:00
|
|
|
*
|
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
|
|
|
STR field_name;
|
|
|
|
NOD for_rel_node, ddl_node;
|
|
|
|
STR for_rel_name_str;
|
|
|
|
NOD nod_for_action, nod_ref_upd_action, nod_ref_del_action;
|
|
|
|
|
|
|
|
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 */
|
|
|
|
ddl_node = request->req_ddl_node;
|
|
|
|
for_rel_node = ddl_node->nod_arg[e_drl_name];
|
|
|
|
for_rel_name_str = (STR) for_rel_node->nod_arg[e_rln_name];
|
|
|
|
|
|
|
|
|
|
|
|
/* stuff a zero-length name, indicating that an index
|
|
|
|
name should be generated */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_uchar(gds_dyn_def_foreign_key);
|
|
|
|
request->append_ushort(0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (element->nod_arg[e_for_action])
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
nod_for_action = element->nod_arg[e_for_action];
|
|
|
|
assert(nod_for_action->nod_type == nod_ref_upd_del);
|
|
|
|
|
|
|
|
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,
|
2001-12-24 03:51:06 +01:00
|
|
|
reinterpret_cast<char*>(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,
|
2001-12-24 03:51:06 +01:00
|
|
|
reinterpret_cast<char*>(for_rel_name_str->str_data),
|
|
|
|
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,
|
2001-12-24 03:51:06 +01:00
|
|
|
reinterpret_cast<char*>(for_rel_name_str->str_data),
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
reinterpret_cast <
|
|
|
|
char *>(for_rel_name_str->str_data));
|
|
|
|
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,
|
2001-12-24 03:51:06 +01:00
|
|
|
reinterpret_cast<char*>(for_rel_name_str->str_data),
|
|
|
|
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,
|
2001-12-24 03:51:06 +01:00
|
|
|
reinterpret_cast<char*>(for_rel_name_str->str_data),
|
|
|
|
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 */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD* ptr;
|
|
|
|
NOD* end = columns->nod_arg + columns->nod_count;
|
|
|
|
for (ptr = columns->nod_arg; ptr < end; ++ptr)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
field_name = (STR) (*ptr)->nod_arg[1];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_fld_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(field_name->str_data));
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
field_name = (STR) (*ptr)->nod_arg[1];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_idx_ref_column,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(field_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
|
|
|
request->append_uchar(gds_dyn_end);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void modify_database( REQ request)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m o d i f y _ d a t a b a s e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
2001-07-10 19:35:13 +02:00
|
|
|
* Modify a database.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
2001-12-24 03:51:06 +01:00
|
|
|
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;
|
|
|
|
SSHORT drop_log = FALSE;
|
|
|
|
SSHORT drop_cache = FALSE;
|
|
|
|
|
|
|
|
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
|
|
|
*/
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD elements = ddl_node->nod_arg[e_adb_all];
|
|
|
|
NOD* 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_drop_log:
|
|
|
|
drop_log = TRUE;
|
|
|
|
break;
|
|
|
|
case nod_drop_cache:
|
|
|
|
drop_cache = TRUE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
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,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(file->fil_name->str_data));
|
|
|
|
|
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,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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);
|
2001-05-23 15:26:42 +02:00
|
|
|
temp_short = (SSHORT) (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);
|
2001-05-23 15:26:42 +02:00
|
|
|
temp_short = (SSHORT) (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_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( REQ request)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2001-07-10 19:35:13 +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.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
NOD ddl_node, domain_node, ops, element, *ptr, *end;
|
|
|
|
STR string, domain_name;
|
|
|
|
FLD field;
|
2001-12-24 03:51:06 +01:00
|
|
|
fld local_field;
|
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,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(domain_name->str_data));
|
|
|
|
|
|
|
|
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:
|
|
|
|
/* CVC: So do you want to crash me with ALTER DOMAIN dom SET; ??? */
|
|
|
|
if (!element->nod_arg[e_dft_default])
|
|
|
|
{
|
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] =
|
|
|
|
PASS1_node(request, element->nod_arg[e_dft_default], 0);
|
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,
|
|
|
|
reinterpret_cast<char*>(string->str_data),
|
|
|
|
(USHORT) string->str_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_def_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))
|
|
|
|
{
|
2001-07-30 01:43:24 +02:00
|
|
|
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
|
|
|
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],
|
|
|
|
0));
|
|
|
|
|
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,
|
|
|
|
reinterpret_cast<char*>(string->str_data),
|
|
|
|
(USHORT) string->str_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_mod_domain_type:
|
|
|
|
field = (FLD) element->nod_arg[e_mod_dom_new_dom_type];
|
|
|
|
DDL_resolve_intl_type(request, field, NULL);
|
|
|
|
put_field(request, field, FALSE);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_field_name:
|
|
|
|
{
|
|
|
|
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,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast <
|
|
|
|
char *>(new_dom_name->str_data));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case nod_delete_rel_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:
|
2001-12-24 03:51:06 +01:00
|
|
|
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( REQ request)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m o d i f y _ i n d e x
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
|
|
|
* Alter an index (only active or inactive for now)
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
NOD ddl_node, index_node;
|
|
|
|
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];
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_mod_idx,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(index_name->str_data));
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void modify_privilege( REQ request,
|
|
|
|
NOD_TYPE type,
|
|
|
|
SSHORT option,
|
|
|
|
UCHAR* privs,
|
|
|
|
NOD table,
|
|
|
|
NOD user,
|
|
|
|
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.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SSHORT priv_count, i;
|
|
|
|
UCHAR *dynsave;
|
|
|
|
STR name;
|
|
|
|
|
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 */
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
dynsave = request->req_blr;
|
|
|
|
for (i = priv_count + 2; i; i--)
|
|
|
|
--dynsave;
|
|
|
|
|
|
|
|
*dynsave++ = (UCHAR) priv_count;
|
|
|
|
*dynsave = (UCHAR) (priv_count >> 8);
|
|
|
|
|
|
|
|
name = (STR) table->nod_arg[0];
|
|
|
|
if (table->nod_type == nod_procedure_name)
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_prc_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(name->str_data));
|
|
|
|
else
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_rel_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(name->str_data));
|
|
|
|
name = (STR) user->nod_arg[0];
|
|
|
|
switch (user->nod_type) {
|
|
|
|
case nod_user_group: /* GRANT priv ON tbl TO GROUP unix_group */
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(isc_dyn_grant_user_group,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(name->str_data));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_user_name:
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_grant_user,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(name->str_data));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_proc_obj:
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_grant_proc,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(name->str_data));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_trig_obj:
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_grant_trig,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(name->str_data));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_view_obj:
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_grant_view,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(name->str_data));
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (field_name) {
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_fld_name,
|
|
|
|
reinterpret_cast<char*>(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(REQ request,
|
|
|
|
NOD_TYPE type,
|
|
|
|
SSHORT option,
|
|
|
|
NOD privs,
|
|
|
|
NOD table,
|
|
|
|
NOD user)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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], *p;
|
|
|
|
NOD fields, *ptr, *end;
|
|
|
|
|
|
|
|
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";
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!(fields = privs->nod_arg[0]))
|
|
|
|
return *p;
|
|
|
|
|
|
|
|
for (ptr = fields->nod_arg, end = ptr + fields->nod_count; ptr < end;
|
|
|
|
ptr++)
|
|
|
|
modify_privilege(request, type, option,
|
|
|
|
reinterpret_cast < UCHAR * >(p), table, user,
|
|
|
|
reinterpret_cast < str * >((*ptr)->nod_arg[1]));
|
|
|
|
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++)
|
|
|
|
if (*p =
|
|
|
|
modify_privileges(request, type, option, *ptr, table,
|
|
|
|
user)) p++;
|
|
|
|
*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( REQ request)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m o d i f y _ r e l a t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
|
|
|
* Alter an SQL table, relying on DYN to generate
|
2001-07-10 19:35:13 +02:00
|
|
|
* global fields for the local fields.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
NOD ddl_node, ops, element, *ptr, *end, relation_node, field_node;
|
|
|
|
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];
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_mod_rel,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(relation_name->str_data));
|
|
|
|
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:
|
|
|
|
{
|
|
|
|
NOD old_field, new_field;
|
|
|
|
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,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast <
|
|
|
|
char *>(old_field_name->str_data));
|
|
|
|
|
|
|
|
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,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast <
|
|
|
|
char *>(relation_name->str_data));
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(isc_dyn_new_fld_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast <
|
|
|
|
char *>(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;
|
|
|
|
NOD const_node;
|
|
|
|
|
|
|
|
field_node = element->nod_arg[e_mod_fld_pos_orig_name];
|
|
|
|
field_name = (STR) field_node->nod_arg[e_fln_name];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_mod_local_fld,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(field_name->str_data));
|
|
|
|
|
|
|
|
const_node = element->nod_arg[e_mod_fld_pos_new_position];
|
|
|
|
constant = (SSHORT) const_node->nod_arg[0];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_rel_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast <
|
|
|
|
char *>(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
|
2001-07-10 19:35:13 +02:00
|
|
|
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 */
|
2001-07-30 01:43:24 +02:00
|
|
|
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);
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_delete_local_fld,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(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];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_delete_rel_constraint,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(field_name->str_data));
|
|
|
|
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
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void process_role_nm_list( REQ request,
|
|
|
|
SSHORT option,
|
|
|
|
NOD user_ptr,
|
|
|
|
NOD role_ptr,
|
|
|
|
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];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(isc_dyn_sql_role_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(role_nm->str_data));
|
|
|
|
|
|
|
|
user_nm = (STR) user_ptr->nod_arg[0];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(isc_dyn_grant_user,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(user_nm->str_data));
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void put_descriptor(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);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void put_dtype(REQ request, FLD field, USHORT use_subtype)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2001-07-10 19:35:13 +02:00
|
|
|
* p u t _ d t y p e
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
|
|
|
* Write out field data type
|
|
|
|
* Taking special care to declare international text.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
#ifdef DEV_BUILD
|
|
|
|
/* Check if the field describes a known datatype */
|
|
|
|
|
|
|
|
if (field->fld_dtype > sizeof(blr_dtypes) / sizeof(blr_dtypes[0]) ||
|
|
|
|
!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( REQ request, FLD field, BOOLEAN udf_flag)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2001-07-10 19:35:13 +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)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
assert((field->fld_length - sizeof(USHORT)) <= 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( REQ request, VAR variable)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* p u t _ l o c a l _ v a r i a b l e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
|
|
|
* Write out local variable field data type
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
FLD field = variable->var_field;
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
put_dtype(request, field, TRUE);
|
|
|
|
field->fld_dtype = dtype;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
// Initialize variable to NULL
|
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_variable);
|
|
|
|
request->append_ushort(variable->var_variable_number);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static SSHORT put_local_variables(REQ request, 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)
|
|
|
|
{
|
|
|
|
NOD* ptr = parameters->nod_arg;
|
|
|
|
for (NOD* end = ptr + parameters->nod_count; ptr < end; ptr++)
|
|
|
|
{
|
|
|
|
NOD parameter = *ptr;
|
|
|
|
FLD field = (FLD) parameter->nod_arg[e_dfl_field];
|
|
|
|
NOD* rest = ptr;
|
|
|
|
while ((++rest) != end)
|
|
|
|
{
|
|
|
|
FLD rest_field = (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
|
|
|
{
|
2001-07-30 01:43:24 +02: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
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
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];
|
2001-05-23 15:26:42 +02:00
|
|
|
put_local_variable(request, variable);
|
|
|
|
locals++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return locals;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void put_msg_field( REQ request, FLD field)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
put_dtype(request, field, TRUE);
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
void 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 req::append_cstring(UCHAR verb, 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 req::append_string(UCHAR verb, 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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static NOD replace_field_names(NOD input,
|
|
|
|
NOD search_fields,
|
|
|
|
NOD replace_fields,
|
|
|
|
SSHORT 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
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
const NOD* endo = input->nod_arg + input->nod_count;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
for (NOD* ptr = input->nod_arg; ptr < endo; ++ptr)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if ((*ptr)->nod_type == nod_select_expr)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-07-30 01:43:24 +02: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];
|
|
|
|
NOD* search = search_fields->nod_arg;
|
|
|
|
NOD* end = search + search_fields->nod_count;
|
|
|
|
NOD* replace;
|
|
|
|
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];
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
NOD field_node = *search;
|
|
|
|
FLD field = (FLD) field_node->nod_arg[e_fld_field];
|
|
|
|
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
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
(*ptr)->nod_arg[e_fln_context] = (NOD) MAKE_cstring(NEW_CONTEXT);
|
|
|
|
|
|
|
|
}
|
|
|
|
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( REQ request)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* r e s e t _ c o n t e x t _ s t a c k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
2001-07-10 19:35:13 +02:00
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void save_field(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
|
2001-07-10 19:35:13 +02:00
|
|
|
* 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
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
FLD field = new(*tdsql->tsql_default, strlen(field_name) + 1) 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( REQ request, STR relation_name)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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
|
2001-07-10 19:35:13 +02:00
|
|
|
* 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
|
|
|
|
|
|
|
NOD ddl_node = request->req_ddl_node;
|
|
|
|
DSQL_REL relation;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (ddl_node->nod_type == nod_mod_relation)
|
|
|
|
{
|
|
|
|
relation = METD_get_relation(request, relation_name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
relation = new(*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( REQ request)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e t _ s t a t i s t i c s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
|
|
|
* Alter an index/.. statistics
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
NOD ddl_node;
|
|
|
|
STR index_name;
|
|
|
|
|
|
|
|
ddl_node = request->req_ddl_node;
|
|
|
|
|
|
|
|
index_name = (STR) ddl_node->nod_arg[e_stat_name];
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_mod_idx,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(index_name->str_data));
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void stuff_default_blr( REQ request,
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void stuff_matching_blr(REQ request, NOD for_columns, 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
|
2001-07-10 19:35:13 +02:00
|
|
|
* 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;
|
|
|
|
NOD* for_key_flds = for_columns->nod_arg;
|
|
|
|
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,
|
|
|
|
reinterpret_cast<char*>(for_key_fld_name_str->str_data));
|
|
|
|
request->append_uchar(blr_field);
|
|
|
|
request->append_uchar(0);
|
|
|
|
request->append_cstring(0,
|
|
|
|
reinterpret_cast<char*>(prim_key_fld_name_str->str_data));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
num_fields++;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (prim_columns->nod_count - num_fields >= (unsigned) 2) {
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void stuff_trg_firing_cond(REQ request, 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;
|
|
|
|
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_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,
|
|
|
|
reinterpret_cast<char*>(prim_key_fld_name_str->str_data));
|
|
|
|
request->append_uchar(blr_field);
|
|
|
|
request->append_uchar(1);
|
|
|
|
request->append_cstring(0,
|
|
|
|
reinterpret_cast<char*>(prim_key_fld_name_str->str_data));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
num_fields++;
|
|
|
|
|
|
|
|
if (prim_columns->nod_count - num_fields >= (unsigned) 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
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static void modify_field(REQ request,
|
|
|
|
NOD element,
|
|
|
|
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.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
NOD domain_node;
|
|
|
|
FLD field;
|
|
|
|
DSQL_REL relation;
|
|
|
|
|
|
|
|
field = (FLD) element->nod_arg[e_dfl_field];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(isc_dyn_mod_sql_fld,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(field->fld_name));
|
|
|
|
|
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])
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
NOD node1;
|
|
|
|
STR domain_name;
|
|
|
|
|
|
|
|
node1 = domain_node->nod_arg[e_dom_name];
|
|
|
|
domain_name = (STR) node1->nod_arg[e_fln_name];
|
2001-12-24 03:51:06 +01:00
|
|
|
request->append_cstring(gds_dyn_fld_source,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(domain_name->str_data));
|
|
|
|
|
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))
|
|
|
|
{
|
2001-07-30 01:43:24 +02:00
|
|
|
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,
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<char*>(relation_name->str_data));
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
DDL_resolve_intl_type(request, field, NULL);
|
|
|
|
put_field(request, field, FALSE);
|
|
|
|
}
|
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( NOD node, FLD field)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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)
|
|
|
|
{
|
|
|
|
NOD child = node->nod_arg[child_number];
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
void req::append_uchar(UCHAR byte)
|
|
|
|
{
|
|
|
|
if (req_blr < req_blr_yellow) {
|
|
|
|
*req_blr++ = byte;
|
|
|
|
} else {
|
|
|
|
GEN_expand_buffer(this, byte);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void req::append_uchars(UCHAR byte, UCHAR count)
|
|
|
|
{
|
|
|
|
for (int i=0; i< count ; ++i) {
|
|
|
|
append_uchar(byte);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void req::append_ushort(USHORT val)
|
|
|
|
{
|
|
|
|
append_uchar(val);
|
|
|
|
append_uchar(val >> 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
void req::append_ulong(ULONG val)
|
|
|
|
{
|
|
|
|
append_ushort(val);
|
|
|
|
append_ushort(val >> 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
void req::append_ushort_with_length(USHORT val)
|
|
|
|
{
|
|
|
|
// append an USHORT value, prepended with the USHORT length of an USHORT
|
|
|
|
append_ushort(2);
|
|
|
|
append_ushort(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
void req::append_ulong_with_length(ULONG val)
|
|
|
|
{
|
|
|
|
// append an ULONG value, prepended with the USHORT length of an ULONG
|
|
|
|
append_ushort(4);
|
|
|
|
append_ulong(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
void req::append_file_length(ULONG length)
|
|
|
|
{
|
|
|
|
append_uchar(gds_dyn_file_length);
|
|
|
|
append_ulong_with_length(length);
|
|
|
|
}
|
|
|
|
|
|
|
|
void req::append_file_start(ULONG start)
|
|
|
|
{
|
|
|
|
append_uchar(gds_dyn_file_start);
|
|
|
|
append_ulong_with_length(start);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// common code factored out
|
|
|
|
//
|
|
|
|
void req::generate_unnamed_trigger_beginning( bool on_update_trigger,
|
|
|
|
TEXT* prim_rel_name,
|
|
|
|
struct nod* prim_columns,
|
|
|
|
TEXT* for_rel_name,
|
|
|
|
struct nod* for_columns)
|
|
|
|
{
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|