//____________________________________________________________ // // PROGRAM: C preprocessor // MODULE: cmd.cpp // DESCRIPTION: Data definition compiler // // 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): ______________________________________. // TMN (Mike Nordell) 11.APR.2001 - Reduce compiler warnings // // //____________________________________________________________ // // #include "firebird.h" #include #include "../gpre/gpre.h" #include "../jrd/ibase.h" #include "../jrd/flags.h" #include "../gpre/cmd_proto.h" #include "../gpre/cme_proto.h" #include "../gpre/cmp_proto.h" #include "../gpre/gpre_proto.h" #include "../gpre/msc_proto.h" #include "../gpre/gpre_meta.h" //typedef void (*pfn_local_trigger_cb) (gpre_nod*, gpre_req*, // void* // /* TMN: NOTE, parameter type unknown! */ // ); // CVC: This was an unaceptable hack in the original code and Mike only // found the problem when C++ couldn't compile. Let's see, the // two functions that get this cast are // void CME_expr(gpre_nod*, gpre_req*); // and // void CME_rse(gpre_rse*, gpre_req*); // Obviously, they can't see a third parameter. Therefore, I've changed the // signature, after verifying the third param was always zero. typedef void (*pfn_local_trigger_cb) (gpre_nod*, gpre_req*); // The call to CME_rse still needs the cast due to the different first param. //static void add_cache(gpre_req*, const act*, DBB); static void alter_database(gpre_req*, act*); static void alter_domain(gpre_req*, const act*); static void alter_index(gpre_req*, const act*); static void alter_table(gpre_req*, const act*); static void create_check_constraint(gpre_req*, const act*, CNSTRT); static void create_constraint(gpre_req*, const act*, CNSTRT); static void create_database(gpre_req*, const act*); static void create_database_modify_dyn(gpre_req*, act*); static void create_default_blr(gpre_req*, const TEXT*, const USHORT); static void create_del_cascade_trg(gpre_req*, const act*, CNSTRT); static void create_domain(gpre_req*, const act*); static void create_domain_constraint(gpre_req*, const act*, const cnstrt*); static void create_generator(gpre_req*, const act*); static void create_index(gpre_req*, const ind*); static void create_matching_blr(gpre_req*, const cnstrt*); static void create_set_default_trg(gpre_req*, const act*, CNSTRT, bool); static void create_set_null_trg(gpre_req*, const act*, CNSTRT, bool); static void create_shadow(gpre_req*, act*); static void create_table(gpre_req*, const act*); static void create_trg_firing_cond(gpre_req*, const cnstrt*); static void create_trigger(gpre_req*, const act*, gpre_trg*, pfn_local_trigger_cb); static void create_upd_cascade_trg(gpre_req*, const act*, CNSTRT); static bool create_view(gpre_req*, act*); static void create_view_trigger(gpre_req*, const act*, gpre_trg*, GPRE_NOD, gpre_ctx**, GPRE_NOD); static void declare_filter(gpre_req*, const act*); static void declare_udf(gpre_req*, const act*); static void get_referred_fields(const act*, CNSTRT); static void grant_revoke_privileges(gpre_req*, const act*); static void init_field_struct(gpre_fld*); static void put_array_info(gpre_req*, const gpre_fld*); static void put_blr(gpre_req*, USHORT, GPRE_NOD, pfn_local_trigger_cb); static void put_computed_blr(gpre_req*, const gpre_fld*); static void put_computed_source(gpre_req*, const gpre_fld*); static void put_cstring(gpre_req*, USHORT, const TEXT*); static void put_dtype(gpre_req*, const gpre_fld*); static void put_field_attributes(gpre_req*, const gpre_fld*); static void put_numeric(gpre_req*, USHORT, SSHORT); static void put_short_cstring(gpre_req*, USHORT, const TEXT*); static void put_string(gpre_req*, USHORT, const TEXT*, USHORT); static void put_symbol(gpre_req*, int, const gpre_sym*); static void put_trigger_blr(gpre_req*, USHORT, GPRE_NOD, pfn_local_trigger_cb); static void put_view_trigger_blr(gpre_req*, const gpre_rel*, USHORT, gpre_trg*, GPRE_NOD, gpre_ctx**, GPRE_NOD); static void replace_field_names(gpre_nod* const, const gpre_nod* const, gpre_fld* const, bool, gpre_ctx**); static void set_statistics(gpre_req*, const act*); #define STUFF_CHECK(n) if (request->req_base - request->req_blr + request->req_length <= (n) + 50)\ CMP_check (request,(n)) const int BLOB_BUFFER_SIZE = 4096; // to read in blr blob for default values //____________________________________________________________ // // Compile a single request, but do not generate any text. // Generate port blocks, assign parameter numbers, message // numbers, and internal idents. Compute length of request. // int CMD_compile_ddl(gpre_req* request) { IND index; gpre_rel* relation; // Initialize the blr string act* action = request->req_actions; request->req_blr = request->req_base = MSC_alloc(250); request->req_length = 250; request->req_flags |= REQ_exp_hand; request->add_byte(isc_dyn_version_1); request->add_byte(isc_dyn_begin); switch (action->act_type) { case ACT_alter_table: alter_table(request, action); break; case ACT_alter_database: alter_database(request, action); break; case ACT_alter_domain: alter_domain(request, action); break; case ACT_alter_index: alter_index(request, action); break; case ACT_create_database: if (!(request->req_flags & REQ_sql_database_dyn)) { request->req_blr = request->req_base; create_database(request, action); return 0; } create_database_modify_dyn(request, action); break; case ACT_create_domain: create_domain(request, action); break; case ACT_create_generator: create_generator(request, action); break; case ACT_create_index: index = (IND) action->act_object; create_index(request, index); break; case ACT_create_shadow: create_shadow(request, action); break; case ACT_create_table: create_table(request, action); break; case ACT_create_view: if (!create_view(request, action)) return -1; break; case ACT_drop_database: break; case ACT_drop_domain: put_cstring(request, isc_dyn_delete_global_fld, (TEXT *) action->act_object); request->add_end(); break; case ACT_drop_filter: put_cstring(request, isc_dyn_delete_filter, (TEXT *) action->act_object); request->add_end(); break; case ACT_drop_index: index = (IND) action->act_object; put_symbol(request, isc_dyn_delete_idx, index->ind_symbol); request->add_end(); break; case ACT_drop_shadow: put_numeric(request, isc_dyn_delete_shadow, (SSHORT) (IPTR) action->act_object); request->add_end(); break; case ACT_drop_table: case ACT_drop_view: relation = (gpre_rel*) action->act_object; put_symbol(request, isc_dyn_delete_rel, relation->rel_symbol); request->add_end(); break; case ACT_drop_udf: put_cstring(request, isc_dyn_delete_function, (TEXT *) action->act_object); request->add_end(); break; case ACT_dyn_grant: grant_revoke_privileges(request, action); break; case ACT_dyn_revoke: grant_revoke_privileges(request, action); break; case ACT_declare_filter: declare_filter(request, action); break; case ACT_declare_udf: declare_udf(request, action); break; case ACT_statistics: set_statistics(request, action); break; default: CPR_error("*** unknown request type node ***"); return -1; } request->add_end(); request->add_byte(isc_dyn_eoc); request->req_length = request->req_blr - request->req_base; request->req_blr = request->req_base; return 0; } //____________________________________________________________ // // Add cache file to a database. // /* static void add_cache( gpre_req* request, const act* action, dbb* database) { TEXT file_name[254]; // CVC: Maybe MAXPATHLEN? const fil* file = database->dbb_cache_file; const SSHORT l = MIN((strlen(file->fil_name)), (sizeof(file_name) - 1)); strncpy(file_name, file->fil_name, l); file_name[l] = '\0'; put_cstring(request, isc_dyn_def_cache_file, file_name); request->add_byte(isc_dyn_file_length); request->add_word(4); request->add_long(file->fil_length); request->add_end(); } */ //____________________________________________________________ // // Generate dynamic DDL for modifying database. // static void alter_database( gpre_req* request, act* action) { FIL file, next; dbb* db = (DBB) action->act_object; request->add_byte(isc_dyn_mod_database); // Reverse the order of files (parser left them backwards) FIL files = db->dbb_files; for (file = files, files = NULL; file; file = next) { next = file->fil_next; file->fil_next = files; files = file; } for (file = files; file != NULL; file = file->fil_next) { put_cstring(request, isc_dyn_def_file, file->fil_name); request->add_byte(isc_dyn_file_start); request->add_word(4); const SLONG start = file->fil_start; request->add_long(start); request->add_byte(isc_dyn_file_length); request->add_word(4); request->add_long(file->fil_length); request->add_end(); } // Drop cache /* if (db->dbb_flags & DBB_drop_cache) request->add_byte(isc_dyn_drop_cache); if (db->dbb_cache_file) add_cache(request, action, db); */ if (db->dbb_def_charset) put_cstring(request, isc_dyn_fld_character_set_name, db->dbb_def_charset); request->add_end(); } //____________________________________________________________ // // Generate dynamic DDL for CREATE DOMAIN action. // static void alter_domain( gpre_req* request, const act* action) { const gpre_fld* field = (gpre_fld*) action->act_object; // modify field info put_symbol(request, isc_dyn_mod_global_fld, field->fld_symbol); const gpre_nod* default_node = field->fld_default_value; if (default_node) { if (default_node->nod_type == nod_erase) { request->add_byte(isc_dyn_del_default); } else { put_blr(request, isc_dyn_fld_default_value, field->fld_default_value, CME_expr); TEXT* default_source = (TEXT *) MSC_alloc(field->fld_default_source->txt_length + 1); CPR_get_text(default_source, field->fld_default_source); put_cstring(request, isc_dyn_fld_default_source, default_source); } } if (field->fld_constraints) { request->add_byte(isc_dyn_single_validation); for (const cnstrt* constraint = field->fld_constraints; constraint; constraint = constraint->cnstrt_next) { if (constraint->cnstrt_flags & CNSTRT_delete) request->add_byte(isc_dyn_del_validation); } create_domain_constraint(request, action, field->fld_constraints); } request->add_end(); } //____________________________________________________________ // // Generate dynamic DDL for ALTER INDEX statement // static void alter_index( gpre_req* request, const act* action) { const ind* index = (IND) action->act_object; put_symbol(request, isc_dyn_mod_idx, index->ind_symbol); const SSHORT value = (index->ind_flags & IND_active) ? 0 : 1; put_numeric(request, isc_dyn_idx_inactive, value); request->add_end(); } //____________________________________________________________ // // Generate dynamic DDL for ALTER TABLE action. // static void alter_table( gpre_req* request, const act* action) { // add relation name const gpre_rel* relation = (gpre_rel*) action->act_object; put_symbol(request, isc_dyn_mod_rel, relation->rel_symbol); // add field info for (const gpre_fld* field = relation->rel_fields; field; field = field->fld_next) { if (field->fld_flags & FLD_delete) { put_symbol(request, isc_dyn_delete_local_fld, field->fld_symbol); request->add_end(); } else if (field->fld_flags & FLD_meta) { if (field->fld_global) { put_symbol(request, isc_dyn_def_local_fld, field->fld_symbol); put_symbol(request, isc_dyn_fld_source, field->fld_global); } else put_symbol(request, isc_dyn_def_sql_fld, field->fld_symbol); put_field_attributes(request, field); if (field->fld_default_value) { put_blr(request, isc_dyn_fld_default_value, field->fld_default_value, CME_expr); TEXT* default_source = (TEXT*) MSC_alloc(field->fld_default_source->txt_length + 1); CPR_get_text(default_source, field->fld_default_source); put_cstring(request, isc_dyn_fld_default_source, default_source); } request->add_end(); // Any constraints defined for field being added? if (field->fld_constraints) create_constraint(request, action, field->fld_constraints); } } // Check for any relation level ADD/DROP of constraints if (relation->rel_constraints) { for (const cnstrt* constraint = relation->rel_constraints; constraint; constraint = constraint->cnstrt_next) { if (constraint->cnstrt_flags & CNSTRT_delete) put_cstring(request, isc_dyn_delete_rel_constraint, constraint->cnstrt_name->str_string); } create_constraint(request, action, relation->rel_constraints); } request->add_end(); } //____________________________________________________________ // // Generate dyn for creating a CHECK constraint. // static void create_check_constraint( gpre_req* request, const act* action, cnstrt* constraint) { gpre_trg* trigger = (gpre_trg*) MSC_alloc(TRG_LEN); // create the INSERT trigger trigger->trg_type = PRE_STORE_TRIGGER; // "insert violates CHECK constraint on table" trigger->trg_message = NULL; trigger->trg_boolean = constraint->cnstrt_boolean; trigger->trg_source = (STR) MSC_alloc(constraint->cnstrt_text->txt_length + 1); CPR_get_text(trigger->trg_source->str_string, constraint->cnstrt_text); create_trigger(request, action, trigger, CME_expr); // create the UPDATE trigger trigger->trg_type = PRE_MODIFY_TRIGGER; // "update violates CHECK constraint on table" create_trigger(request, action, trigger, CME_expr); } //____________________________________________________________ // // Function // Generate blr to express: if (old.primary_key != new.primary_key). // do a column by column comparison. // static void create_trg_firing_cond( gpre_req* request, const cnstrt* constraint) { // count primary key columns const gpre_lls* prim_key_fld = constraint->cnstrt_referred_fields; const gpre_lls* field = prim_key_fld; fb_assert(field != NULL); USHORT prim_key_num_flds = 0; while (field) { prim_key_num_flds++; field = field->lls_next; } fb_assert(prim_key_num_flds > 0); // generate blr request->add_byte(blr_if); if (prim_key_num_flds > 1) request->add_byte(blr_or); USHORT num_flds = 0; for (; prim_key_fld; prim_key_fld = prim_key_fld->lls_next) { request->add_byte(blr_neq); const str* prim_key_fld_name = (STR) prim_key_fld->lls_object; request->add_byte(blr_field); request->add_byte((SSHORT) 0); put_cstring(request, 0, prim_key_fld_name->str_string); request->add_byte(blr_field); request->add_byte((SSHORT) 1); put_cstring(request, 0, prim_key_fld_name->str_string); ++num_flds; if (prim_key_num_flds - num_flds >= 2) request->add_byte(blr_or); } } //____________________________________________________________ // // Function // Generate blr to express: foreign_key == primary_key // ie., for_key.column_1 = prim_key.column_1 and // for_key.column_2 = prim_key.column_2 and .... so on.. // static void create_matching_blr(gpre_req* request, const cnstrt* constraint) { // count primary key columns const gpre_lls* prim_key_fld = constraint->cnstrt_referred_fields; const gpre_lls* field = prim_key_fld; fb_assert(field != NULL); USHORT prim_key_num_flds = 0; while (field) { prim_key_num_flds++; field = field->lls_next; } fb_assert(prim_key_num_flds > 0); // count of foreign key columns const gpre_lls* for_key_fld = constraint->cnstrt_fields; field = for_key_fld; fb_assert(field != NULL); USHORT for_key_num_flds = 0; while (field) { for_key_num_flds++; field = field->lls_next; } fb_assert(for_key_num_flds > 0); fb_assert(prim_key_num_flds == for_key_num_flds); request->add_byte(blr_boolean); if (prim_key_num_flds > 1) request->add_byte(blr_and); USHORT num_flds = 0; do { request->add_byte(blr_eql); const str* for_key_fld_name = (STR) for_key_fld->lls_object; const str* prim_key_fld_name = (STR) prim_key_fld->lls_object; request->add_byte(blr_field); request->add_byte((SSHORT) 2); put_cstring(request, 0, for_key_fld_name->str_string); request->add_byte(blr_field); request->add_byte((SSHORT) 0); put_cstring(request, 0, prim_key_fld_name->str_string); ++num_flds; if (prim_key_num_flds - num_flds >= 2) request->add_byte(blr_and); for_key_fld = for_key_fld->lls_next; prim_key_fld = prim_key_fld->lls_next; } while (num_flds < for_key_num_flds); request->add_byte(blr_end); } //____________________________________________________________ // Function: // The default_blr is passed in default_buffer. It is of the form: // blr_version4 blr_literal ..... blr_eoc. // strip the blr_version4/blr_version5 and blr_eoc verbs and stuff the remaining // blr in the blr stream in the request. // static void create_default_blr( gpre_req* request, const TEXT* default_buff, const USHORT buff_size) { int i; fb_assert(*default_buff == blr_version4 || *default_buff == blr_version5); for (i = 1; ((i < buff_size) && (default_buff[i] != blr_eoc)); i++) request->add_byte(default_buff[i]); fb_assert(default_buff[i] == blr_eoc); } //____________________________________________________________ // // Generate dyn for "on update cascade" trigger (for referential // integrity) along with the trigger blr. // static void create_upd_cascade_trg( gpre_req* request, const act* action, cnstrt* constraint) { gpre_lls* for_key_fld = constraint->cnstrt_fields; gpre_lls* prim_key_fld = constraint->cnstrt_referred_fields; gpre_rel* relation = (gpre_rel*) action->act_object; // no trigger name is generated here. Let the engine make one up put_string(request, isc_dyn_def_trigger, "", (USHORT) 0); put_numeric(request, isc_dyn_trg_type, (SSHORT) POST_MODIFY_TRIGGER); request->add_byte(isc_dyn_sql_object); put_numeric(request, isc_dyn_trg_sequence, (SSHORT) 1); put_numeric(request, isc_dyn_trg_inactive, (SSHORT) 0); put_cstring(request, isc_dyn_rel_name, constraint->cnstrt_referred_rel->str_string); // the trigger blr request->add_byte(isc_dyn_trg_blr); const USHORT offset = request->req_blr - request->req_base; request->add_word(0); if (request->req_flags & REQ_blr_version4) request->add_byte(blr_version4); else request->add_byte(blr_version5); create_trg_firing_cond(request, constraint); request->add_byte(blr_begin); request->add_byte(blr_begin); request->add_byte(blr_for); request->add_byte(blr_rse); // the new context for the prim. key relation request->add_byte(1); request->add_byte(blr_relation); put_cstring(request, 0, relation->rel_symbol->sym_string); // the context for the foreign key relation request->add_byte(2); // generate the blr for: foreign_key == primary_key create_matching_blr(request, constraint); request->add_byte(blr_modify); request->add_byte((SSHORT) 2); request->add_byte((SSHORT) 2); request->add_byte(blr_begin); for (; for_key_fld && prim_key_fld; for_key_fld = for_key_fld->lls_next, prim_key_fld = prim_key_fld->lls_next) { const str* for_key_fld_name = (STR) for_key_fld->lls_object; const str* prim_key_fld_name = (STR) prim_key_fld->lls_object; request->add_byte(blr_assignment); request->add_byte(blr_field); request->add_byte((SSHORT) 1); put_cstring(request, 0, prim_key_fld_name->str_string); request->add_byte(blr_field); request->add_byte((SSHORT) 2); put_cstring(request, 0, for_key_fld_name->str_string); } request->add_byte(blr_end); request->add_byte(blr_end); request->add_byte(blr_end); request->add_byte(blr_end); request->add_byte(blr_eoc); const USHORT length = request->req_blr - request->req_base - offset - 2; request->req_base[offset] = (UCHAR) length; request->req_base[offset + 1] = (UCHAR) (length >> 8); // end of the blr // no trg_source and no trg_description request->add_byte(isc_dyn_end); } //____________________________________________________________ // // Generate dyn for "on delete cascade" trigger (for referential // integrity) along with the trigger blr. // static void create_del_cascade_trg( gpre_req* request, const act* action, cnstrt* constraint) { const gpre_rel* relation = (gpre_rel*) action->act_object; // stuff a trigger_name of size 0. So the dyn-parser will make one up. put_string(request, isc_dyn_def_trigger, "", (USHORT) 0); put_numeric(request, isc_dyn_trg_type, (SSHORT) POST_ERASE_TRIGGER); request->add_byte(isc_dyn_sql_object); put_numeric(request, isc_dyn_trg_sequence, (SSHORT) 1); put_numeric(request, isc_dyn_trg_inactive, (SSHORT) 0); put_cstring(request, isc_dyn_rel_name, constraint->cnstrt_referred_rel->str_string); // the trigger blr request->add_byte(isc_dyn_trg_blr); const USHORT offset = request->req_blr - request->req_base; request->add_word(0); if (request->req_flags & REQ_blr_version4) request->add_byte(blr_version4); else request->add_byte(blr_version5); request->add_byte(blr_for); request->add_byte(blr_rse); // the context for the prim. key relation request->add_byte(1); request->add_byte(blr_relation); put_cstring(request, 0, relation->rel_symbol->sym_string); // the context for the foreign key relation request->add_byte(2); create_matching_blr(request, constraint); request->add_byte(blr_erase); request->add_byte((SSHORT) 2); request->add_byte(blr_eoc); const USHORT length = request->req_blr - request->req_base - offset - 2; request->req_base[offset] = (UCHAR) length; request->req_base[offset + 1] = (UCHAR) (length >> 8); // end of the blr // no trg_source and no trg_description request->add_byte(isc_dyn_end); } //____________________________________________________________ // // Generate dyn for "on delete|update set default" trigger (for // referential integrity) along with the trigger blr. // The non_upd_trg parameter == true is an update trigger. // static void create_set_default_trg(gpre_req* request, const act* action, cnstrt* constraint, bool on_upd_trg) { gpre_rel* rel; gpre_req* req; act* request_action; TEXT s[512]; TEXT default_val[BLOB_BUFFER_SIZE]; fb_assert(request->req_actions->act_type == ACT_create_table || request->req_actions->act_type == ACT_alter_table); gpre_lls* for_key_fld = constraint->cnstrt_fields; const gpre_rel* relation = (gpre_rel*) action->act_object; // no trigger name. It is generated by the engine put_string(request, isc_dyn_def_trigger, "", (USHORT) 0); put_numeric(request, isc_dyn_trg_type, (SSHORT) (on_upd_trg ? POST_MODIFY_TRIGGER : POST_ERASE_TRIGGER)); request->add_byte(isc_dyn_sql_object); put_numeric(request, isc_dyn_trg_sequence, (SSHORT) 1); put_numeric(request, isc_dyn_trg_inactive, (SSHORT) 0); put_cstring(request, isc_dyn_rel_name, constraint->cnstrt_referred_rel->str_string); // the trigger blr request->add_byte(isc_dyn_trg_blr); const USHORT offset = request->req_blr - request->req_base; request->add_word(0); if (request->req_flags & REQ_blr_version4) request->add_byte(blr_version4); else request->add_byte(blr_version5); // 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_upd_trg) { create_trg_firing_cond(request, constraint); request->add_byte(blr_begin); request->add_byte(blr_begin); } request->add_byte(blr_for); request->add_byte(blr_rse); // the context for the prim. key relation request->add_byte(1); request->add_byte(blr_relation); put_cstring(request, 0, relation->rel_symbol->sym_string); // the context for the foreign key relation request->add_byte(2); create_matching_blr(request, constraint); request->add_byte(blr_modify); request->add_byte((SSHORT) 2); request->add_byte((SSHORT) 2); request->add_byte(blr_begin); for (; for_key_fld; for_key_fld = for_key_fld->lls_next) { // for every column in the foreign key .... const str* for_key_fld_name = (STR) for_key_fld->lls_object; request->add_byte(blr_assignment); /* here stuff the default value as blr_literal .... or blr_null if this column does not have an applicable default */ /* the default is determined in many cases: (1) The default-info for the column is in memory. (This is because the column is being created in this application) (1-a) the table has a column level default. We get this by searching both current ddl statement and requests linked list. (1-b) the table does not have a column level default, but has a domain default. We get this by searching requests linked list. (2) The default-info for the column is not in memory. We get the column and/or domain default value from the system tables by calling MET_get_column_default/MET_get_domain_defult */ bool search_for_default = true; bool search_for_column = false; const TEXT* search_for_domain = NULL; // Is the column being created in this ddl statement? gpre_fld* field; for (field = relation->rel_fields; field; field = field->fld_next) { if (strcmp(field->fld_symbol->sym_string, for_key_fld_name->str_string) == 0) { break; } } if (field) { // Yes. The column is being created in this ddl statement if (field->fld_default_value) { // (1-a) CME_expr(field->fld_default_value, request); search_for_default = false; } else { // check for domain default if (field->fld_global) { // could be either (1-b) or (2) search_for_domain = field->fld_global->sym_string; } else { request->add_byte(blr_null); search_for_default = false; } } } else { // Nop. The column is not being created in this ddl statement if (request->req_actions->act_type == ACT_create_table) { sprintf(s, "field \"%s\" does not exist in relation \"%s\"", for_key_fld_name->str_string, relation->rel_symbol->sym_string); CPR_error(s); } // Thus we have an ALTER TABLE statement. // If somebody is 'clever' enough to create table and then to alter it // within the same application ... for (req = gpreGlob.requests; req; req = req->req_next) { if ((req->req_type == REQ_ddl) && (request_action = req->req_actions) && (request_action->act_type == ACT_create_table || request_action->act_type == ACT_alter_table) && (rel = (gpre_rel*) request_action->act_object) && (strcmp(rel->rel_symbol->sym_string, relation->rel_symbol->sym_string) == 0)) { // ... then try to check for the default in memory gpre_fld* fld; for (fld = (gpre_fld*) rel->rel_fields; fld; fld = fld->fld_next) { if (strcmp(fld->fld_symbol->sym_string, for_key_fld_name->str_string) != 0) continue; if (fld->fld_default_value) { // case (1-a): CME_expr(fld->fld_default_value, request); search_for_default = false; } else { if (fld->fld_global) { search_for_domain = fld->fld_global->sym_string; } else { // default not found request->add_byte(blr_null); search_for_default = false; } } break; } if (fld) break; } } if (!req) search_for_column = true; } if (search_for_default && search_for_domain != NULL) { // search for domain level default fb_assert(search_for_column == false); // search for domain in memory for (req = gpreGlob.requests; req; req = req->req_next) { gpre_fld* domain; if ((req->req_type == REQ_ddl) && (request_action = req->req_actions) && ((request_action->act_type == ACT_create_domain) || (request_action->act_type == ACT_alter_domain)) && (domain = (gpre_fld*) request_action->act_object) && (strcmp(search_for_domain, domain->fld_symbol->sym_string) == 0) && (domain->fld_default_value->nod_type != nod_erase)) { // domain found in memory if (domain->fld_default_value) { // case (1-b) CME_expr(domain->fld_default_value, request); } else { // default not found request->add_byte(blr_null); } search_for_default = false; break; } } if (search_for_default) { // search for domain in db system tables if (MET_get_domain_default(relation->rel_database, search_for_domain, default_val, sizeof(default_val))) { create_default_blr(request, default_val, sizeof(default_val)); } else { request->add_byte(blr_null); } search_for_default = false; } } // end of search for domain level default if (search_for_default && search_for_column) { // nothing is found in memory, try to check db system tables fb_assert(search_for_domain == NULL); if (MET_get_column_default(relation, for_key_fld_name->str_string, default_val, sizeof(default_val)) != FALSE) { create_default_blr(request, default_val, sizeof(default_val)); } else { request->add_byte(blr_null); } } // the context for the foreign key relation request->add_byte(blr_field); request->add_byte((SSHORT) 2); put_cstring(request, 0, for_key_fld_name->str_string); } request->add_byte(blr_end); if (on_upd_trg) { request->add_byte(blr_end); request->add_byte(blr_end); request->add_byte(blr_end); } request->add_byte(blr_eoc); const USHORT length = request->req_blr - request->req_base - offset - 2; request->req_base[offset] = (UCHAR) length; request->req_base[offset + 1] = (UCHAR) (length >> 8); // end of the blr // no trg_source and no trg_description request->add_byte(isc_dyn_end); } //____________________________________________________________ // // Generate dyn for "on delete|update set null" trigger (for // referential integrity). The trigger blr is the same for // both the delete and update cases. Only differences is its // TRIGGER_TYPE (ON DELETE or ON UPDATE). // The non_upd_trg parameter == true is an update trigger. // static void create_set_null_trg(gpre_req* request, const act* action, cnstrt* constraint, bool on_upd_trg) { gpre_lls* for_key_fld = constraint->cnstrt_fields; const gpre_rel* relation = (gpre_rel*) action->act_object; // no trigger name. It is generated by the engine put_string(request, isc_dyn_def_trigger, "", (USHORT) 0); put_numeric(request, isc_dyn_trg_type, (SSHORT) (on_upd_trg ? POST_MODIFY_TRIGGER : POST_ERASE_TRIGGER)); request->add_byte(isc_dyn_sql_object); put_numeric(request, isc_dyn_trg_sequence, (SSHORT) 1); put_numeric(request, isc_dyn_trg_inactive, (SSHORT) 0); put_cstring(request, isc_dyn_rel_name, constraint->cnstrt_referred_rel->str_string); // the trigger blr request->add_byte(isc_dyn_trg_blr); const USHORT offset = request->req_blr - request->req_base; request->add_word(0); if (request->req_flags & REQ_blr_version4) request->add_byte(blr_version4); else request->add_byte(blr_version5); // 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_upd_trg) { create_trg_firing_cond(request, constraint); request->add_byte(blr_begin); request->add_byte(blr_begin); } request->add_byte(blr_for); request->add_byte(blr_rse); // the context for the prim. key relation request->add_byte(1); request->add_byte(blr_relation); put_cstring(request, 0, relation->rel_symbol->sym_string); // the context for the foreign key relation request->add_byte(2); create_matching_blr(request, constraint); request->add_byte(blr_modify); request->add_byte((SSHORT) 2); request->add_byte((SSHORT) 2); request->add_byte(blr_begin); for (; for_key_fld; for_key_fld = for_key_fld->lls_next) { const str* for_key_fld_name = (STR) for_key_fld->lls_object; request->add_byte(blr_assignment); request->add_byte(blr_null); request->add_byte(blr_field); request->add_byte((SSHORT) 2); put_cstring(request, 0, for_key_fld_name->str_string); } request->add_byte(blr_end); if (on_upd_trg) { request->add_byte(blr_end); request->add_byte(blr_end); request->add_byte(blr_end); } request->add_byte(blr_eoc); const USHORT length = request->req_blr - request->req_base - offset - 2; request->req_base[offset] = (UCHAR) length; request->req_base[offset + 1] = (UCHAR) (length >> 8); // end of the blr // no trg_source and no trg_description request->add_byte(isc_dyn_end); } //____________________________________________________________ // // Get referred fields from memory/system tables // static void get_referred_fields(const act* action, cnstrt* constraint) { TEXT s[512]; const gpre_rel* relation = (gpre_rel*) action->act_object; for (gpre_req* req = gpreGlob.requests; req; req = req->req_next) { const act* request_action; const gpre_rel* rel; if ((req->req_type == REQ_ddl) && (request_action = req->req_actions) && (request_action->act_type == ACT_create_table || request_action->act_type == ACT_alter_table) && (rel = (gpre_rel*) request_action->act_object) && (strcmp(rel->rel_symbol->sym_string, constraint->cnstrt_referred_rel->str_string) == 0)) { for (const cnstrt* cns = rel->rel_constraints; cns; cns = cns->cnstrt_next) { if (cns->cnstrt_type == CNSTRT_PRIMARY_KEY) { constraint->cnstrt_referred_fields = cns->cnstrt_fields; break; } } if (!constraint->cnstrt_referred_fields && rel->rel_fields) for (const cnstrt* cns = rel->rel_fields->fld_constraints; cns; cns = cns->cnstrt_next) { if (cns->cnstrt_type == CNSTRT_PRIMARY_KEY) { constraint->cnstrt_referred_fields = cns->cnstrt_fields; break; } } if (constraint->cnstrt_referred_fields) break; } } if (constraint->cnstrt_referred_fields == NULL) // Nothing is in memory. Try to find in system tables constraint->cnstrt_referred_fields = MET_get_primary_key(relation->rel_database, constraint->cnstrt_referred_rel->str_string); if (constraint->cnstrt_referred_fields == NULL) { // Nothing is in system tables. sprintf(s, "\"REFERENCES %s\" without \"(column list)\" requires PRIMARY KEY on referenced table", constraint->cnstrt_referred_rel->str_string); CPR_error(s); } else { // count both primary key and foreign key columns USHORT prim_key_num_flds = 0, for_key_num_flds = 0; const gpre_lls* field = constraint->cnstrt_referred_fields; while (field) { prim_key_num_flds++; field = field->lls_next; } field = constraint->cnstrt_fields; while (field) { for_key_num_flds++; field = field->lls_next; } if (prim_key_num_flds != for_key_num_flds) { sprintf(s, "PRIMARY KEY column count in relation \"%s\" does not match FOREIGN KEY in relation \"%s\"", constraint->cnstrt_referred_rel->str_string, relation->rel_symbol->sym_string); CPR_error(s); } } } //____________________________________________________________ // // Generate dyn for creating a constraint. // static void create_constraint( gpre_req* request, const act* action, cnstrt* constraint) { for (; constraint; constraint = constraint->cnstrt_next) { if (constraint->cnstrt_flags & CNSTRT_delete) continue; put_cstring(request, isc_dyn_rel_constraint, constraint->cnstrt_name->str_string); switch (constraint->cnstrt_type) { case CNSTRT_PRIMARY_KEY: request->add_byte(isc_dyn_def_primary_key); break; case CNSTRT_UNIQUE: request->add_byte(isc_dyn_def_unique); break; case CNSTRT_FOREIGN_KEY: request->add_byte(isc_dyn_def_foreign_key); break; case CNSTRT_NOT_NULL: request->add_byte(isc_dyn_fld_not_null); request->add_end(); continue; case CNSTRT_CHECK: create_check_constraint(request, action, constraint); request->add_end(); continue; default: fb_assert(false); } // stuff a zero-length name, indicating that an index // name should be generated request->add_word(0); if (constraint->cnstrt_type == CNSTRT_FOREIGN_KEY) { // If is not specified try to catch // them right here if (constraint->cnstrt_referred_fields == NULL) get_referred_fields(action, constraint); if (constraint->cnstrt_fkey_def_type & REF_UPDATE_ACTION) { request->add_byte(isc_dyn_foreign_key_update); switch (constraint->cnstrt_fkey_def_type & REF_UPDATE_MASK) { case REF_UPD_NONE: request->add_byte(isc_dyn_foreign_key_none); break; case REF_UPD_CASCADE: request->add_byte(isc_dyn_foreign_key_cascade); create_upd_cascade_trg(request, action, constraint); break; case REF_UPD_SET_DEFAULT: request->add_byte(isc_dyn_foreign_key_default); create_set_default_trg(request, action, constraint, true); break; case REF_UPD_SET_NULL: request->add_byte(isc_dyn_foreign_key_null); create_set_null_trg(request, action, constraint, true); break; default: // just in case fb_assert(0); request->add_byte(isc_dyn_foreign_key_none); break; } } if (constraint->cnstrt_fkey_def_type & REF_DELETE_ACTION) { request->add_byte(isc_dyn_foreign_key_delete); switch (constraint->cnstrt_fkey_def_type & REF_DELETE_MASK) { case REF_DEL_NONE: request->add_byte(isc_dyn_foreign_key_none); break; case REF_DEL_CASCADE: request->add_byte(isc_dyn_foreign_key_cascade); create_del_cascade_trg(request, action, constraint); break; case REF_DEL_SET_DEFAULT: request->add_byte(isc_dyn_foreign_key_default); create_set_default_trg(request, action, constraint, false); break; case REF_DEL_SET_NULL: request->add_byte(isc_dyn_foreign_key_null); create_set_null_trg(request, action, constraint, false); break; default: // just in case fb_assert(0); request->add_byte(isc_dyn_foreign_key_none); break; } } } else put_numeric(request, isc_dyn_idx_unique, 1); for (const gpre_lls* field = constraint->cnstrt_fields; field; field = field->lls_next) { const str* string = (STR) field->lls_object; put_cstring(request, isc_dyn_fld_name, string->str_string); } if (constraint->cnstrt_type == CNSTRT_FOREIGN_KEY) { put_cstring(request, isc_dyn_idx_foreign_key, constraint->cnstrt_referred_rel->str_string); for (const gpre_lls* field = constraint->cnstrt_referred_fields; field; field = field->lls_next) { const str* string = (STR) field->lls_object; put_cstring(request, isc_dyn_idx_ref_column, string->str_string); } } request->add_end(); } } //____________________________________________________________ // // Generate parameter buffer for CREATE DATABASE action. // static void create_database( gpre_req* request, const act* action) { const dbb* db = ((mdbb*) action->act_object)->mdbb_database; request->add_byte(isc_dpb_version1); request->add_byte(isc_dpb_overwrite); request->add_byte(1); request->add_byte(0); request->add_byte(isc_dpb_sql_dialect); request->add_byte(sizeof(int)); int def_db_dial = 3; if ((gpreGlob.dialect_specified) && (gpreGlob.sw_sql_dialect == 1 || gpreGlob.sw_sql_dialect == 3)) def_db_dial = gpreGlob.sw_sql_dialect; request->add_long(def_db_dial); if (db->dbb_allocation) { request->add_byte(isc_dpb_allocation); request->add_byte(4); request->add_long(db->dbb_allocation); } if (db->dbb_pagesize) { request->add_byte(isc_dpb_page_size); request->add_byte(4); request->add_long(db->dbb_pagesize); } if (db->dbb_buffercount) { request->add_byte(isc_dpb_num_buffers); request->add_byte(4); request->add_long(db->dbb_buffercount); } if (db->dbb_buffersize) { request->add_byte(isc_dpb_buffer_length); request->add_byte(4); request->add_long(db->dbb_buffersize); } if (db->dbb_users) { request->add_byte(isc_dpb_number_of_users); request->add_byte(4); request->add_long(db->dbb_users); } SSHORT l; if (db->dbb_c_user && !db->dbb_r_user) { request->add_byte(isc_dpb_user_name); l = strlen(db->dbb_c_user); request->add_byte(l); const char* ch = db->dbb_c_user; while (*ch) request->add_byte(*ch++); } if (db->dbb_c_password && !db->dbb_r_password) { request->add_byte(isc_dpb_password); l = strlen(db->dbb_c_password); request->add_byte(l); const char* ch = db->dbb_c_password; while (*ch) request->add_byte(*ch++); } *request->req_blr = 0; request->req_length = request->req_blr - request->req_base; if (request->req_length == 1) request->req_length = 0; request->req_blr = request->req_base; } //____________________________________________________________ // // Generate dynamic DDL for second stage of create database // static void create_database_modify_dyn( gpre_req* request, act* action) { dbb* db = ((mdbb*) action->act_object)->mdbb_database; request->add_byte(isc_dyn_mod_database); // Reverse the order of files (parser left them backwards) FIL files = db->dbb_files; FIL file, next; for (file = files, files = NULL; file; file = next) { next = file->fil_next; file->fil_next = files; files = file; } SLONG start = db->dbb_length; for (file = files; file != NULL; file = file->fil_next) { put_cstring(request, isc_dyn_def_file, file->fil_name); request->add_byte(isc_dyn_file_start); request->add_word(4); start = MAX(start, file->fil_start); request->add_long(start); request->add_byte(isc_dyn_file_length); request->add_word(4); request->add_long(file->fil_length); request->add_end(); start += file->fil_length; } /* if (db->dbb_cache_file) add_cache(request, action, db); */ if (db->dbb_def_charset) put_cstring(request, isc_dyn_fld_character_set_name, db->dbb_def_charset); request->add_end(); } //____________________________________________________________ // // Generate dynamic DDL for CREATE DOMAIN action. // static void create_domain( gpre_req* request, const act* action) { const gpre_fld* field = (gpre_fld*) action->act_object; // add field info put_symbol(request, isc_dyn_def_global_fld, field->fld_symbol); put_field_attributes(request, field); if (field->fld_default_value) { put_blr(request, isc_dyn_fld_default_value, field->fld_default_value, CME_expr); TEXT* default_source = (TEXT*) MSC_alloc(field->fld_default_source->txt_length + 1); CPR_get_text(default_source, field->fld_default_source); put_cstring(request, isc_dyn_fld_default_source, default_source); } if (field->fld_constraints) create_domain_constraint(request, action, field->fld_constraints); request->add_end(); } //____________________________________________________________ // // Generate dyn for creating a constraints for domains. // static void create_domain_constraint(gpre_req* request, const act* action, const cnstrt* constraint) { for (; constraint; constraint = constraint->cnstrt_next) { if (constraint->cnstrt_flags & CNSTRT_delete) continue; // **** this will be used later // put_cstring (request, isc_dyn_rel_constraint, constraint->cnstrt_name->str_string); //*** if (constraint->cnstrt_type == CNSTRT_CHECK) { TEXT* source = (TEXT*) MSC_alloc(constraint->cnstrt_text->txt_length + 1); CPR_get_text(source, constraint->cnstrt_text); if (source != NULL) put_cstring(request, isc_dyn_fld_validation_source, source); put_blr(request, isc_dyn_fld_validation_blr, constraint->cnstrt_boolean, CME_expr); } } } //____________________________________________________________ // // Generate dynamic DDL for creating a generator. // static void create_generator( gpre_req* request, const act* action) { const TEXT* generator_name = (TEXT*) action->act_object; put_cstring(request, isc_dyn_def_generator, generator_name); request->add_end(); } //____________________________________________________________ // // Generate dynamic DDL for CREATE INDEX action. // static void create_index( gpre_req* request, const ind* index) { if (index->ind_symbol) put_symbol(request, isc_dyn_def_idx, index->ind_symbol); else { // An index created because of the UNIQUE constraint on this field. put_cstring(request, isc_dyn_def_idx, ""); } put_symbol(request, isc_dyn_rel_name, index->ind_relation->rel_symbol); if (index->ind_flags & IND_dup_flag) put_numeric(request, isc_dyn_idx_unique, 1); if (index->ind_flags & IND_descend) put_numeric(request, isc_dyn_idx_type, 1); if (index->ind_symbol) { for (const gpre_fld* field = index->ind_fields; field; field = field->fld_next) { put_symbol(request, isc_dyn_fld_name, field->fld_symbol); } } else { // An index created on this one field because of the // UNIQUE constraint on this field. put_symbol(request, isc_dyn_fld_name, index->ind_fields->fld_symbol); } request->add_end(); } //____________________________________________________________ // // Generate dynamic DDL for creating a shadow // static void create_shadow( gpre_req* request, act* action) { fil* files = (FIL) action->act_object; // Reverse the order of files (parser left them backwards) FIL file, next; for (file = files, files = NULL; file; file = next) { next = file->fil_next; file->fil_next = files; files = file; } put_numeric(request, isc_dyn_def_shadow, (SSHORT) files->fil_shadow_number); for (file = files; file != NULL; file = file->fil_next) { put_cstring(request, isc_dyn_def_file, file->fil_name); request->add_byte(isc_dyn_file_start); request->add_word(4); const SLONG start = file->fil_start; request->add_long(start); request->add_byte(isc_dyn_file_length); request->add_word(4); request->add_long(file->fil_length); if (file->fil_flags & FIL_manual) put_numeric(request, isc_dyn_shadow_man_auto, 1); if (file->fil_flags & FIL_conditional) put_numeric(request, isc_dyn_shadow_conditional, 1); request->add_end(); } request->add_end(); } //____________________________________________________________ // // Generate dynamic DDL for CREATE TABLE action. // static void create_table( gpre_req* request, const act* action) { // add relation name const gpre_rel* relation = (gpre_rel*) action->act_object; put_symbol(request, isc_dyn_def_rel, relation->rel_symbol); // If the relation is defined as an external file, add dyn for that if (relation->rel_ext_file) put_cstring(request, isc_dyn_rel_ext_file, relation->rel_ext_file); put_numeric(request, isc_dyn_rel_sql_protection, 1); // add field info const gpre_fld* field; USHORT position = 0; for (field = relation->rel_fields; field; field = field->fld_next) { if (field->fld_global) { put_symbol(request, isc_dyn_def_local_fld, field->fld_symbol); put_symbol(request, isc_dyn_fld_source, field->fld_global); } else put_symbol(request, isc_dyn_def_sql_fld, field->fld_symbol); put_field_attributes(request, field); put_numeric(request, isc_dyn_fld_position, position++); if (field->fld_default_value) { put_blr(request, isc_dyn_fld_default_value, field->fld_default_value, CME_expr); TEXT* default_source = (TEXT*) MSC_alloc(field->fld_default_source->txt_length + 1); CPR_get_text(default_source, field->fld_default_source); put_cstring(request, isc_dyn_fld_default_source, default_source); } request->add_end(); if (field->fld_constraints) create_constraint(request, action, field->fld_constraints); } if (relation->rel_constraints) create_constraint(request, action, relation->rel_constraints); request->add_end(); // Need to create an index for any fields (columns) declared with // the UNIQUE constraint. for (field = relation->rel_fields; field; field = field->fld_next) if (field->fld_index) create_index(request, field->fld_index); } //____________________________________________________________ // // Generate dynamic DDL for a trigger. // static void create_trigger(gpre_req* request, const act* action, gpre_trg* trigger, pfn_local_trigger_cb routine) { const gpre_rel* relation = (gpre_rel*) action->act_object; // Name of trigger to be generated put_cstring(request, isc_dyn_def_trigger, ""); put_symbol(request, isc_dyn_rel_name, relation->rel_symbol); put_numeric(request, isc_dyn_trg_type, trigger->trg_type); put_numeric(request, isc_dyn_trg_sequence, 0); put_numeric(request, isc_dyn_trg_inactive, 0); request->add_byte(isc_dyn_sql_object); if (trigger->trg_source != NULL) put_cstring(request, isc_dyn_trg_source, trigger->trg_source->str_string); if (trigger->trg_message != NULL) { put_numeric(request, isc_dyn_def_trigger_msg, 1); put_cstring(request, isc_dyn_trg_msg, trigger->trg_message->str_string); request->add_byte(isc_dyn_end); } // Generate the BLR for firing the trigger put_trigger_blr(request, isc_dyn_trg_blr, trigger->trg_boolean, routine); request->add_end(); } //____________________________________________________________ // // Generate dynamic DDL for CREATE VIEW action. // static bool create_view(gpre_req* request, act* action) { // add relation name gpre_rel* relation = (gpre_rel*) action->act_object; put_symbol(request, isc_dyn_def_view, relation->rel_symbol); put_numeric(request, isc_dyn_rel_sql_protection, 1); // write out blr put_blr(request, isc_dyn_view_blr, (GPRE_NOD) relation->rel_view_rse, reinterpret_cast(CME_rse)); // write out view source TEXT* view_source = (TEXT *) MSC_alloc(relation->rel_view_text->txt_length + 1); CPR_get_text(view_source, relation->rel_view_text); put_cstring(request, isc_dyn_view_source, view_source); // Write out view context info gpre_rel* sub_relation = 0; gpre_ctx* context; for (context = request->req_contexts; context; context = context->ctx_next) { sub_relation = context->ctx_relation; if (!sub_relation) continue; put_symbol(request, isc_dyn_view_relation, sub_relation->rel_symbol); put_numeric(request, isc_dyn_view_context, context->ctx_internal); if (context->ctx_symbol) put_symbol(request, isc_dyn_view_context_name, context->ctx_symbol); request->add_end(); } // add the mapping from the rse to the view fields gpre_fld* field = relation->rel_fields; gpre_nod* fields = relation->rel_view_rse->rse_fields; SSHORT position = 0; bool non_updateable = false; gpre_nod** ptr; const gpre_nod* const* end; for (ptr = fields->nod_arg, end = ptr + fields->nod_count; ptr < end; ptr++, field = (field) ? field->fld_next : NULL) { const gpre_fld* fld = NULL; gpre_nod* value = *ptr; if (value->nod_type == nod_field) { const ref* reference = (REF) value->nod_arg[0]; fld = reference->ref_field; const gpre_req* slice_req; const slc* slice; if ((value->nod_count >= 2) && (slice_req = (gpre_req*) value->nod_arg[2]) && (slice = slice_req->req_slice)) { CPR_error("Array slices not supported in views"); } context = reference->ref_context; } const gpre_sym* symbol; if (field) symbol = field->fld_symbol; else if (fld) symbol = fld->fld_symbol; else { request->req_length = 0; CPR_error("view expression requires field name"); return false; } if (fld) { put_symbol(request, isc_dyn_def_local_fld, symbol); put_symbol(request, isc_dyn_fld_base_fld, fld->fld_symbol); put_numeric(request, isc_dyn_view_context, context->ctx_internal); } else { non_updateable = true; put_symbol(request, isc_dyn_def_sql_fld, symbol); put_blr(request, isc_dyn_fld_computed_blr, value, CME_expr); gpre_fld tmp_field; init_field_struct(&tmp_field); CME_get_dtype(value, &tmp_field); put_dtype(request, &tmp_field); } put_numeric(request, isc_dyn_fld_position, position++); request->add_end(); } if (relation->rel_flags & REL_view_check) { // VIEW WITH CHECK OPTION // Make sure VIEW is updateable gpre_rse* select = relation->rel_view_rse; if ((select->rse_aggregate) || (non_updateable) || (select->rse_count != 1)) { CPR_error("Invalid view WITH CHECK OPTION - non-updateable view"); return false; } if (!select->rse_boolean) { CPR_error("Invalid view WITH CHECK OPTION - no WHERE clause"); return false; } gpre_trg* trigger = (gpre_trg*) MSC_alloc(TRG_LEN); // For the triggers, the OLD, NEW contexts are reserved request->req_internal = 0; request->req_contexts = 0; gpre_ctx* contexts[3]; // Make the OLD context for the trigger contexts[0] = request->req_contexts = context = MSC_context(request); context->ctx_relation = relation; // Make the NEW context for the trigger contexts[1] = request->req_contexts = context = MSC_context(request); context->ctx_relation = relation; // Make the context for the base relation contexts[2] = select->rse_context[0] = request->req_contexts = context = MSC_context(request); context->ctx_relation = sub_relation; // Make lists to assign from NEW fields to fields in the base relation. /* Also make sure rows in base relation correspond to rows in VIEW by making sure values in fields inherited by the VIEW are same as values in base relation. */ field = relation->rel_fields; fields = relation->rel_view_rse->rse_fields; gpre_nod* and_nod = 0; gpre_nod* or_node = 0; SSHORT count = 0; gpre_lls* stack = NULL; for (ptr = fields->nod_arg, end = ptr + fields->nod_count; ptr < end; ptr++, field = (field) ? field->fld_next : NULL) { gpre_fld* fld = NULL; gpre_nod* value = *ptr; if (value->nod_type == nod_field) { ref* reference = (REF) value->nod_arg[0]; reference->ref_context = contexts[2]; fld = reference->ref_field; } ref* view_ref = MSC_reference(0); view_ref->ref_context = contexts[0]; ref* new_view_ref = MSC_reference(0); new_view_ref->ref_context = contexts[1]; new_view_ref->ref_field = view_ref->ref_field = (field) ? field : fld; gpre_nod* view_field = MSC_unary(nod_field, (GPRE_NOD) view_ref); gpre_nod* new_view_field = MSC_unary(nod_field, (GPRE_NOD) new_view_ref); gpre_nod* anull_node = MSC_unary(nod_missing, view_field); gpre_nod* bnull_node = MSC_unary(nod_missing, value); gpre_nod* iand_node = MSC_binary(nod_and, anull_node, bnull_node); gpre_nod* eq_nod = MSC_binary(nod_eq, view_field, value); or_node = MSC_binary(nod_or, eq_nod, iand_node); gpre_nod* set_item = MSC_node(nod_assignment, 2); set_item->nod_arg[1] = value; set_item->nod_arg[0] = new_view_field; MSC_push(set_item, &stack); count++; if (!or_node) or_node = MSC_binary(nod_or, eq_nod, iand_node); else if (!and_nod) and_nod = MSC_binary(nod_and, or_node, MSC_binary(nod_or, eq_nod, iand_node)); else and_nod = MSC_binary(nod_and, and_nod, MSC_binary(nod_or, eq_nod, iand_node)); } gpre_nod* set_list = MSC_node(nod_list, count); ptr = set_list->nod_arg + count; while (stack) *--ptr = (GPRE_NOD) MSC_pop(&stack); // Modify the context of fields in boolean to be that of the // sub-relation. replace_field_names(select->rse_boolean, 0, 0, false, contexts); gpre_nod* view_boolean = select->rse_boolean; select->rse_boolean = MSC_binary(nod_and, (and_nod) ? and_nod : or_node, select->rse_boolean); // create the UPDATE trigger trigger->trg_type = PRE_MODIFY_TRIGGER; // "update violates CHECK constraint on view" trigger->trg_message = NULL; trigger->trg_boolean = (GPRE_NOD) select; create_view_trigger(request, action, trigger, view_boolean, contexts, set_list); // create the Pre-store trigger trigger->trg_type = PRE_STORE_TRIGGER; // "insert violates CHECK constraint on view" create_view_trigger(request, action, trigger, view_boolean, contexts, set_list); } request->add_end(); return true; } //____________________________________________________________ // // Generate dynamic DDL for a trigger. // static void create_view_trigger(gpre_req* request, const act* action, gpre_trg* trigger, gpre_nod* view_boolean, gpre_ctx** contexts, GPRE_NOD set_list) { const gpre_rel* relation = (gpre_rel*) action->act_object; // Name of trigger to be generated put_cstring(request, isc_dyn_def_trigger, ""); put_symbol(request, isc_dyn_rel_name, relation->rel_symbol); put_numeric(request, isc_dyn_trg_type, trigger->trg_type); put_numeric(request, isc_dyn_trg_sequence, 0); request->add_byte(isc_dyn_sql_object); if (trigger->trg_source != NULL) put_cstring(request, isc_dyn_trg_source, trigger->trg_source->str_string); if (trigger->trg_message != NULL) { put_numeric(request, isc_dyn_def_trigger_msg, 1); put_cstring(request, isc_dyn_trg_msg, trigger->trg_message->str_string); request->add_byte(isc_dyn_end); } // Generate the BLR for firing the trigger put_view_trigger_blr(request, relation, isc_dyn_trg_blr, trigger, view_boolean, contexts, set_list); request->add_end(); } //____________________________________________________________ // // Generate dynamic DDL for DECLARE FILTER action. // static void declare_filter( gpre_req* request, const act* action) { const fltr* filter = (FLTR) action->act_object; put_cstring(request, isc_dyn_def_filter, filter->fltr_name); put_numeric(request, isc_dyn_filter_in_subtype, filter->fltr_input_type); put_numeric(request, isc_dyn_filter_out_subtype, filter->fltr_output_type); put_cstring(request, isc_dyn_func_entry_point, filter->fltr_entry_point); put_cstring(request, isc_dyn_func_module_name, filter->fltr_module_name); request->add_end(); } //____________________________________________________________ // // Generate dynamic DDL for DECLARE EXTERNAL // static void declare_udf( gpre_req* request, const act* action) { const decl_udf* udf_declaration = (decl_udf*) action->act_object; const TEXT* udf_name = udf_declaration->decl_udf_name; put_cstring(request, isc_dyn_def_function, udf_name); put_cstring(request, isc_dyn_func_entry_point, udf_declaration->decl_udf_entry_point); put_cstring(request, isc_dyn_func_module_name, udf_declaration->decl_udf_module_name); // Reverse the order of arguments which parse left backwords. // //for (field = udf_declaration->decl_udf_arg_list, udf_declaration->decl_udf_arg_list = NULL; field; field = next) // { // next = field->fld_next; // field->fld_next = udf_declaration->decl_udf_arg_list; // udf_declaration->decl_udf_arg_list = field; // } // SSHORT position, blob_position = 0; const gpre_fld* field = udf_declaration->decl_udf_return_type; if (field) { // Function returns a value // Some data types can not be returned as value if ((udf_declaration->decl_udf_return_mode == 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)) { CPR_error ("return mode by value not allowed for this data type"); } // For functions returning a blob, coerce return argument position to // be the last parameter. if (field->fld_dtype == dtype_blob) { blob_position = 1; for (const gpre_fld* next = udf_declaration->decl_udf_arg_list; next; next = next->fld_next) { ++blob_position; } put_numeric(request, isc_dyn_func_return_argument, blob_position); } else put_numeric(request, isc_dyn_func_return_argument, 0); position = 0; } else { position = 1; // Function modifies an argument whose value is the function return value put_numeric(request, isc_dyn_func_return_argument, udf_declaration->decl_udf_return_parameter); } // Now define all the arguments if (!position) { if (field->fld_dtype == dtype_blob) { put_numeric(request, isc_dyn_def_function_arg, blob_position); put_numeric(request, isc_dyn_func_mechanism, FUN_blob_struct); } else { put_numeric(request, isc_dyn_def_function_arg, 0); put_numeric(request, isc_dyn_func_mechanism, udf_declaration->decl_udf_return_mode); } put_cstring(request, isc_dyn_function_name, udf_name); put_dtype(request, field); request->add_byte(isc_dyn_end); position = 1; } for (field = udf_declaration->decl_udf_arg_list; field; field = field->fld_next) { if (position > 10) CPR_error ("External functions can not have more than 10 parameters"); put_numeric(request, isc_dyn_def_function_arg, position++); if (field->fld_dtype == dtype_blob) put_numeric(request, isc_dyn_func_mechanism, FUN_blob_struct); else put_numeric(request, isc_dyn_func_mechanism, FUN_reference); put_cstring(request, isc_dyn_function_name, udf_name); put_dtype(request, field); request->add_byte(isc_dyn_end); } request->add_end(); } //____________________________________________________________ // // Generate dynamic DDL for GRANT or // REVOKE privileges action. // static void grant_revoke_privileges( gpre_req* request, const act* action) { TEXT privileges[7]; TEXT* p = privileges; const prv* priv_block = (PRV) action->act_object; if (priv_block->prv_privileges & PRV_select) *p++ = 'S'; if (priv_block->prv_privileges & PRV_insert) *p++ = 'I'; if (priv_block->prv_privileges & PRV_delete) *p++ = 'D'; if (priv_block->prv_privileges & PRV_execute) *p++ = 'X'; if (priv_block->prv_privileges & PRV_all) *p++ = 'A'; if (priv_block->prv_privileges & PRV_references) *p++ = 'R'; *p = 0; // If there are any select, insert, or delete privileges to be granted // or revoked output the necessary DYN strings if (p != privileges) for (priv_block = (PRV) action->act_object; priv_block; priv_block = priv_block->prv_next) { if (action->act_type == ACT_dyn_grant) put_cstring(request, isc_dyn_grant, privileges); else // action = ACT_dyn_revoke put_cstring(request, isc_dyn_revoke, privileges); put_cstring(request, priv_block->prv_object_dyn, priv_block->prv_relation->str_string); put_cstring(request, priv_block->prv_user_dyn, priv_block->prv_username); if ((priv_block->prv_privileges & PRV_grant_option) && ((action->act_type == ACT_dyn_grant) || !(request->req_database->dbb_flags & DBB_v3))) { put_numeric(request, isc_dyn_grant_options, 1); } request->add_end(); } // If there are no UPDATE privileges to be granted or revoked, we've finished if (!(((PRV) action->act_object)->prv_privileges & PRV_update)) return; p = privileges; *p++ = 'U'; *p = 0; for (priv_block = (PRV) action->act_object; priv_block; priv_block = priv_block->prv_next) { if (priv_block->prv_fields) { for (const gpre_lls* field = priv_block->prv_fields; field; field = field->lls_next) { if (action->act_type == ACT_dyn_grant) put_cstring(request, isc_dyn_grant, privileges); else // action->act_type == ACT_dyn_revoke put_cstring(request, isc_dyn_revoke, privileges); put_cstring(request, priv_block->prv_object_dyn, priv_block->prv_relation->str_string); const str* string = (STR) field->lls_object; put_cstring(request, isc_dyn_fld_name, string->str_string); put_cstring(request, priv_block->prv_user_dyn, priv_block->prv_username); if ((priv_block->prv_privileges & PRV_grant_option) && ((action->act_type == ACT_dyn_grant) || !(request->req_database->dbb_flags & DBB_v3))) { put_numeric(request, isc_dyn_grant_options, 1); } request->add_end(); } } else { // No specific fields mentioned; // UPDATE privilege granted or revoked on all fields if (action->act_type == ACT_dyn_grant) put_cstring(request, isc_dyn_grant, privileges); else // action->act_type == ACT_dyn_revoke put_cstring(request, isc_dyn_revoke, privileges); put_cstring(request, priv_block->prv_object_dyn, priv_block->prv_relation->str_string); put_cstring(request, priv_block->prv_user_dyn, priv_block->prv_username); if ((priv_block->prv_privileges & PRV_grant_option) && ((action->act_type == ACT_dyn_grant) || !(request->req_database->dbb_flags & DBB_v3))) { put_numeric(request, isc_dyn_grant_options, 1); } request->add_end(); } } } //____________________________________________________________ // // // static void init_field_struct( gpre_fld* field) { field->fld_dtype = 0; field->fld_length = 0; field->fld_scale = 0; field->fld_id = 0; field->fld_flags = 0; field->fld_seg_length = 0; field->fld_position = 0; field->fld_sub_type = 0; field->fld_next = 0; field->fld_array = 0; field->fld_relation = 0; field->fld_procedure = 0; field->fld_symbol = 0; field->fld_global = 0; field->fld_array_info = 0; field->fld_default_value = 0; field->fld_default_source = 0; field->fld_index = 0; field->fld_constraints = 0; field->fld_character_set = 0; field->fld_collate = 0; field->fld_computed = 0; field->fld_char_length = 0; field->fld_charset_id = 0; field->fld_collate_id = 0; } //____________________________________________________________ // // Put dimensions for the array field. // static void put_array_info( gpre_req* request, const gpre_fld* field) { const ary* array_info = field->fld_array_info; const SSHORT dims = (SSHORT) array_info->ary_dimension_count; put_numeric(request, isc_dyn_fld_dimensions, dims); for (SSHORT i = 0; i < dims; ++i) { put_numeric(request, isc_dyn_def_dimension, i); request->add_byte(isc_dyn_dim_lower); const SLONG lrange = (SLONG) (array_info->ary_rpt[i].ary_lower); request->add_word(4); request->add_long(lrange); request->add_byte(isc_dyn_dim_upper); const SLONG urange = (SLONG) (array_info->ary_rpt[i].ary_upper); request->add_word(4); request->add_long(urange); request->add_byte(isc_dyn_end); } } //____________________________________________________________ // // Put an expression expressed in BLR. // static void put_blr(gpre_req* request, USHORT blr_operator, GPRE_NOD node, pfn_local_trigger_cb routine) { request->add_byte(blr_operator); const USHORT offset = request->req_blr - request->req_base; request->add_word(0); if (request->req_flags & REQ_blr_version4) request->add_byte(blr_version4); else request->add_byte(blr_version5); (*routine) (node, request); request->add_byte(blr_eoc); const USHORT length = request->req_blr - request->req_base - offset - 2; request->req_base[offset] = (UCHAR) length; request->req_base[offset + 1] = (UCHAR) (length >> 8); } //____________________________________________________________ // // Generate dynamic DDL for a computed field. // static void put_computed_blr( gpre_req* request, const gpre_fld* field) { const act* action = request->req_actions; const gpre_rel* relation = (gpre_rel*) action->act_object; // Computed field context has to be 0 - so force it gpre_ctx* context = request->req_contexts; const USHORT save_ctx_int = context->ctx_internal; context->ctx_internal = 0; request->add_byte(isc_dyn_fld_computed_blr); const USHORT offset = request->req_blr - request->req_base; request->add_word(0); if (request->req_flags & REQ_blr_version4) request->add_byte(blr_version4); else request->add_byte(blr_version5); CME_expr(field->fld_computed->cmpf_boolean, request); request->add_byte(blr_eoc); context->ctx_internal = save_ctx_int; const USHORT length = request->req_blr - request->req_base - offset - 2; request->req_base[offset] = (UCHAR) length; request->req_base[offset + 1] = (UCHAR) (length >> 8); } //____________________________________________________________ // // Generate dynamic DDL for a computed field. // static void put_computed_source( gpre_req* request, const gpre_fld* field) { const act* action = request->req_actions; const gpre_rel* relation = (gpre_rel*) action->act_object; if (field->fld_computed->cmpf_text != NULL) { TEXT* computed_source = (TEXT*) MSC_alloc(field->fld_computed->cmpf_text->txt_length + 1); CPR_get_text(computed_source, field->fld_computed->cmpf_text); put_cstring(request, isc_dyn_fld_computed_source, computed_source); } } //____________________________________________________________ // // Put a null-terminated string valued attributed to the output string. // static void put_cstring(gpre_req* request, USHORT ddl_operator, const TEXT* string) { USHORT length = 0; if (string != NULL) length = strlen(string); put_string(request, ddl_operator, string, length); } //____________________________________________________________ // // Generate dynamic DDL to create a field for CREATE // or ALTER TABLE action. // static void put_dtype( gpre_req* request, const gpre_fld* field) { USHORT dtype; USHORT length = field->fld_length; const USHORT precision = field->fld_precision; const USHORT sub_type = field->fld_sub_type; switch (field->fld_dtype) { case dtype_cstring: // If the user is defining a field as cstring then generate // blr_cstring. Currently being used only for defining udf's if (field->fld_flags & FLD_meta_cstring) dtype = blr_cstring; else { // Correct the length of C string for meta data operations if (gpreGlob.sw_cstring && field->fld_sub_type != dsc_text_type_fixed) length--; dtype = blr_text; } case dtype_text: if (field->fld_dtype == dtype_text) dtype = blr_text; // Fall into case dtype_varying: fb_assert(length); if (field->fld_dtype == dtype_varying) dtype = blr_varying; put_numeric(request, isc_dyn_fld_type, dtype); put_numeric(request, isc_dyn_fld_length, length); put_numeric(request, isc_dyn_fld_scale, 0); if (field->fld_sub_type) put_numeric(request, isc_dyn_fld_sub_type, field->fld_sub_type); if (field->fld_char_length) put_numeric(request, isc_dyn_fld_char_length, field->fld_char_length); if (field->fld_collate_id) put_numeric(request, isc_dyn_fld_collation, field->fld_collate_id); if (field->fld_charset_id) put_numeric(request, isc_dyn_fld_character_set, field->fld_charset_id); return; case dtype_short: dtype = blr_short; length = sizeof(SSHORT); if (gpreGlob.sw_server_version >= 6) { put_numeric(request, isc_dyn_fld_type, dtype); put_numeric(request, isc_dyn_fld_length, length); put_numeric(request, isc_dyn_fld_scale, field->fld_scale); put_numeric(request, isc_dyn_fld_precision, field->fld_precision); put_numeric(request, isc_dyn_fld_sub_type, field->fld_sub_type); return; } break; case dtype_long: dtype = blr_long; length = sizeof(SLONG); if (gpreGlob.sw_server_version >= 6) { put_numeric(request, isc_dyn_fld_type, dtype); put_numeric(request, isc_dyn_fld_length, length); put_numeric(request, isc_dyn_fld_scale, field->fld_scale); put_numeric(request, isc_dyn_fld_precision, field->fld_precision); put_numeric(request, isc_dyn_fld_sub_type, field->fld_sub_type); return; } break; case dtype_blob: dtype = blr_blob; length = 8; put_numeric(request, isc_dyn_fld_type, dtype); put_numeric(request, isc_dyn_fld_length, length); put_numeric(request, isc_dyn_fld_scale, 0); put_numeric(request, isc_dyn_fld_sub_type, field->fld_sub_type); put_numeric(request, isc_dyn_fld_segment_length, field->fld_seg_length); if (field->fld_sub_type == isc_blob_text && field->fld_charset_id) put_numeric(request, isc_dyn_fld_character_set, field->fld_charset_id); return; case dtype_quad: dtype = blr_quad; length = 8; break; case dtype_real: dtype = blr_float; length = sizeof(float); break; case dtype_double: dtype = blr_double; length = sizeof(double); break; // ** Begin sql date/time/timestamp * case dtype_sql_date: dtype = blr_sql_date; length = sizeof(ISC_DATE); break; case dtype_sql_time: dtype = blr_sql_time; length = sizeof(ISC_TIME); break; case dtype_timestamp: dtype = blr_timestamp; length = sizeof(ISC_TIMESTAMP); break; // ** End sql date/time/timestamp * case dtype_int64: dtype = blr_int64; length = sizeof(ISC_INT64); put_numeric(request, isc_dyn_fld_type, dtype); put_numeric(request, isc_dyn_fld_length, length); put_numeric(request, isc_dyn_fld_scale, field->fld_scale); put_numeric(request, isc_dyn_fld_precision, field->fld_precision); put_numeric(request, isc_dyn_fld_sub_type, field->fld_sub_type); return; default: CPR_bugcheck(" *** Unknown datatype in put_dtype *** "); break; } put_numeric(request, isc_dyn_fld_type, dtype); put_numeric(request, isc_dyn_fld_length, length); put_numeric(request, isc_dyn_fld_scale, field->fld_scale); } //____________________________________________________________ // // Generate dynamic DDL to create a field for CREATE // or ALTER TABLE action. // // Emit the DDL that is appopriate for a local instance // of a field. eg: that can vary from the local fields // global field (DOMAIN in SQL). // static void put_field_attributes( gpre_req* request, const gpre_fld* field) { if (field->fld_flags & FLD_computed) put_computed_blr(request, field); if (!field->fld_global) put_dtype(request, field); // Put the DDL for local field instances if (field->fld_array_info) put_array_info(request, field); if (field->fld_collate && field->fld_global) { put_numeric(request, isc_dyn_fld_collation, field->fld_collate->intlsym_collate_id); } if (field->fld_flags & FLD_not_null) { request->add_byte(isc_dyn_fld_not_null); } if (field->fld_flags & FLD_computed) put_computed_source(request, field); } //____________________________________________________________ // // Put a numeric valued attributed to the output string. // static void put_numeric( gpre_req* request, USHORT blr_operator, SSHORT number) { request->add_byte(blr_operator); request->add_word(2); request->add_word(number); } //____________________________________________________________ // // Put a counted string valued attributed to the output string. // Count value is BYTE instead of WORD like put_cstring & put_string // static void put_short_cstring(gpre_req* request, USHORT ddl_operator, const TEXT* string) { SSHORT length = 0; if (string != NULL) length = strlen(string); STUFF_CHECK(length); request->add_byte(ddl_operator); request->add_byte(length); if (string != NULL) { while (length--) request->add_byte(*string++); } } //____________________________________________________________ // // Put a counted string valued attributed to the output string. // static void put_string(gpre_req* request, USHORT ddl_operator, const TEXT* string, USHORT length) { STUFF_CHECK(length); if (ddl_operator) { request->add_byte(ddl_operator); request->add_word(length); } else request->add_byte(length); if (string != NULL) { while (length--) request->add_byte(*string++); } } //____________________________________________________________ // // Put a symbol valued attribute. // static void put_symbol(gpre_req* request, int ddl_operator, const gpre_sym* symbol) { put_cstring(request, (USHORT) ddl_operator, symbol->sym_string); } //____________________________________________________________ // // Generate BLR for a trigger whose action is to abort. // Abort with a gds_error code error. // static void put_trigger_blr(gpre_req* request, USHORT blr_operator, GPRE_NOD node, pfn_local_trigger_cb routine) { request->add_byte(blr_operator); const USHORT offset = request->req_blr - request->req_base; request->add_word(0); if (request->req_flags & REQ_blr_version4) request->add_byte(blr_version4); else request->add_byte(blr_version5); request->add_byte(blr_begin); request->add_byte(blr_if); (*routine) (node, request); request->add_byte(blr_begin); request->add_byte(blr_end); // Generate the action for the trigger to be abort request->add_byte(blr_abort); put_short_cstring(request, blr_gds_code, "check_constraint"); request->add_byte(blr_end); // for if request->add_byte(blr_eoc); const USHORT length = request->req_blr - request->req_base - offset - 2; request->req_base[offset] = (UCHAR) length; request->req_base[offset + 1] = (UCHAR) (length >> 8); } //____________________________________________________________ // // Generate BLR for a trigger for a VIEW WITH CHECK OPTION. // This is messy, the gpre_rse passed in is mutilated by the end. // Fields in the where clause and in the VIEW definition, are replaced // by the VIEW fields. // For fields in the where clause but not in the VIEW definition, // the fields are set to NULL node for the PRE STORE trigger. // // static void put_view_trigger_blr(gpre_req* request, const gpre_rel* relation, USHORT blr_operator, gpre_trg* trigger, GPRE_NOD view_boolean, gpre_ctx** contexts, GPRE_NOD set_list) { gpre_rse* node = (gpre_rse*) trigger->trg_boolean; request->add_byte(blr_operator); const USHORT offset = request->req_blr - request->req_base; request->add_word(0); if (request->req_flags & REQ_blr_version4) request->add_byte(blr_version4); else request->add_byte(blr_version5); request->add_byte(blr_begin); if (trigger->trg_type == PRE_MODIFY_TRIGGER) { request->add_byte(blr_for); CME_rse(node, request); // For the boolean, replace all fields in the rse and the view, with the // equivalent view field_name, for remaining fields in rse, leave them // alone. replace_field_names(view_boolean, node->rse_fields, relation->rel_fields, false, contexts); request->add_byte(blr_begin); request->add_byte(blr_if); CME_expr(view_boolean, request); request->add_byte(blr_begin); request->add_byte(blr_end); // Generate the action for the trigger to be abort request->add_byte(blr_abort); put_short_cstring(request, blr_gds_code, "check_constraint"); request->add_byte(blr_end); request->add_byte(blr_end); request->add_byte(blr_eoc); } // end of PRE_MODIFY_TRIGGER trigger if (trigger->trg_type == PRE_STORE_TRIGGER) { replace_field_names(view_boolean, node->rse_fields, relation->rel_fields, true, contexts); request->add_byte(blr_if); CME_expr(view_boolean, request); request->add_byte(blr_begin); request->add_byte(blr_end); // Generate the action for the trigger to be abort request->add_byte(blr_abort); put_short_cstring(request, blr_gds_code, "check_constraint"); request->add_byte(blr_end); request->add_byte(blr_eoc); } // end of PRE_STORE_TRIGGER trigger const USHORT length = request->req_blr - request->req_base - offset - 2; request->req_base[offset] = (UCHAR) length; request->req_base[offset + 1] = (UCHAR) (length >> 8); } //____________________________________________________________ // // Replace fields in given rse by fields referenced in VIEW. // if fields in gpre_rse are not part of VIEW definition, then they // are not changed. // If search list is not specified, then only the context of the fields // in the rse is chaged to contexts[2]. // If null_them is true, then fields in rse but not in VIEW definition // are converted to null nodes, this is used for PRE STORE trigger // verification. // static void replace_field_names(gpre_nod* const input, const gpre_nod* const search_list, gpre_fld* const replace_with, bool null_them, gpre_ctx** contexts) { if (!input) return; if (((input->nod_type == nod_via) || (input->nod_type == nod_any) || (input->nod_type == nod_unique)) && (search_list == 0) && (replace_with == 0) && (input->nod_count == 0)) { CPR_error("Invalid view WITH CHECK OPTION - no subqueries permitted"); return; } gpre_nod** ptr = input->nod_arg; for (const gpre_nod* const* const end = ptr + input->nod_count; ptr < end; ptr++) { if ((*ptr)->nod_type == nod_field) { ref* reference = (REF) (*ptr)->nod_arg[0]; gpre_fld* rse_field = reference->ref_field; if (null_them) { if (reference->ref_context == contexts[2]) { *ptr = MSC_node(nod_null, 0); } continue; } reference->ref_context = contexts[2]; if (!search_list) continue; gpre_fld* view_field = replace_with; gpre_nod* const* ptrs = search_list->nod_arg; for (gpre_nod* const* const ends = ptrs + search_list->nod_count; ptrs < ends; ptrs++, view_field = (view_field) ? view_field->fld_next : NULL) { const ref* references = (REF) (*ptrs)->nod_arg[0]; gpre_fld* select_field = references->ref_field; if (rse_field == select_field) { reference->ref_field = (view_field) ? view_field : select_field; reference->ref_context = contexts[1]; break; } } } else replace_field_names(*ptr, search_list, replace_with, null_them, contexts); } } //____________________________________________________________ // // Generate dynamic DDL for a set statistics // static void set_statistics( gpre_req* request, const act* action) { const sts* stats = (STS) action->act_object; if (stats) if (stats->sts_flags & STS_index) { put_cstring(request, isc_dyn_mod_idx, stats->sts_name->str_string); request->add_byte(isc_dyn_idx_statistic); } request->add_end(); }