/* * PROGRAM: JRD Access Method * MODULE: ini.epp * DESCRIPTION: Metadata initialization / population * * 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): ______________________________________. */ #include "firebird.h" #include #include #include "../jrd/common.h" #include "../jrd/flags.h" #include "../jrd/jrd.h" #include "../jrd/val.h" #include "../jrd/ibase.h" #include "../jrd/ods.h" #include "../jrd/btr.h" #include "gen/ids.h" #include "../jrd/tra.h" #include "../jrd/trig.h" #include "../jrd/intl.h" #include "../jrd/dflt.h" #include "../jrd/ini.h" #include "../jrd/idx.h" #include "../jrd/gdsassert.h" #include "../jrd/blb_proto.h" #include "../jrd/cch_proto.h" #include "../jrd/cmp_proto.h" #include "../jrd/dfw_proto.h" #include "../jrd/dpm_proto.h" #include "../jrd/err_proto.h" #include "../jrd/exe_proto.h" #include "../jrd/gds_proto.h" #include "../jrd/idx_proto.h" #include "../jrd/ini_proto.h" #include "../jrd/jrd_proto.h" #include "../jrd/met_proto.h" #include "../jrd/obj.h" #include "../jrd/acl.h" #include "../jrd/irq.h" #include "../jrd/IntlManager.h" using namespace Jrd; DATABASE DB = FILENAME "ODS.RDB"; #define PAD(string, field) jrd_vtof ((char*)(string), field, sizeof (field)) const int FB_MAX_ACL_SIZE = 4096; const char* DEFAULT_CLASS = "SQL$DEFAULT"; static void add_index_set(Database*, bool, USHORT, USHORT); static void add_relation_fields(thread_db*, USHORT); static void add_security_to_sys_rel(thread_db*, const Firebird::MetaName&, const TEXT*, const UCHAR*, const SSHORT); static int init2_helper(const int* fld, int n, jrd_rel* relation); static void modify_relation_field(thread_db*, const int*, const int*, jrd_req**); static void store_generator(thread_db*, const gen*, jrd_req**); static void store_global_field(thread_db*, const gfld*, jrd_req**); static void store_intlnames(thread_db*, Database*); static void store_functions(thread_db*, Database*); static void store_message(thread_db*, const trigger_msg*, jrd_req**); static void store_relation_field(thread_db*, const int*, const int*, int, jrd_req**, bool); static void store_trigger(thread_db*, const jrd_trg*, jrd_req**); /* This is the table used in defining triggers; note that RDB$TRIGGER_0 was first changed to RDB$TRIGGER_7 to make it easier to upgrade a database to support field-level grant. It has since been changed to RDB$TRIGGER_9 to handle SQL security on relations whose name is > 27 characters */ static const jrd_trg triggers[] = { { "RDB$TRIGGER_1", (UCHAR) nam_user_privileges, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger3), trigger3, 0, ODS_8_0 }, { "RDB$TRIGGER_8", (UCHAR) nam_user_privileges, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger2), trigger2, 0, ODS_8_0 }, { "RDB$TRIGGER_9", (UCHAR) nam_user_privileges, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger1), trigger1, 0, ODS_8_0 }, { "RDB$TRIGGER_2", (UCHAR) nam_trgs, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger4), trigger4, 0, ODS_8_0 }, { "RDB$TRIGGER_3", (UCHAR) nam_trgs, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger4), trigger4, 0, ODS_8_0 }, { "RDB$TRIGGER_4", (UCHAR) nam_relations, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger5), trigger5, 0, ODS_8_0 }, { "RDB$TRIGGER_5", (UCHAR) nam_relations, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger6), trigger6, 0, ODS_8_0 }, { "RDB$TRIGGER_6", (UCHAR) nam_gens, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger7), trigger7, 0, ODS_8_0 }, { "RDB$TRIGGER_26", (UCHAR) nam_rel_constr, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger26), trigger26, 0, ODS_8_0 }, { "RDB$TRIGGER_25", (UCHAR) nam_rel_constr, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger25), trigger25, 0, ODS_8_0 }, { "RDB$TRIGGER_10", (UCHAR) nam_rel_constr, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger10), trigger10, 0, ODS_8_0 }, { "RDB$TRIGGER_11", (UCHAR) nam_rel_constr, RDB$TRIGGERS.RDB$TRIGGER_TYPE.POST_ERASE, sizeof(trigger11), trigger11, 0, ODS_8_0 }, { "RDB$TRIGGER_12", (UCHAR) nam_ref_constr, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger12), trigger12, 0, ODS_8_0 }, { "RDB$TRIGGER_13", (UCHAR) nam_ref_constr, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger13), trigger13, 0, ODS_8_0 }, { "RDB$TRIGGER_14", (UCHAR) nam_chk_constr, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger14), trigger14, 0, ODS_8_0 }, { "RDB$TRIGGER_15", (UCHAR) nam_chk_constr, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger15), trigger15, 0, ODS_8_0 }, { "RDB$TRIGGER_16", (UCHAR) nam_chk_constr, RDB$TRIGGERS.RDB$TRIGGER_TYPE.POST_ERASE, sizeof(trigger16), trigger16, 0, ODS_8_0 }, { "RDB$TRIGGER_17", (UCHAR) nam_i_segments, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger17), trigger17, 0, ODS_8_0 }, { "RDB$TRIGGER_18", (UCHAR) nam_i_segments, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger18), trigger18, 0, ODS_8_0 }, { "RDB$TRIGGER_19", (UCHAR) nam_indices, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger19), trigger19, 0, ODS_8_0 }, { "RDB$TRIGGER_20", (UCHAR) nam_indices, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger20), trigger20, 0, ODS_8_0 }, { "RDB$TRIGGER_21", (UCHAR) nam_trgs, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger21), trigger21, 0, ODS_8_0 }, { "RDB$TRIGGER_22", (UCHAR) nam_trgs, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger22), trigger22, 0, ODS_8_0 }, { "RDB$TRIGGER_23", (UCHAR) nam_r_fields, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger23), trigger23, 0, ODS_8_0 }, { "RDB$TRIGGER_24", (UCHAR) nam_r_fields, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger24), trigger24, 0, ODS_8_0 }, { "RDB$TRIGGER_27", (UCHAR) nam_r_fields, RDB$TRIGGERS.RDB$TRIGGER_TYPE.POST_ERASE, sizeof(trigger27), trigger27, 0, ODS_8_0 }, { "RDB$TRIGGER_28", (UCHAR) nam_procedures, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger28), trigger28, 0, ODS_8_0 }, { "RDB$TRIGGER_29", (UCHAR) nam_procedures, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger29), trigger29, 0, ODS_8_0 }, { "RDB$TRIGGER_30", (UCHAR) nam_exceptions, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger30), trigger30, 0, ODS_8_0 }, { "RDB$TRIGGER_31", (UCHAR) nam_user_privileges, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger31), trigger31, 0, ODS_8_1 }, { "RDB$TRIGGER_32", (UCHAR) nam_user_privileges, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger31), trigger31, 0, ODS_8_1 }, { "RDB$TRIGGER_33", (UCHAR) nam_user_privileges, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger31), trigger31, 0, ODS_8_1 }, { "RDB$TRIGGER_34", (UCHAR) nam_rel_constr, RDB$TRIGGERS.RDB$TRIGGER_TYPE.POST_ERASE, sizeof(trigger34), trigger34, TRG_ignore_perm, ODS_8_1 }, { "RDB$TRIGGER_35", (UCHAR) nam_chk_constr, RDB$TRIGGERS.RDB$TRIGGER_TYPE.POST_ERASE, sizeof(trigger35), trigger35, TRG_ignore_perm, ODS_8_1 }, { "RDB$TRIGGER_36", (UCHAR) nam_fields, RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger36), trigger36, 0, ODS_11_0 }, { 0, 0, 0, 0, 0, 0 } }; /* this table is used in defining messages for system triggers */ static const trigger_msg trigger_messages[] = { { "RDB$TRIGGER_9", 0, "grant_obj_notfound", ODS_8_0 }, { "RDB$TRIGGER_9", 1, "grant_fld_notfound", ODS_8_0 }, { "RDB$TRIGGER_9", 2, "grant_nopriv", ODS_8_0 }, { "RDB$TRIGGER_9", 3, "nonsql_security_rel", ODS_8_0 }, { "RDB$TRIGGER_9", 4, "nonsql_security_fld", ODS_8_0 }, { "RDB$TRIGGER_9", 5, "grant_nopriv_on_base", ODS_8_0 }, { "RDB$TRIGGER_1", 0, "existing_priv_mod", ODS_8_0 }, { "RDB$TRIGGER_2", 0, "systrig_update", ODS_8_0 }, { "RDB$TRIGGER_3", 0, "systrig_update", ODS_8_0 }, { "RDB$TRIGGER_5", 0, "not_rel_owner", ODS_8_0 }, { "RDB$TRIGGER_24", 1, "cnstrnt_fld_rename", ODS_8_0 }, { "RDB$TRIGGER_23", 1, "cnstrnt_fld_del", ODS_8_0 }, { "RDB$TRIGGER_22", 1, "check_trig_update", ODS_8_0 }, { "RDB$TRIGGER_21", 1, "check_trig_del", ODS_8_0 }, { "RDB$TRIGGER_20", 1, "integ_index_mod", ODS_8_0 }, { "RDB$TRIGGER_20", 2, "integ_index_deactivate", ODS_8_0 }, { "RDB$TRIGGER_20", 3, "integ_deactivate_primary", ODS_8_0 }, { "RDB$TRIGGER_19", 1, "integ_index_del", ODS_8_0 }, { "RDB$TRIGGER_18", 1, "integ_index_seg_mod", ODS_8_0 }, { "RDB$TRIGGER_17", 1, "integ_index_seg_del", ODS_8_0 }, { "RDB$TRIGGER_15", 1, "check_cnstrnt_del", ODS_8_0 }, { "RDB$TRIGGER_14", 1, "check_cnstrnt_update", ODS_8_0 }, { "RDB$TRIGGER_13", 1, "ref_cnstrnt_update", ODS_8_0 }, { "RDB$TRIGGER_12", 1, "ref_cnstrnt_notfound", ODS_8_0 }, { "RDB$TRIGGER_12", 2, "foreign_key_notfound", ODS_8_0 }, { "RDB$TRIGGER_10", 1, "primary_key_ref", ODS_8_0 }, { "RDB$TRIGGER_10", 2, "primary_key_notnull", ODS_8_0 }, { "RDB$TRIGGER_25", 1, "rel_cnstrnt_update", ODS_8_0 }, { "RDB$TRIGGER_26", 1, "constaint_on_view", ODS_8_0 }, { "RDB$TRIGGER_26", 2, "invld_cnstrnt_type", ODS_8_0 }, { "RDB$TRIGGER_26", 3, "primary_key_exists", ODS_8_0 }, { "RDB$TRIGGER_31", 0, "no_write_user_priv", ODS_8_1 }, { "RDB$TRIGGER_32", 0, "no_write_user_priv", ODS_8_1 }, { "RDB$TRIGGER_33", 0, "no_write_user_priv", ODS_8_1 }, { "RDB$TRIGGER_24", 2, "integ_index_seg_mod", ODS_11_0 }, { "RDB$TRIGGER_36", 1, "integ_index_seg_mod", ODS_11_0 }, { 0, 0, 0, 0 } }; void INI_format(const TEXT* owner, const TEXT* charset) { /************************************** * * I N I _ f o r m a t * ************************************** * * Functional description * Initialize system relations in the database. * The full complement of metadata should be * stored here. * **************************************/ thread_db* tdbb = JRD_get_thread_data(); Database* dbb = tdbb->getDatabase(); /* Uppercase owner name */ Firebird::MetaName string(owner ? owner : ""); string.upper7(); /* Uppercase charset name */ Firebird::MetaName string2(charset ? charset : ""); string2.upper7(); int n; const int* fld; /* Make sure relations exist already */ for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) { if (relfld[RFLD_R_TYPE] == rel_persistent) { DPM_create_relation(tdbb, MET_relation(tdbb, relfld[RFLD_R_ID])); } for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) ; } /* Store RELATIONS and RELATION_FIELDS */ jrd_req* handle1 = NULL; jrd_req* handle2 = NULL; for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) { for (n = 0, fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) { if (!fld[RFLD_F_MINOR]) { const int* pFld = fld; const int* pRelFld = relfld; store_relation_field(tdbb, pFld, pRelFld, n, &handle2, true); n++; } } STORE(REQUEST_HANDLE handle1) X IN RDB$RELATIONS X.RDB$RELATION_ID = relfld[RFLD_R_ID]; PAD(names[relfld[RFLD_R_NAME]], X.RDB$RELATION_NAME); X.RDB$FIELD_ID = n; X.RDB$FORMAT = 0; X.RDB$SYSTEM_FLAG = RDB_system; X.RDB$SYSTEM_FLAG.NULL = FALSE; X.RDB$DBKEY_LENGTH = 8; X.RDB$OWNER_NAME.NULL = TRUE; X.RDB$RELATION_TYPE = relfld[RFLD_R_TYPE]; if (string.length()) { PAD(string.c_str(), X.RDB$OWNER_NAME); X.RDB$OWNER_NAME.NULL = FALSE; } END_STORE; } CMP_release(tdbb, handle1); CMP_release(tdbb, handle2); handle1 = handle2 = NULL; /* Store global FIELDS */ for (const gfld* gfield = gfields; gfield->gfld_name; gfield++) { store_global_field(tdbb, gfield, &handle1); } CMP_release(tdbb, handle1); handle1 = NULL; // Store DATABASE record STORE(REQUEST_HANDLE handle1) X IN RDB$DATABASE X.RDB$RELATION_ID = (int) USER_DEF_REL_INIT_ID; X.RDB$CHARACTER_SET_NAME.NULL = TRUE; if (string2.length()) { PAD (string2.c_str(), X.RDB$CHARACTER_SET_NAME); X.RDB$CHARACTER_SET_NAME.NULL = FALSE; } else { PAD (DEFAULT_DB_CHARACTER_SET_NAME, X.RDB$CHARACTER_SET_NAME); X.RDB$CHARACTER_SET_NAME.NULL = FALSE; } END_STORE CMP_release(tdbb, handle1); handle1 = NULL; // Store ADMIN_ROLE record STORE(REQUEST_HANDLE handle1) X IN RDB$ROLES PAD (ADMIN_ROLE, X.RDB$ROLE_NAME); X.RDB$ROLE_NAME.NULL = FALSE; if (string.length()) { PAD (string.c_str(), X.RDB$OWNER_NAME); } else { PAD (SYSDBA_USER_NAME, X.RDB$OWNER_NAME); } X.RDB$OWNER_NAME.NULL = FALSE; X.RDB$DESCRIPTION.NULL = TRUE; X.RDB$SYSTEM_FLAG = ROLE_FLAG_DBO; // Mark it as privileged role X.RDB$SYSTEM_FLAG.NULL = FALSE; END_STORE CMP_release(tdbb, handle1); handle1 = NULL; // Create indices for system relations add_index_set(dbb, false, 0, 0); // Create parameter types handle1 = NULL; for (const rtyp* type = types; type->rtyp_name; ++type) { // this STORE should be compatible with two below, // as they use the same compiled request STORE(REQUEST_HANDLE handle1) X IN RDB$TYPES PAD(names[type->rtyp_field], X.RDB$FIELD_NAME); PAD(type->rtyp_name, X.RDB$TYPE_NAME); X.RDB$TYPE = type->rtyp_value; X.RDB$SYSTEM_FLAG = RDB_system; X.RDB$SYSTEM_FLAG.NULL = FALSE; END_STORE; } for (const IntlManager::CharSetDefinition* charSet = IntlManager::defaultCharSets; charSet->name; ++charSet) { // this STORE should be compatible with one above and below, // as they use the same compiled request STORE(REQUEST_HANDLE handle1) X IN RDB$TYPES PAD(names[nam_charset_name], X.RDB$FIELD_NAME); PAD(charSet->name, X.RDB$TYPE_NAME); X.RDB$TYPE = charSet->id; X.RDB$SYSTEM_FLAG = RDB_system; X.RDB$SYSTEM_FLAG.NULL = FALSE; END_STORE; } for (const IntlManager::CharSetAliasDefinition* alias = IntlManager::defaultCharSetAliases; alias->name; ++alias) { // this STORE should be compatible with two above, // as they use the same compiled request STORE(REQUEST_HANDLE handle1) X IN RDB$TYPES PAD(names[nam_charset_name], X.RDB$FIELD_NAME); PAD(alias->name, X.RDB$TYPE_NAME); X.RDB$TYPE = alias->charSetId; X.RDB$SYSTEM_FLAG = RDB_system; X.RDB$SYSTEM_FLAG.NULL = FALSE; END_STORE; } CMP_release(tdbb, handle1); // Store symbols for international character sets & collations store_intlnames(tdbb, dbb); // Create generators to be used by system triggers handle1 = NULL; for (const gen* generator = generators; generator->gen_name; generator++) { store_generator(tdbb, generator, &handle1); } CMP_release(tdbb, handle1); // Adjust the value of the hidden generator RDB$GENERATORS DPM_gen_id(tdbb, 0, true, FB_NELEM(generators) - 1); /* store system-defined triggers */ handle1 = NULL; for (const jrd_trg* trigger = triggers; trigger->trg_relation; ++trigger) { store_trigger(tdbb, trigger, &handle1); } CMP_release(tdbb, handle1); /* store trigger messages to go with triggers */ handle1 = NULL; for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message) { store_message(tdbb, message, &handle1); } CMP_release(tdbb, handle1); // Store IUDFs declared automatically as system functions. // CVC: Demonstration code to register IUDF automatically moved to functions.h store_functions(tdbb, dbb); DFW_perform_system_work(tdbb); add_relation_fields(tdbb, 0); /* ==================================================================== == == Add security on RDB$ROLES system table == ====================================================================== */ UCHAR buffer[FB_MAX_ACL_SIZE]; UCHAR* acl = buffer; *acl++ = ACL_version; *acl++ = ACL_id_list; *acl++ = id_person; USHORT length = string.length(); if (length > MAX_UCHAR) length = MAX_UCHAR; *acl++ = (UCHAR)length; if (length) { const TEXT* p_1 = string.c_str(); memcpy(acl, p_1, length); acl += length; } *acl++ = ACL_end; *acl++ = ACL_priv_list; *acl++ = priv_protect; *acl++ = priv_control; *acl++ = priv_delete; *acl++ = priv_write; *acl++ = priv_read; *acl++ = ACL_end; *acl++ = ACL_id_list; *acl++ = ACL_end; *acl++ = ACL_priv_list; *acl++ = priv_read; *acl++ = ACL_end; *acl++ = ACL_end; length = acl - buffer; add_security_to_sys_rel(tdbb, string, "RDB$ROLES", buffer, length); add_security_to_sys_rel(tdbb, string, "RDB$PAGES", buffer, length); // DFW writes here add_security_to_sys_rel(tdbb, string, "RDB$FORMATS", buffer, length); } USHORT INI_get_trig_flags(const TEXT* trig_name) { /********************************************* * * I N I _ g e t _ t r i g _ f l a g s * ********************************************* * * Functional description * Return the trigger flags for a system trigger. * **************************************/ for (const jrd_trg* trig = triggers; trig->trg_length > 0; trig++) { if (!strcmp(trig->trg_name, trig_name)) { return (trig->trg_flags); } } return (0); } void INI_init(thread_db* tdbb) { /************************************** * * I N I _ i n i t * ************************************** * * Functional description * Initialize in memory meta data. Assume that all meta data * fields exist in the database even if this is not the case. * Do not fill in the format length or the address in each * format descriptor. * **************************************/ SET_TDBB(tdbb); Database* const dbb = tdbb->getDatabase(); CHECK_DBB(dbb); const int* fld; for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) { jrd_rel* relation = MET_relation(tdbb, relfld[RFLD_R_ID]); relation->rel_flags |= REL_system; relation->rel_name = names[relfld[RFLD_R_NAME]]; int n = 0; for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) { n++; } /* Set a flag if their is a trigger on the relation. Later we may need to compile it. */ for (const jrd_trg* trigger = triggers; trigger->trg_relation; trigger++) { if (relation->rel_name == names[trigger->trg_relation]) { relation->rel_flags |= REL_sys_triggers; break; } } vec* fields = vec::newVector(*dbb->dbb_permanent, n); relation->rel_fields = fields; vec::iterator itr = fields->begin(); Format* format = Format::newFormat(*dbb->dbb_permanent, n); relation->rel_current_format = format; vec* formats = vec::newVector(*dbb->dbb_permanent, 1); relation->rel_formats = formats; (*formats)[0] = format; Format::fmt_desc_iterator desc = format->fmt_desc.begin(); for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH, ++desc, ++itr) { const gfld* gfield = &gfields[fld[RFLD_F_ID]]; desc->dsc_length = gfield->gfld_length; if (gfield->gfld_dtype == dtype_varying) { fb_assert(desc->dsc_length <= MAX_USHORT - sizeof(USHORT)); desc->dsc_length += sizeof(USHORT); } desc->dsc_dtype = gfield->gfld_dtype; desc->dsc_sub_type = gfield->gfld_sub_type; if (desc->dsc_dtype == dtype_blob && desc->dsc_sub_type == isc_blob_text) desc->dsc_scale = CS_METADATA; // blob charset jrd_fld* field = FB_NEW(*dbb->dbb_permanent) jrd_fld(*dbb->dbb_permanent); *itr = field; field->fld_name = names[fld[RFLD_F_NAME]]; } } } void INI_init2(thread_db* tdbb) { /************************************** * * I N I _ i n i t 2 * ************************************** * * Functional description * Re-initialize in memory meta data. Fill in * format 0 based on the minor ODS version of * the database when it was created. * **************************************/ SET_TDBB(tdbb); Database* const dbb = tdbb->getDatabase(); const USHORT major_version = dbb->dbb_ods_version; const USHORT minor_original = dbb->dbb_minor_original; vec* vector = dbb->dbb_relations; const int* fld; for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) { if (relfld[RFLD_R_ODS] > ENCODE_ODS(major_version, minor_original)) { /***************************************************** ** ** free the space allocated for RDB$ROLES ** ******************************************************/ const USHORT id = relfld[RFLD_R_ID]; jrd_rel* relation = (*vector)[id]; delete relation->rel_current_format; delete relation->rel_formats; delete relation->rel_fields; (*vector)[id] = NULL; fld = relfld + RFLD_RPT; while (fld[RFLD_F_NAME]) { fld += RFLD_F_LENGTH; } } else { jrd_rel* relation = MET_relation(tdbb, relfld[RFLD_R_ID]); Format* format = relation->rel_current_format; int n = 0; for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) { /* If the ODS is less than 10, then remove all fields named * RDB$FIELD_PRECISION and field RDB$CHARACTER_LENGTH from * relation RDB$FUNCTION_ARGUMENTS , as they were not present * in < 10 ODS */ if (fld[RFLD_F_NAME] == nam_f_precision || (fld[RFLD_F_NAME] == nam_char_length && relfld[RFLD_R_NAME] == nam_args)) { if (major_version >= ODS_VERSION10) n = init2_helper(fld, n, relation); } else if (fld[RFLD_F_NAME] == nam_statistics && relfld[RFLD_R_NAME] == nam_i_segments) { if (major_version >= ODS_VERSION11) n = init2_helper(fld, n, relation); } else if ((fld[RFLD_F_NAME] == nam_description || fld[RFLD_F_NAME] == nam_sys_flag) && relfld[RFLD_R_NAME] == nam_roles) { if (major_version >= ODS_VERSION11) n = init2_helper(fld, n, relation); } else if (fld[RFLD_F_NAME] == nam_description && relfld[RFLD_R_NAME] == nam_gens) { if (major_version >= ODS_VERSION11) n = init2_helper(fld, n, relation); } else if ((fld[RFLD_F_NAME] == nam_base_collation_name || fld[RFLD_F_NAME] == nam_specific_attr) && relfld[RFLD_R_NAME] == nam_collations) { if (major_version >= ODS_VERSION11) n = init2_helper(fld, n, relation); } else if (fld[RFLD_F_NAME] == nam_r_type && relfld[RFLD_R_NAME] == nam_relations) { if (ENCODE_ODS(major_version, minor_original) >= ODS_11_1) n = init2_helper(fld, n, relation); } else if (fld[RFLD_F_NAME] == nam_valid_blr && relfld[RFLD_R_NAME] == nam_trgs) { if (ENCODE_ODS(major_version, minor_original) >= ODS_11_1) n = init2_helper(fld, n, relation); } else if ((fld[RFLD_F_NAME] == nam_prc_type || fld[RFLD_F_NAME] == nam_valid_blr) && relfld[RFLD_R_NAME] == nam_procedures) { if (ENCODE_ODS(major_version, minor_original) >= ODS_11_1) n = init2_helper(fld, n, relation); } else if (fld[RFLD_F_NAME] == nam_debug_info && (relfld[RFLD_R_NAME] == nam_trgs || relfld[RFLD_R_NAME] == nam_procedures)) { if (ENCODE_ODS(major_version, minor_original) >= ODS_11_1) n = init2_helper(fld, n, relation); } else if ((fld[RFLD_F_NAME] == nam_default || fld[RFLD_F_NAME] == nam_d_source || fld[RFLD_F_NAME] == nam_collate_id || fld[RFLD_F_NAME] == nam_null_flag || fld[RFLD_F_NAME] == nam_prm_mechanism) && relfld[RFLD_R_NAME] == nam_proc_parameters) { if (ENCODE_ODS(major_version, minor_original) >= ODS_11_1) n = init2_helper(fld, n, relation); } else if ((fld[RFLD_F_NAME] == nam_f_name || fld[RFLD_F_NAME] == nam_r_name) && relfld[RFLD_R_NAME] == nam_proc_parameters) { if (ENCODE_ODS(major_version, minor_original) >= ODS_11_2) n = init2_helper(fld, n, relation); } else n = init2_helper(fld, n, relation); } relation->rel_fields->resize(n); format->fmt_count = n; // We are using less than the allocated members. format->fmt_length = (USHORT)FLAG_BYTES(n); Format::fmt_desc_iterator desc = format->fmt_desc.begin(); for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH, ++desc) { if (n-- > 0) { format->fmt_length = (USHORT)MET_align(dbb, &(*desc), format->fmt_length); desc->dsc_address = (UCHAR*) (IPTR) format->fmt_length; // In ODS11 length of RDB$MESSAGE was enlarged from 80 to 1023 bytes if ((fld[RFLD_F_NAME] == nam_msg) && (major_version < ODS_VERSION11)) { desc->dsc_length = 80 + sizeof(USHORT); } // In ODS prior to 11.2 all varchar columns were actually // two bytes shorter than defined in fields.h if (desc->dsc_dtype == dtype_varying && ENCODE_ODS(major_version, minor_original) < ODS_11_2) { desc->dsc_length -= sizeof(USHORT); } // In ODS11.2 length of RDB$CONTEXT_NAME was enlarged from 31 to 255 bytes if ((fld[RFLD_F_NAME] == nam_context) && ENCODE_ODS(major_version, minor_original) < ODS_11_2) { desc->dsc_length = 31; } format->fmt_length += desc->dsc_length; } } } } } static void add_index_set(Database* dbb, bool update_ods, USHORT major_version, USHORT minor_version) { /************************************** * * a d d _ i n d e x _ s e t * ************************************** * * Functional description * Add system indices. If update_ods is true we are performing * an ODS update, and only add the indices marked as newer than * ODS (major_version,minor_version). * **************************************/ Firebird::MetaName string; index_desc idx; thread_db* tdbb = JRD_get_thread_data(); jrd_req* handle1 = NULL; jrd_req* handle2 = NULL; for (int n = 0; n < SYSTEM_INDEX_COUNT; n++) { const ini_idx_t* index = &indices[n]; /* For minor ODS updates, only add indices newer than on-disk ODS */ if (update_ods && ((index->ini_idx_version_flag <= ENCODE_ODS(major_version, minor_version)) || (index->ini_idx_version_flag > ODS_CURRENT_VERSION) || (((USHORT) DECODE_ODS_MAJOR(index->ini_idx_version_flag)) != major_version))) { /* The DECODE_ODS_MAJOR() is used (in this case) to instruct the server to perform updates for minor ODS versions only within a major ODS */ continue; } STORE(REQUEST_HANDLE handle1) X IN RDB$INDICES jrd_rel* relation = MET_relation(tdbb, index->ini_idx_relid); PAD(relation->rel_name.c_str(), X.RDB$RELATION_NAME); string.printf("RDB$INDEX_%d", index->ini_idx_index_id); PAD(string.c_str(), X.RDB$INDEX_NAME); X.RDB$UNIQUE_FLAG = index->ini_idx_flags & idx_unique; X.RDB$SEGMENT_COUNT = index->ini_idx_segment_count; if (index->ini_idx_flags & idx_descending) { X.RDB$INDEX_TYPE.NULL = FALSE; X.RDB$INDEX_TYPE = 1; } else { X.RDB$INDEX_TYPE.NULL = TRUE; } X.RDB$SYSTEM_FLAG = 1; X.RDB$SYSTEM_FLAG.NULL = FALSE; X.RDB$INDEX_INACTIVE = 0; /* Store each segment for the index */ index_desc::idx_repeat* tail = idx.idx_rpt; for (USHORT position = 0; position < index->ini_idx_segment_count; position++, tail++) { const ini_idx_t::ini_idx_segment_t* segment = &index->ini_idx_segment[position]; STORE(REQUEST_HANDLE handle2) Y IN RDB$INDEX_SEGMENTS jrd_fld* field = (*relation->rel_fields)[segment->ini_idx_rfld_id]; Y.RDB$FIELD_POSITION = position; PAD(X.RDB$INDEX_NAME, Y.RDB$INDEX_NAME); PAD(field->fld_name.c_str(), Y.RDB$FIELD_NAME); tail->idx_field = segment->ini_idx_rfld_id; tail->idx_itype = segment->ini_idx_type; tail->idx_selectivity = 0; END_STORE; } idx.idx_count = index->ini_idx_segment_count; idx.idx_flags = index->ini_idx_flags; SelectivityList selectivity(*tdbb->getDefaultPool()); IDX_create_index(tdbb, relation, &idx, string.c_str(), NULL, NULL, selectivity); X.RDB$INDEX_ID = idx.idx_id + 1; END_STORE; } if (handle1) { CMP_release(tdbb, handle1); } if (handle2) { CMP_release(tdbb, handle2); } } static void add_relation_fields(thread_db* tdbb, USHORT minor_version) { /************************************** * * a d d _ r e l a t i o n _ f i e l d s * ************************************** * * Functional description * Add any local fields which have a non-zero * update number in the relfields table. That * is, those that have been added since the last * ODS change. * **************************************/ SET_TDBB(tdbb); //Database* dbb = tdbb->getDatabase(); /* add desired fields to system relations, forcing a new format version */ jrd_req* s_handle = NULL; jrd_req* m_handle = NULL; const int* fld; for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) { int n = 0; for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; n++, fld += RFLD_F_LENGTH) { if (minor_version < fld[RFLD_F_MINOR] || minor_version < fld[RFLD_F_UPD_MINOR]) { if (minor_version < fld[RFLD_F_MINOR]) { store_relation_field(tdbb, fld, relfld, n, &s_handle, false); } else { modify_relation_field(tdbb, fld, relfld, &m_handle); } dsc desc; desc.dsc_dtype = dtype_text; INTL_ASSIGN_DSC(&desc, CS_METADATA, COLLATE_NONE); desc.dsc_address = (UCHAR*) names[relfld[RFLD_R_NAME]]; desc.dsc_length = strlen((char*)desc.dsc_address); DFW_post_system_work(tdbb, dfw_update_format, &desc, 0); } } } if (s_handle) { CMP_release(tdbb, s_handle); } if (m_handle) { CMP_release(tdbb, m_handle); } DFW_perform_system_work(tdbb); } // The caller used an UCHAR* to store the acl, it was converted to TEXT* to // be passed to this function, only to be converted to UCHAR* to be passed // to BLB_put_segment. Therefore, "acl" was changed to UCHAR* as param. static void add_security_to_sys_rel(thread_db* tdbb, const Firebird::MetaName& user_name, const TEXT* rel_name, const UCHAR* acl, const SSHORT acl_length) { /************************************** * * a d d _ s e c u r i t y _ t o _ s y s _ r e l * ************************************** * * Functional description * * Add security to system relations. Only the owner of the * database has SELECT/INSERT/UPDATE/DELETE privileges on * any system relations. Any other users only has SELECT * privilege. * **************************************/ TEXT sec_class_name[100]; Firebird::MetaName default_class; SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); strcpy(sec_class_name, SQL_SECCLASS_PREFIX); strcat(sec_class_name, rel_name); bid blob_id_1; blb* blob = BLB_create(tdbb, dbb->dbb_sys_trans, &blob_id_1); BLB_put_segment(tdbb, blob, acl, acl_length); BLB_close(tdbb, blob); bid blob_id_2; blob = BLB_create(tdbb, dbb->dbb_sys_trans, &blob_id_2); BLB_put_segment(tdbb, blob, acl, acl_length); BLB_close(tdbb, blob); default_class.printf("%s%" SQUADFORMAT, DEFAULT_CLASS, DPM_gen_id(tdbb, MET_lookup_generator(tdbb, DEFAULT_CLASS), false, 1)); jrd_req* handle1 = NULL; for (int cnt = 0; cnt < 6; cnt++) { STORE(REQUEST_HANDLE handle1) PRIV IN RDB$USER_PRIVILEGES switch (cnt) { case 0: strcpy(PRIV.RDB$USER, user_name.c_str()); PRIV.RDB$PRIVILEGE[0] = 'S'; PRIV.RDB$GRANT_OPTION = 1; break; case 1: strcpy(PRIV.RDB$USER, user_name.c_str()); PRIV.RDB$PRIVILEGE[0] = 'I'; PRIV.RDB$GRANT_OPTION = 1; break; case 2: strcpy(PRIV.RDB$USER, user_name.c_str()); PRIV.RDB$PRIVILEGE[0] = 'U'; PRIV.RDB$GRANT_OPTION = 1; break; case 3: strcpy(PRIV.RDB$USER, user_name.c_str()); PRIV.RDB$PRIVILEGE[0] = 'D'; PRIV.RDB$GRANT_OPTION = 1; break; case 4: strcpy(PRIV.RDB$USER, user_name.c_str()); PRIV.RDB$PRIVILEGE[0] = 'R'; PRIV.RDB$GRANT_OPTION = 1; break; default: strcpy(PRIV.RDB$USER, "PUBLIC"); PRIV.RDB$PRIVILEGE[0] = 'S'; PRIV.RDB$GRANT_OPTION = 0; break; } strcpy(PRIV.RDB$GRANTOR, user_name.c_str()); PRIV.RDB$PRIVILEGE[1] = 0; strcpy(PRIV.RDB$RELATION_NAME, rel_name); PRIV.RDB$FIELD_NAME.NULL = TRUE; PRIV.RDB$USER_TYPE = obj_user; PRIV.RDB$OBJECT_TYPE = obj_relation; END_STORE; } CMP_release(tdbb, handle1); handle1 = NULL; STORE(REQUEST_HANDLE handle1) CLS IN RDB$SECURITY_CLASSES jrd_vtof((char*)sec_class_name, CLS.RDB$SECURITY_CLASS, sizeof(CLS.RDB$SECURITY_CLASS)); CLS.RDB$ACL = blob_id_1; END_STORE; CMP_release(tdbb, handle1); handle1 = NULL; STORE(REQUEST_HANDLE handle1) CLS IN RDB$SECURITY_CLASSES jrd_vtof(default_class.c_str(), CLS.RDB$SECURITY_CLASS, sizeof(CLS.RDB$SECURITY_CLASS)); CLS.RDB$ACL = blob_id_2; END_STORE; CMP_release(tdbb, handle1); handle1 = NULL; FOR(REQUEST_HANDLE handle1) REL IN RDB$RELATIONS WITH REL.RDB$RELATION_NAME EQ rel_name MODIFY REL USING REL.RDB$DEFAULT_CLASS.NULL = FALSE; jrd_vtof(default_class.c_str(), REL.RDB$DEFAULT_CLASS, sizeof(REL.RDB$DEFAULT_CLASS)); END_MODIFY; END_FOR; CMP_release(tdbb, handle1); } static int init2_helper(const int* fld, int n, jrd_rel* relation) { if (!fld[RFLD_F_MINOR]) { ++n; if (fld[RFLD_F_UPD_MINOR]) relation->rel_flags |= REL_force_scan; } else { relation->rel_flags |= REL_force_scan; } return n; } static void modify_relation_field(thread_db* tdbb, const int* fld, const int* relfld, jrd_req** handle) { /************************************** * * m o d i f y _ r e l a t i o n _ f i e l d * ************************************** * * Functional description * Modify a local field according to the * passed information. Note that the field id and * field position do not change. * **************************************/ SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); FOR(REQUEST_HANDLE * handle) X IN RDB$RELATION_FIELDS WITH X.RDB$RELATION_NAME EQ names[relfld[RFLD_R_NAME]] AND X.RDB$FIELD_NAME EQ names[fld[RFLD_F_NAME]] MODIFY X USING const gfld* gfield = &gfields[fld[RFLD_F_UPD_ID]]; PAD(names[gfield->gfld_name], X.RDB$FIELD_SOURCE); X.RDB$UPDATE_FLAG = fld[RFLD_F_UPDATE]; END_MODIFY; END_FOR; } static void store_generator(thread_db* tdbb, const gen* generator, jrd_req** handle) { /************************************** * * s t o r e _ g e n e r a t o r * ************************************** * * Functional description * Store the passed generator according to * the information in the generator block. * **************************************/ SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); STORE(REQUEST_HANDLE * handle) X IN RDB$GENERATORS PAD(generator->gen_name, X.RDB$GENERATOR_NAME); X.RDB$GENERATOR_ID = generator->gen_id; X.RDB$SYSTEM_FLAG = RDB_system; X.RDB$SYSTEM_FLAG.NULL = FALSE; if (generator->gen_description) { blb* blob = BLB_create(tdbb, dbb->dbb_sys_trans, &X.RDB$DESCRIPTION); BLB_put_segment(tdbb, blob, reinterpret_cast(generator->gen_description), strlen(generator->gen_description)); BLB_close(tdbb, blob); X.RDB$DESCRIPTION.NULL = FALSE; } else { X.RDB$DESCRIPTION.NULL = TRUE; } END_STORE; } static void store_global_field(thread_db* tdbb, const gfld* gfield, jrd_req** handle) { /************************************** * * s t o r e _ g l o b a l _ f i e l d * ************************************** * * Functional description * Store a global field according to the * passed information. * **************************************/ SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); STORE(REQUEST_HANDLE * handle) X IN RDB$FIELDS PAD(names[(USHORT)gfield->gfld_name], X.RDB$FIELD_NAME); X.RDB$FIELD_LENGTH = gfield->gfld_length; X.RDB$FIELD_SCALE = 0; X.RDB$SYSTEM_FLAG = RDB_system; X.RDB$SYSTEM_FLAG.NULL = FALSE; X.RDB$FIELD_SUB_TYPE.NULL = TRUE; X.RDB$CHARACTER_SET_ID.NULL = TRUE; X.RDB$COLLATION_ID.NULL = TRUE; X.RDB$SEGMENT_LENGTH.NULL = TRUE; if (gfield->gfld_dflt_blr) { blb* blob = BLB_create(tdbb, dbb->dbb_sys_trans, &X.RDB$DEFAULT_VALUE); BLB_put_segment(tdbb, blob, gfield->gfld_dflt_blr, gfield->gfld_dflt_len); BLB_close(tdbb, blob); X.RDB$DEFAULT_VALUE.NULL = FALSE; } else { X.RDB$DEFAULT_VALUE.NULL = TRUE; } switch (gfield->gfld_dtype) { case dtype_timestamp: X.RDB$FIELD_TYPE = (int) blr_timestamp; break; case dtype_sql_time: X.RDB$FIELD_TYPE = (int) blr_sql_time; break; case dtype_sql_date: X.RDB$FIELD_TYPE = (int) blr_sql_date; break; case dtype_short: case dtype_long: case dtype_int64: if (gfield->gfld_dtype == dtype_short) X.RDB$FIELD_TYPE = (int) blr_short; else if (gfield->gfld_dtype == dtype_long) X.RDB$FIELD_TYPE = (int) blr_long; else { // Workaround to allow fld_counter domain // in dialect 1 databases if (dbb->dbb_flags & DBB_DB_SQL_dialect_3) X.RDB$FIELD_TYPE = (int) blr_int64; else X.RDB$FIELD_TYPE = (int) blr_double; } if ((gfield->gfld_sub_type == dsc_num_type_numeric) || (gfield->gfld_sub_type == dsc_num_type_decimal)) { X.RDB$FIELD_SUB_TYPE.NULL = FALSE; X.RDB$FIELD_SUB_TYPE = gfield->gfld_sub_type; } break; case dtype_double: X.RDB$FIELD_TYPE = (int) blr_double; break; case dtype_text: case dtype_varying: if (gfield->gfld_dtype == dtype_text) { X.RDB$FIELD_TYPE = (int) blr_text; } else { X.RDB$FIELD_TYPE = (int) blr_varying; } switch (gfield->gfld_sub_type) { case dsc_text_type_metadata: X.RDB$CHARACTER_SET_ID.NULL = FALSE; X.RDB$CHARACTER_SET_ID = CS_METADATA; X.RDB$COLLATION_ID.NULL = FALSE; X.RDB$COLLATION_ID = COLLATE_NONE; X.RDB$FIELD_SUB_TYPE.NULL = FALSE; X.RDB$FIELD_SUB_TYPE = gfield->gfld_sub_type; break; case dsc_text_type_ascii: X.RDB$CHARACTER_SET_ID.NULL = FALSE; X.RDB$CHARACTER_SET_ID = CS_ASCII; X.RDB$COLLATION_ID.NULL = FALSE; X.RDB$COLLATION_ID = COLLATE_NONE; X.RDB$FIELD_SUB_TYPE.NULL = FALSE; X.RDB$FIELD_SUB_TYPE = gfield->gfld_sub_type; break; case dsc_text_type_fixed: X.RDB$CHARACTER_SET_ID.NULL = FALSE; X.RDB$CHARACTER_SET_ID = CS_BINARY; X.RDB$COLLATION_ID.NULL = FALSE; X.RDB$COLLATION_ID = COLLATE_NONE; X.RDB$FIELD_SUB_TYPE.NULL = FALSE; X.RDB$FIELD_SUB_TYPE = gfield->gfld_sub_type; break; default: X.RDB$CHARACTER_SET_ID.NULL = FALSE; X.RDB$CHARACTER_SET_ID = CS_NONE; X.RDB$COLLATION_ID.NULL = FALSE; X.RDB$COLLATION_ID = COLLATE_NONE; break; } break; case dtype_blob: X.RDB$FIELD_TYPE = (int) blr_blob; X.RDB$FIELD_SUB_TYPE.NULL = FALSE; X.RDB$SEGMENT_LENGTH.NULL = FALSE; X.RDB$FIELD_SUB_TYPE = gfield->gfld_sub_type; X.RDB$SEGMENT_LENGTH = 80; if (gfield->gfld_sub_type == isc_blob_text) { X.RDB$CHARACTER_SET_ID.NULL = FALSE; X.RDB$CHARACTER_SET_ID = CS_METADATA; } break; default: fb_assert(FALSE); break; } /* For the next ODS change, when we'll have not NULL sys fields X.RDB$NULL_FLAG.NULL = FALSE; X.RDB$NULL_FLAG = gfield->gfld_null_flag; */ END_STORE; } static void store_intlnames(thread_db* tdbb, Database* dbb) { /************************************** * * s t o r e _ i n t l n a m e s * ************************************** * * Functional description * Store symbolic names & information for international * character sets & collations. * **************************************/ SET_TDBB(tdbb); jrd_req* handle = NULL; for (const IntlManager::CharSetDefinition* charSet = IntlManager::defaultCharSets; charSet->name; ++charSet) { STORE(REQUEST_HANDLE handle) X IN RDB$CHARACTER_SETS USING PAD(charSet->name, X.RDB$CHARACTER_SET_NAME); PAD(charSet->name, X.RDB$DEFAULT_COLLATE_NAME); X.RDB$CHARACTER_SET_ID = charSet->id; X.RDB$BYTES_PER_CHARACTER = charSet->maxBytes; X.RDB$SYSTEM_FLAG = RDB_system; X.RDB$SYSTEM_FLAG.NULL = FALSE; END_STORE; } CMP_release(tdbb, handle); handle = NULL; for (const IntlManager::CollationDefinition* collation = IntlManager::defaultCollations; collation->name; ++collation) { STORE(REQUEST_HANDLE handle) X IN RDB$COLLATIONS USING PAD(collation->name, X.RDB$COLLATION_NAME); if (collation->baseName) { X.RDB$BASE_COLLATION_NAME.NULL = false; PAD(collation->baseName, X.RDB$BASE_COLLATION_NAME); } else X.RDB$BASE_COLLATION_NAME.NULL = true; X.RDB$CHARACTER_SET_ID = collation->charSetId; X.RDB$COLLATION_ID = collation->collationId; X.RDB$SYSTEM_FLAG = RDB_system; X.RDB$SYSTEM_FLAG.NULL = FALSE; X.RDB$COLLATION_ATTRIBUTES = collation->attributes; if (collation->specificAttributes) { blb* blob = BLB_create(tdbb, dbb->dbb_sys_trans, &X.RDB$SPECIFIC_ATTRIBUTES); BLB_put_segment(tdbb, blob, reinterpret_cast(collation->specificAttributes), strlen(collation->specificAttributes)); BLB_close(tdbb, blob); X.RDB$SPECIFIC_ATTRIBUTES.NULL = FALSE; } else X.RDB$SPECIFIC_ATTRIBUTES.NULL = TRUE; END_STORE; } CMP_release(tdbb, handle); handle = NULL; } static void store_function_argument(thread_db* tdbb, Database* dbb, jrd_req*& handle, const char* function_name, SLONG argument_position, SLONG mechanism, SLONG type, SLONG scale, SLONG length, SLONG sub_type, SLONG charset, SLONG precision, SLONG char_length) { STORE(REQUEST_HANDLE handle) FA IN RDB$FUNCTION_ARGUMENTS PAD(function_name, FA.RDB$FUNCTION_NAME); FA.RDB$FUNCTION_NAME.NULL = FALSE; FA.RDB$ARGUMENT_POSITION = argument_position; FA.RDB$MECHANISM = mechanism; FA.RDB$FIELD_TYPE = type; FA.RDB$FIELD_SCALE = scale; FA.RDB$FIELD_LENGTH = length; FA.RDB$FIELD_SUB_TYPE = sub_type; FA.RDB$CHARACTER_SET_ID = charset; FA.RDB$FIELD_PRECISION = precision; FA.RDB$CHARACTER_LENGTH = char_length; END_STORE; } static void store_function(thread_db* tdbb, Database* dbb, jrd_req*& handle, const char* function_name, const char* module, const char* entrypoint, SLONG argument) { STORE(REQUEST_HANDLE handle) F IN RDB$FUNCTIONS PAD(function_name, F.RDB$FUNCTION_NAME); F.RDB$FUNCTION_NAME.NULL = FALSE; //F.RDB$FUNCTION_TYPE //F.RDB$QUERY_NAME //F.RDB$DESCRIPTION strcpy(F.RDB$MODULE_NAME, module); F.RDB$MODULE_NAME.NULL = FALSE; PAD(entrypoint, F.RDB$ENTRYPOINT); F.RDB$ENTRYPOINT.NULL = FALSE; F.RDB$RETURN_ARGUMENT = argument; F.RDB$SYSTEM_FLAG = RDB_system; F.RDB$SYSTEM_FLAG.NULL = FALSE; END_STORE; } static void store_functions(thread_db* tdbb, Database* dbb) { /************************************** * * s t o r e _ f u n c t i o n s * ************************************** * * Functional description * Store built-in functions and their arguments * **************************************/ SET_TDBB(tdbb); jrd_req *fun_handle = NULL, *arg_handle = NULL; const char *function_name; SLONG argument_position; #define FUNCTION(ROUTINE, FUNCTION_NAME, MODULE_NAME, ENTRYPOINT, RET_ARG) \ function_name = FUNCTION_NAME; \ argument_position = RET_ARG ? 1 : 0; \ store_function(tdbb, dbb, fun_handle, FUNCTION_NAME, MODULE_NAME, ENTRYPOINT, RET_ARG); #define END_FUNCTION #define FUNCTION_ARGUMENT(MECHANISM, TYPE, SCALE, LENGTH, SUB_TYPE, CHARSET, PRECISION, CHAR_LENGTH) \ store_function_argument(tdbb, dbb, arg_handle, function_name, argument_position, \ MECHANISM, TYPE, SCALE, LENGTH, SUB_TYPE, CHARSET, PRECISION, CHAR_LENGTH); \ argument_position++; #include "../jrd/functions.h" CMP_release(tdbb, fun_handle); CMP_release(tdbb, arg_handle); } static void store_message(thread_db* tdbb, const trigger_msg* message, jrd_req** handle) { /************************************** * * s t o r e _ m e s s a g e * ************************************** * * Functional description * Store system trigger messages. * **************************************/ SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); /* store the trigger */ STORE(REQUEST_HANDLE * handle) X IN RDB$TRIGGER_MESSAGES PAD(message->trigmsg_name, X.RDB$TRIGGER_NAME); X.RDB$MESSAGE_NUMBER = message->trigmsg_number; PAD(message->trigmsg_text, X.RDB$MESSAGE); END_STORE; } static void store_relation_field(thread_db* tdbb, const int* fld, const int* relfld, int field_id, jrd_req** handle, bool fmt0_flag) { /************************************** * * s t o r e _ r e l a t i o n _ f i e l d * ************************************** * * Functional description * Store a local field according to the * passed information. * **************************************/ SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); STORE(REQUEST_HANDLE * handle) X IN RDB$RELATION_FIELDS const gfld* gfield = (fld[RFLD_F_UPD_MINOR] && !fmt0_flag) ? &gfields[fld[RFLD_F_UPD_ID]] : &gfields[fld[RFLD_F_ID]]; PAD(names[relfld[RFLD_R_NAME]], X.RDB$RELATION_NAME); PAD(names[fld[RFLD_F_NAME]], X.RDB$FIELD_NAME); PAD(names[gfield->gfld_name], X.RDB$FIELD_SOURCE); X.RDB$FIELD_POSITION = field_id; X.RDB$FIELD_ID = field_id; X.RDB$SYSTEM_FLAG = RDB_system; X.RDB$SYSTEM_FLAG.NULL = FALSE; X.RDB$UPDATE_FLAG = fld[RFLD_F_UPDATE]; END_STORE; } static void store_trigger(thread_db* tdbb, const jrd_trg* trigger, jrd_req** handle) { /************************************** * * s t o r e _ t r i g g e r * ************************************** * * Functional description * Store the trigger according to the * information in the trigger block. * **************************************/ SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); /* indicate that the relation format needs revising */ dsc desc; desc.dsc_dtype = dtype_text; INTL_ASSIGN_DSC(&desc, CS_METADATA, COLLATE_NONE); desc.dsc_address = (UCHAR*) names[trigger->trg_relation]; desc.dsc_length = strlen((char*)desc.dsc_address); DFW_post_system_work(tdbb, dfw_update_format, &desc, 0); /* store the trigger */ STORE(REQUEST_HANDLE * handle) X IN RDB$TRIGGERS PAD(trigger->trg_name, X.RDB$TRIGGER_NAME); PAD(names[trigger->trg_relation], X.RDB$RELATION_NAME); X.RDB$TRIGGER_SEQUENCE = 0; X.RDB$SYSTEM_FLAG = RDB_system; X.RDB$SYSTEM_FLAG.NULL = FALSE; X.RDB$TRIGGER_TYPE = trigger->trg_type; X.RDB$FLAGS = trigger->trg_flags; blb* blob = BLB_create(tdbb, dbb->dbb_sys_trans, &X.RDB$TRIGGER_BLR); BLB_put_segment(tdbb, blob, trigger->trg_blr, trigger->trg_length); BLB_close(tdbb, blob); END_STORE; }