diff --git a/src/alice/alice.h b/src/alice/alice.h index f08834bb86d..419c4252a96 100644 --- a/src/alice/alice.h +++ b/src/alice/alice.h @@ -73,7 +73,6 @@ enum alice_repl_mode { struct user_action { - ULONG ua_switches; const char* ua_user; const char* ua_role; const char* ua_password; diff --git a/src/alice/aliceswi.h b/src/alice/aliceswi.h index 3702d06e7ee..73ce96f8cda 100644 --- a/src/alice/aliceswi.h +++ b/src/alice/aliceswi.h @@ -66,6 +66,7 @@ const SINT64 sw_nolinger = QUADCONST(0x0000001000000000); const SINT64 sw_icu = QUADCONST(0x0000002000000000); const SINT64 sw_role = QUADCONST(0x0000004000000000); const SINT64 sw_replica = QUADCONST(0x0000008000000000); +const SINT64 sw_upgrade = QUADCONST(0x0000010000000000); // Popular combination of compatible switches const SINT64 sw_auth_set = sw_user | sw_password | sw_role | sw_fetch_password | sw_trusted_auth; @@ -126,7 +127,8 @@ enum alice_switches IN_SW_ALICE_ICU = 48, IN_SW_ALICE_ROLE = 49, IN_SW_ALICE_REPLICA = 50, - IN_SW_ALICE_PARALLEL_WORKERS = 51 + IN_SW_ALICE_PARALLEL_WORKERS = 51, + IN_SW_ALICE_UPGRADE = 52 }; static const char* const ALICE_SW_ASYNC = "ASYNC"; @@ -259,6 +261,9 @@ static const Switches::in_sw_tab_t alice_in_sw_table[] = 0, (sw_user | sw_password | sw_fetch_password), false, false, 115, 3, NULL}, // msg 115: -trusted use trusted authentication #endif + {IN_SW_ALICE_UPGRADE, isc_spb_rpr_upgrade_db, "UPGRADE", sw_upgrade, + 0, ~(sw_upgrade | sw_user | sw_password | sw_nolinger | sw_role), false, true, 137, 2, NULL}, + // msg 137: \t-upgrade\t\tupgrade database ODS {IN_SW_ALICE_NO_RESERVE, 0, "USE", sw_no_reserve, 0, ~(sw_no_reserve | sw_auth_set | sw_nolinger), false, false, 49, 1, NULL}, // msg 49: \t-use\t\tuse full or reserve space for versions diff --git a/src/alice/exe.cpp b/src/alice/exe.cpp index 5dc13750a4a..0d9b9929da2 100644 --- a/src/alice/exe.cpp +++ b/src/alice/exe.cpp @@ -335,6 +335,9 @@ static void buildDpb(Firebird::ClumpletWriter& dpb, const SINT64 switches) if (switches & sw_icu) dpb.insertTag(isc_dpb_reset_icu); + if (switches & sw_upgrade) + dpb.insertTag(isc_dpb_upgrade_db); + const unsigned char* authBlock; unsigned int authBlockSize = tdgbl->uSvc->getAuthBlock(&authBlock); diff --git a/src/include/firebird/impl/consts_pub.h b/src/include/firebird/impl/consts_pub.h index 57bd35f5e0a..688d952de56 100644 --- a/src/include/firebird/impl/consts_pub.h +++ b/src/include/firebird/impl/consts_pub.h @@ -129,6 +129,7 @@ #define isc_dpb_decfloat_round 94 #define isc_dpb_decfloat_traps 95 #define isc_dpb_clear_map 96 +#define isc_dpb_upgrade_db 97 #define isc_dpb_parallel_workers 100 #define isc_dpb_worker_attach 101 @@ -536,6 +537,7 @@ #define isc_spb_rpr_kill_shadows 0x40 #define isc_spb_rpr_full 0x80 #define isc_spb_rpr_icu 0x0800 +#define isc_spb_rpr_upgrade_db 0x1000 /***************************************** * Parameters for isc_action_svc_restore * diff --git a/src/include/firebird/impl/msg/gfix.h b/src/include/firebird/impl/msg/gfix.h index a990b759e51..d1ba2d0d7ba 100644 --- a/src/include/firebird/impl/msg/gfix.h +++ b/src/include/firebird/impl/msg/gfix.h @@ -134,3 +134,4 @@ FB_IMPL_MSG_SYMBOL(GFIX, 133, gfix_role_req, "SQL role name required") FB_IMPL_MSG_SYMBOL(GFIX, 134, gfix_opt_repl, " -repl(ica) replica mode ") FB_IMPL_MSG_SYMBOL(GFIX, 135, gfix_repl_mode_req, "replica mode (none / read_only / read_write) required") FB_IMPL_MSG_SYMBOL(GFIX, 136, gfix_opt_parallel, " -par(allel) parallel workers (-sweep)") +FB_IMPL_MSG_SYMBOL(GFIX, 137, gfix_opt_upgrade, " -up(grade) upgrade database ODS") diff --git a/src/include/firebird/impl/msg/jrd.h b/src/include/firebird/impl/msg/jrd.h index 4ad003d2a22..8848102feb8 100644 --- a/src/include/firebird/impl/msg/jrd.h +++ b/src/include/firebird/impl/msg/jrd.h @@ -963,3 +963,4 @@ FB_IMPL_MSG(JRD, 961, wrong_shmem_bitness, -902, "08", "006", "@1-bit engine can FB_IMPL_MSG(JRD, 962, wrong_proc_plan, -281, "HY", "000", "Procedures cannot specify access type other than NATURAL in the plan") FB_IMPL_MSG(JRD, 963, invalid_blob_util_handle, -402, "42", "000", "Invalid RDB$BLOB_UTIL handle") FB_IMPL_MSG(JRD, 964, bad_temp_blob_id, -402, "42", "000", "Invalid temporary BLOB ID") +FB_IMPL_MSG(JRD, 965, ods_upgrade_err, -901, "HY", "000", "ODS upgrade failed while adding new system %s") diff --git a/src/include/gen/Firebird.pas b/src/include/gen/Firebird.pas index 4778c4474e6..f65483acaaa 100644 --- a/src/include/gen/Firebird.pas +++ b/src/include/gen/Firebird.pas @@ -3986,6 +3986,7 @@ IProfilerStatsImpl = class(IProfilerStats) isc_dpb_decfloat_round = byte(94); isc_dpb_decfloat_traps = byte(95); isc_dpb_clear_map = byte(96); + isc_dpb_upgrade_db = byte(97); isc_dpb_parallel_workers = byte(100); isc_dpb_worker_attach = byte(101); isc_dpb_address = byte(1); @@ -4222,6 +4223,7 @@ IProfilerStatsImpl = class(IProfilerStats) isc_spb_rpr_kill_shadows = $40; isc_spb_rpr_full = $80; isc_spb_rpr_icu = $0800; + isc_spb_rpr_upgrade_db = $1000; isc_spb_res_buffers = byte(9); isc_spb_res_page_size = byte(10); isc_spb_res_length = byte(11); @@ -5304,6 +5306,7 @@ IProfilerStatsImpl = class(IProfilerStats) isc_wrong_proc_plan = 335545282; isc_invalid_blob_util_handle = 335545283; isc_bad_temp_blob_id = 335545284; + isc_ods_upgrade_err = 335545285; isc_gfix_db_name = 335740929; isc_gfix_invalid_sw = 335740930; isc_gfix_incmp_sw = 335740932; diff --git a/src/jrd/RecordSourceNodes.cpp b/src/jrd/RecordSourceNodes.cpp index 4c9b477e940..9b5218b8252 100644 --- a/src/jrd/RecordSourceNodes.cpp +++ b/src/jrd/RecordSourceNodes.cpp @@ -620,10 +620,10 @@ RelationSourceNode* RelationSourceNode::parse(thread_db* tdbb, CompilerScratch* // Scan the relation if it hasn't already been scanned for meta data - if ((!(node->relation->rel_flags & REL_scanned) || (node->relation->rel_flags & REL_being_scanned)) && - ((node->relation->rel_flags & REL_force_scan) || !(csb->csb_g_flags & csb_internal))) + if ((!(node->relation->rel_flags & REL_scanned) || + (node->relation->rel_flags & REL_being_scanned)) && + !(csb->csb_g_flags & csb_internal)) { - node->relation->rel_flags &= ~REL_force_scan; MET_scan_relation(tdbb, node->relation); } else if (node->relation->rel_flags & REL_sys_triggers) diff --git a/src/jrd/Relation.h b/src/jrd/Relation.h index 8c4ffa77a62..36cedc69f82 100644 --- a/src/jrd/Relation.h +++ b/src/jrd/Relation.h @@ -384,22 +384,21 @@ const ULONG REL_scanned = 0x0001; // Field expressions scanned (or being sca const ULONG REL_system = 0x0002; const ULONG REL_deleted = 0x0004; // Relation known gonzo const ULONG REL_get_dependencies = 0x0008; // New relation needs dependencies during scan -const ULONG REL_force_scan = 0x0010; // system relation has been updated since ODS change, force a scan -const ULONG REL_check_existence = 0x0020; // Existence lock released pending drop of relation -const ULONG REL_blocking = 0x0040; // Blocking someone from dropping relation -const ULONG REL_sys_triggers = 0x0080; // The relation has system triggers to compile -const ULONG REL_sql_relation = 0x0100; // Relation defined as sql table -const ULONG REL_check_partners = 0x0200; // Rescan primary dependencies and foreign references -const ULONG REL_being_scanned = 0x0400; // relation scan in progress -const ULONG REL_sys_trigs_being_loaded = 0x0800; // System triggers being loaded -const ULONG REL_deleting = 0x1000; // relation delete in progress -const ULONG REL_temp_tran = 0x2000; // relation is a GTT delete rows -const ULONG REL_temp_conn = 0x4000; // relation is a GTT preserve rows -const ULONG REL_virtual = 0x8000; // relation is virtual -const ULONG REL_jrd_view = 0x10000; // relation is VIEW -const ULONG REL_gc_blocking = 0x20000; // request to downgrade\release gc lock -const ULONG REL_gc_disabled = 0x40000; // gc is disabled temporarily -const ULONG REL_gc_lockneed = 0x80000; // gc lock should be acquired +const ULONG REL_check_existence = 0x0010; // Existence lock released pending drop of relation +const ULONG REL_blocking = 0x0020; // Blocking someone from dropping relation +const ULONG REL_sys_triggers = 0x0040; // The relation has system triggers to compile +const ULONG REL_sql_relation = 0x0080; // Relation defined as sql table +const ULONG REL_check_partners = 0x0100; // Rescan primary dependencies and foreign references +const ULONG REL_being_scanned = 0x0200; // relation scan in progress +const ULONG REL_sys_trigs_being_loaded = 0x0400; // System triggers being loaded +const ULONG REL_deleting = 0x0800; // relation delete in progress +const ULONG REL_temp_tran = 0x1000; // relation is a GTT delete rows +const ULONG REL_temp_conn = 0x2000; // relation is a GTT preserve rows +const ULONG REL_virtual = 0x4000; // relation is virtual +const ULONG REL_jrd_view = 0x8000; // relation is VIEW +const ULONG REL_gc_blocking = 0x10000; // request to downgrade\release gc lock +const ULONG REL_gc_disabled = 0x20000; // gc is disabled temporarily +const ULONG REL_gc_lockneed = 0x40000; // gc lock should be acquired /// class jrd_rel diff --git a/src/jrd/WorkerAttachment.cpp b/src/jrd/WorkerAttachment.cpp index 2cb2ead1fb4..053e5a7b70f 100644 --- a/src/jrd/WorkerAttachment.cpp +++ b/src/jrd/WorkerAttachment.cpp @@ -63,7 +63,6 @@ WorkerStableAttachment::WorkerStableAttachment(FbStatusVector* status, Jrd::Atta LCK_init(tdbb, LCK_OWNER_attachment); INI_init(tdbb); - INI_init2(tdbb); PAG_header(tdbb, true); PAG_attachment_id(tdbb); TRA_init(attachment); diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 8536ab4e822..cebaeb5156a 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -1481,26 +1481,6 @@ void DFW_merge_work(jrd_tra* transaction, SavNumber old_sav_number, SavNumber ne } -void DFW_perform_system_work(thread_db* tdbb) -{ -/************************************** - * - * D F W _ p e r f o r m _ s y s t e m _ w o r k - * - ************************************** - * - * Functional description - * Flush out the work left to be done in the - * system transaction. - * - **************************************/ - SET_TDBB(tdbb); - Jrd::Attachment* attachment = tdbb->getAttachment(); - - DFW_perform_work(tdbb, attachment->getSysTransaction()); -} - - void DFW_perform_work(thread_db* tdbb, jrd_tra* transaction) { /************************************** @@ -1680,25 +1660,6 @@ void DFW_perform_post_commit_work(jrd_tra* transaction) } -DeferredWork* DFW_post_system_work(thread_db* tdbb, enum dfw_t type, const dsc* desc, USHORT id) -{ -/************************************** - * - * D F W _ p o s t _ s y s t e m _ w o r k - * - ************************************** - * - * Functional description - * Post work to be done in the context of system transaction. - * - **************************************/ - SET_TDBB(tdbb); - Jrd::Attachment* attachment = tdbb->getAttachment(); - - return DFW_post_work(attachment->getSysTransaction(), type, desc, id, ""); -} - - DeferredWork* DFW_post_work(jrd_tra* transaction, enum dfw_t type, const dsc* desc, USHORT id, const MetaName& package) { diff --git a/src/jrd/dfw_proto.h b/src/jrd/dfw_proto.h index 850e1e54011..1681e9d727b 100644 --- a/src/jrd/dfw_proto.h +++ b/src/jrd/dfw_proto.h @@ -35,10 +35,8 @@ USHORT DFW_assign_index_type(Jrd::thread_db*, const Jrd::MetaName&, SSHORT, SSHO void DFW_delete_deferred(Jrd::jrd_tra*, SavNumber); Firebird::SortedArray& DFW_get_ids(Jrd::DeferredWork* work); void DFW_merge_work(Jrd::jrd_tra*, SavNumber, SavNumber); -void DFW_perform_system_work(Jrd::thread_db*); void DFW_perform_work(Jrd::thread_db*, Jrd::jrd_tra*); void DFW_perform_post_commit_work(Jrd::jrd_tra*); -Jrd::DeferredWork* DFW_post_system_work(Jrd::thread_db*, Jrd::dfw_t, const dsc*, USHORT); Jrd::DeferredWork* DFW_post_work(Jrd::jrd_tra*, Jrd::dfw_t, const dsc*, USHORT, const Jrd::MetaName& package = NULL); Jrd::DeferredWork* DFW_post_work(Jrd::jrd_tra*, Jrd::dfw_t, const Firebird::string&, USHORT, diff --git a/src/jrd/fields.h b/src/jrd/fields.h index ae9818b3541..98c6a97da14 100644 --- a/src/jrd/fields.h +++ b/src/jrd/fields.h @@ -22,213 +22,213 @@ */ -// type , name , dtype , length , sub_type , dflt_blr , nullable) - FIELD(fld_context , nam_v_context , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_ctx_name , nam_context , dtype_text , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true) - FIELD(fld_description , nam_description , dtype_blob , BLOB_SIZE , isc_blob_text , NULL , true) - FIELD(fld_edit_string , nam_edit_string , dtype_varying , 127 , 0 , NULL , true) - FIELD(fld_f_id , nam_f_id , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_f_name , nam_f_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_flag , nam_sys_flag , dtype_short , sizeof(SSHORT) , 0 , NULL , false) - FIELD(fld_flag_nullable , nam_sys_nullflag , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_i_id , nam_i_id , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_i_name , nam_i_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_f_length , nam_f_length , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_f_position , nam_f_position , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_f_scale , nam_f_scale , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_f_type , nam_f_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_format , nam_fmt , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_key_length , nam_key_length , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_p_number , nam_p_number , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_p_sequence , nam_p_sequence , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_p_type , nam_p_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_q_header , nam_q_header , dtype_blob , BLOB_SIZE , isc_blob_text , NULL , true) - FIELD(fld_r_id , nam_r_id , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_r_name , nam_r_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_s_count , nam_s_count , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_s_length , nam_s_length , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_source , nam_source , dtype_blob , BLOB_SIZE , isc_blob_text , NULL , true) - FIELD(fld_sub_type , nam_f_sub_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_v_blr , nam_v_blr , dtype_blob , BLOB_SIZE , isc_blob_blr , NULL , true) - FIELD(fld_validation , nam_vl_blr , dtype_blob , BLOB_SIZE , isc_blob_blr , NULL , true) - FIELD(fld_value , nam_value , dtype_blob , BLOB_SIZE , isc_blob_blr , NULL , true) - FIELD(fld_class , nam_class , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_acl , nam_acl , dtype_blob , BLOB_SIZE , isc_blob_acl , NULL , true) - FIELD(fld_file_name , nam_file_name , dtype_varying , 255 , 0 , NULL , true) - FIELD(fld_file_name2 , nam_file_name2 , dtype_varying , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true) - FIELD(fld_file_seq , nam_file_seq , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_file_start , nam_file_start , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_file_length , nam_file_length , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_file_flags , nam_file_flags , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_trigger , nam_trigger , dtype_blob , BLOB_SIZE , isc_blob_blr , NULL , true) - - FIELD(fld_trg_name , nam_trg_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_gnr_name , nam_gnr_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_fun_name , nam_fun_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_ext_name , nam_ext_name , dtype_text , 255 , 0 , NULL , true) - FIELD(fld_typ_name , nam_typ_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_dimensions , nam_dimensions , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_runtime , nam_runtime , dtype_blob , BLOB_SIZE , isc_blob_summary , NULL , true) - FIELD(fld_trg_seq , nam_trg_seq , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_gnr_type , nam_gnr_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_trg_type , nam_trg_type , dtype_int64 , sizeof(SINT64) , 0 , NULL , true) - FIELD(fld_obj_type , nam_obj_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_mechanism , nam_mechanism , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_f_descr , nam_desc , dtype_blob , BLOB_SIZE , isc_blob_format , NULL , true) - FIELD(fld_fun_type , nam_fun_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_trans_id , nam_trans_id , dtype_int64 , sizeof(SINT64) , 0 , NULL , true) - FIELD(fld_trans_state , nam_trans_state , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_time , nam_time , dtype_timestamp, TIMESTAMP_SIZE , 0 , NULL , true) - FIELD(fld_trans_desc , nam_trans_desc , dtype_blob , BLOB_SIZE , isc_blob_tra , NULL , true) - FIELD(fld_msg , nam_msg , dtype_varying , 1023 , 0 , NULL , true) - FIELD(fld_msg_num , nam_msg_num , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_user , nam_user , dtype_text , USERNAME_LENGTH , dsc_text_type_metadata , NULL , true) - FIELD(fld_privilege , nam_privilege , dtype_text , 6 , 0 , NULL , true) - FIELD(fld_ext_desc , nam_ext_desc , dtype_blob , BLOB_SIZE , isc_blob_extfile , NULL , true) - FIELD(fld_shad_num , nam_shad_num , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_gen_name , nam_gen_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_gen_id , nam_gen_id , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_bound , nam_bound , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_dim , nam_dim , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_statistics , nam_statistics , dtype_double , sizeof(double) , 0 , NULL , true) - FIELD(fld_null_flag , nam_null_flag , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_con_name , nam_con_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_con_type , nam_con_type , dtype_text , 11 , 0 , NULL , true) - FIELD(fld_defer , nam_defer , dtype_text , 3 , 0 , dflt_no , true) - FIELD(fld_match , nam_match , dtype_text , 7 , 0 , dflt_full , true) - FIELD(fld_rule , nam_rule , dtype_text , 11 , 0 , dflt_restrict, true) - FIELD(fld_file_partitions, nam_file_partitions, dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_prc_blr , nam_prc_blr , dtype_blob , BLOB_SIZE , isc_blob_blr , NULL , true) - FIELD(fld_prc_id , nam_prc_id , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_prc_prm , nam_prc_prm , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_prc_name , nam_prc_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_prm_name , nam_prm_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_prm_number , nam_prm_number , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_prm_type , nam_prm_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - - FIELD(fld_charset_name , nam_charset_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_charset_id , nam_charset_id , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_collate_name , nam_collate_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_collate_id , nam_collate_id , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_num_chars , nam_num_chars , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_xcp_name , nam_xcp_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_xcp_number , nam_xcp_number , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_file_p_offset , nam_file_p_offset , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_f_precision , nam_f_precision , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - - FIELD(fld_backup_id , nam_backup_id , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_backup_level , nam_backup_level , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_guid , nam_guid , dtype_text , 38 , 0 , NULL , true) - FIELD(fld_scn , nam_scn , dtype_long , sizeof(SLONG) , 0 , NULL , true) - - FIELD(fld_specific_attr , nam_specific_attr , dtype_blob , BLOB_SIZE , isc_blob_text , NULL , true) - FIELD(fld_plugin_name , nam_plugin , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - - FIELD(fld_r_type , nam_r_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_prc_type , nam_prc_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - - FIELD(fld_att_id , nam_att_id , dtype_int64 , sizeof(SINT64) , 0 , NULL , true) - FIELD(fld_stmt_id , nam_stmt_id , dtype_int64 , sizeof(SINT64) , 0 , NULL , true) - FIELD(fld_call_id , nam_call_id , dtype_int64 , sizeof(SINT64) , 0 , NULL , true) - FIELD(fld_stat_id , nam_stat_id , dtype_long , sizeof(SLONG) , 0 , NULL , true) - - FIELD(fld_pid , nam_pid , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_state , nam_state , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_ods_number , nam_ods_number , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_page_size , nam_page_size , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_page_bufs , nam_page_bufs , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_shut_mode , nam_shut_mode , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_sql_dialect , nam_sql_dialect , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_sweep_int , nam_sweep_int , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_counter , nam_counter , dtype_int64 , sizeof(SINT64) , 0 , NULL , true) - - FIELD(fld_remote_proto , nam_remote_proto , dtype_varying , 10 , dsc_text_type_ascii , NULL , true) - FIELD(fld_remote_addr , nam_remote_addr , dtype_varying , 255 , dsc_text_type_ascii , NULL , true) - - FIELD(fld_iso_mode , nam_iso_mode , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_lock_timeout , nam_lock_timeout , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_backup_state , nam_backup_state , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_stat_group , nam_stat_group , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - - FIELD(fld_debug_info , nam_debug_info , dtype_blob , BLOB_SIZE , isc_blob_debug_info , NULL , true) - FIELD(fld_prm_mechanism , nam_prm_mechanism , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_src_info , nam_src_info , dtype_long , sizeof(SLONG) , 0 , NULL , true) - - FIELD(fld_ctx_var_name , nam_ctx_var_name , dtype_varying , 80 , 0 , NULL , true) - FIELD(fld_ctx_var_value , nam_ctx_var_value , dtype_varying , MAX_VARY_COLUMN_SIZE , 0 , NULL , true) - - FIELD(fld_engine_name , nam_engine_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - - FIELD(fld_pkg_name , nam_pkg_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - - FIELD(fld_fun_id , nam_fun_id , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_fun_blr , nam_fun_blr , dtype_blob , BLOB_SIZE , isc_blob_blr , NULL , true) - FIELD(fld_arg_name , nam_arg_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_arg_mechanism , nam_arg_mechanism , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - - FIELD(fld_identity_type , nam_identity_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_bool , nam_bool , dtype_boolean , 1 , 0 , NULL , true) - - FIELD(fld_user_name , nam_user_name , dtype_varying , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_attr_key , nam_sec_attr_key , dtype_varying , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_attr_value , nam_sec_attr_value, dtype_varying , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true) - FIELD(fld_name_part , nam_name_part , dtype_varying , 32 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true) - FIELD(fld_client_ver , nam_client_ver , dtype_varying , 255 , dsc_text_type_ascii , NULL , true) - FIELD(fld_remote_ver , nam_remote_ver , dtype_varying , 255 , dsc_text_type_ascii , NULL , true) - FIELD(fld_host_name , nam_host_name , dtype_varying , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true) - FIELD(fld_os_user , nam_os_user , dtype_varying , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true) - FIELD(fld_gen_val , nam_gen_val , dtype_int64 , sizeof(SINT64) , 0 , NULL , true) - FIELD(fld_auth_method , nam_auth_method , dtype_varying , 255 , dsc_text_type_ascii , NULL , true) - - FIELD(fld_linger , nam_linger , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_sec_db , nam_mon_secdb , dtype_text , 7 , dsc_text_type_ascii , NULL , false) - - FIELD(fld_map_name , nam_map_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , false) - FIELD(fld_map_using , nam_map_using , dtype_text , 1 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , false) - FIELD(fld_map_db , nam_map_db , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_map_from_type , nam_map_from_type , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , false) - FIELD(fld_map_from , nam_map_from , dtype_text , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true) - FIELD(fld_map_to , nam_map_to , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - - FIELD(fld_gen_increment , nam_gen_increment , dtype_long , sizeof(SLONG) , 0 , NULL , false) - FIELD(fld_plan , nam_plan , dtype_blob , BLOB_SIZE , isc_blob_text , NULL , true) - - FIELD(fld_system_privileges, nam_system_privileges, dtype_text, 8 , dsc_text_type_fixed , dflt_no_privs, true) - FIELD(fld_b_sql_security, nam_sql_security , dtype_boolean , 1 , 0 , NULL , true) - - FIELD(fld_idle_timeout , nam_idle_timeout , dtype_long , sizeof(SLONG) , 0 , NULL , false) - FIELD(fld_idle_timer , nam_idle_timer , dtype_timestamp_tz, TIMESTAMP_TZ_SIZE , 0 , NULL , true) - FIELD(fld_stmt_timeout , nam_stmt_timeout , dtype_long , sizeof(SLONG) , 0 , NULL , false) - FIELD(fld_stmt_timer , nam_stmt_timer , dtype_timestamp_tz, TIMESTAMP_TZ_SIZE , 0 , NULL , true) - - FIELD(fld_tz_id , nam_tz_id , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_tz_name , nam_tz_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - FIELD(fld_tz_offset , nam_tz_offset , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_timestamp_tz , nam_timestamp_tz , dtype_timestamp_tz, TIMESTAMP_TZ_SIZE , 0 , NULL , true) - - FIELD(fld_tz_db_version , nam_tz_db_version , dtype_varying , 10 , dsc_text_type_ascii , NULL , true) - - FIELD(fld_crypt_state , nam_crypt_state , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - FIELD(fld_remote_crypt , nam_wire_crypt_plugin, dtype_varying, MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) - - FIELD(fld_pub_name , nam_pub_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , false) - FIELD(fld_file_id , nam_file_id , dtype_varying , 255 , dsc_text_type_ascii , NULL , false) - - FIELD(fld_cfg_id , nam_cfg_id , dtype_long , sizeof(SLONG) , 0 , NULL , false) - FIELD(fld_cfg_name , nam_cfg_name , dtype_varying , MAX_CONFIG_NAME_LEN , dsc_text_type_ascii , NULL , false) - FIELD(fld_cfg_value , nam_cfg_value , dtype_varying , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true) - FIELD(fld_cfg_is_set , nam_cfg_is_set , dtype_boolean , 1 , 0 , NULL , false) - - FIELD(fld_repl_mode , nam_repl_mode , dtype_short , sizeof(SSHORT) , 0 , NULL , true) - - FIELD(fld_keyword_name , nam_keyword_name , dtype_varying , METADATA_IDENTIFIER_CHAR_LEN, dsc_text_type_ascii , NULL , false) - FIELD(fld_keyword_reserved, nam_keyword_reserved, dtype_boolean, 1 , 0 , NULL , false) - - FIELD(fld_short_description, nam_short_description, dtype_varying, 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata, NULL , true) - FIELD(fld_seconds_interval, nam_seconds_interval, dtype_long, sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_prof_ses_id , nam_prof_ses_id , dtype_int64 , sizeof(SINT64) , 0 , NULL , true) - - FIELD(fld_butil_handle , nam_butil_handle , dtype_long , sizeof(SLONG) , 0 , NULL , true) - FIELD(fld_blob , nam_blob , dtype_blob , BLOB_SIZE , isc_blob_untyped , NULL , true) - FIELD(fld_varybinary_max, nam_varbinary_max , dtype_varying , MAX_VARY_COLUMN_SIZE , 0 , NULL , true) - FIELD(fld_integer , nam_integer , dtype_long , sizeof(SLONG) , 0 , NULL , true) +// type , name , dtype , length , sub_type , dflt_blr , nullable , ods) + FIELD(fld_context , nam_v_context , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_ctx_name , nam_context , dtype_text , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_description , nam_description , dtype_blob , BLOB_SIZE , isc_blob_text , NULL , true , ODS_13_0) + FIELD(fld_edit_string , nam_edit_string , dtype_varying , 127 , 0 , NULL , true , ODS_13_0) + FIELD(fld_f_id , nam_f_id , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_f_name , nam_f_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_flag , nam_sys_flag , dtype_short , sizeof(SSHORT) , 0 , NULL , false , ODS_13_0) + FIELD(fld_flag_nullable , nam_sys_nullflag , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_i_id , nam_i_id , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_i_name , nam_i_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_f_length , nam_f_length , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_f_position , nam_f_position , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_f_scale , nam_f_scale , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_f_type , nam_f_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_format , nam_fmt , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_key_length , nam_key_length , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_p_number , nam_p_number , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_p_sequence , nam_p_sequence , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_p_type , nam_p_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_q_header , nam_q_header , dtype_blob , BLOB_SIZE , isc_blob_text , NULL , true , ODS_13_0) + FIELD(fld_r_id , nam_r_id , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_r_name , nam_r_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_s_count , nam_s_count , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_s_length , nam_s_length , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_source , nam_source , dtype_blob , BLOB_SIZE , isc_blob_text , NULL , true , ODS_13_0) + FIELD(fld_sub_type , nam_f_sub_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_v_blr , nam_v_blr , dtype_blob , BLOB_SIZE , isc_blob_blr , NULL , true , ODS_13_0) + FIELD(fld_validation , nam_vl_blr , dtype_blob , BLOB_SIZE , isc_blob_blr , NULL , true , ODS_13_0) + FIELD(fld_value , nam_value , dtype_blob , BLOB_SIZE , isc_blob_blr , NULL , true , ODS_13_0) + FIELD(fld_class , nam_class , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_acl , nam_acl , dtype_blob , BLOB_SIZE , isc_blob_acl , NULL , true , ODS_13_0) + FIELD(fld_file_name , nam_file_name , dtype_varying , 255 , 0 , NULL , true , ODS_13_0) + FIELD(fld_file_name2 , nam_file_name2 , dtype_varying , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_file_seq , nam_file_seq , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_file_start , nam_file_start , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_file_length , nam_file_length , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_file_flags , nam_file_flags , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_trigger , nam_trigger , dtype_blob , BLOB_SIZE , isc_blob_blr , NULL , true , ODS_13_0) + + FIELD(fld_trg_name , nam_trg_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_gnr_name , nam_gnr_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_fun_name , nam_fun_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_ext_name , nam_ext_name , dtype_text , 255 , 0 , NULL , true , ODS_13_0) + FIELD(fld_typ_name , nam_typ_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_dimensions , nam_dimensions , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_runtime , nam_runtime , dtype_blob , BLOB_SIZE , isc_blob_summary , NULL , true , ODS_13_0) + FIELD(fld_trg_seq , nam_trg_seq , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_gnr_type , nam_gnr_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_trg_type , nam_trg_type , dtype_int64 , sizeof(SINT64) , 0 , NULL , true , ODS_13_0) + FIELD(fld_obj_type , nam_obj_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_mechanism , nam_mechanism , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_f_descr , nam_desc , dtype_blob , BLOB_SIZE , isc_blob_format , NULL , true , ODS_13_0) + FIELD(fld_fun_type , nam_fun_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_trans_id , nam_trans_id , dtype_int64 , sizeof(SINT64) , 0 , NULL , true , ODS_13_0) + FIELD(fld_trans_state , nam_trans_state , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_time , nam_time , dtype_timestamp, TIMESTAMP_SIZE , 0 , NULL , true , ODS_13_0) + FIELD(fld_trans_desc , nam_trans_desc , dtype_blob , BLOB_SIZE , isc_blob_tra , NULL , true , ODS_13_0) + FIELD(fld_msg , nam_msg , dtype_varying , 1023 , 0 , NULL , true , ODS_13_0) + FIELD(fld_msg_num , nam_msg_num , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_user , nam_user , dtype_text , USERNAME_LENGTH , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_privilege , nam_privilege , dtype_text , 6 , 0 , NULL , true , ODS_13_0) + FIELD(fld_ext_desc , nam_ext_desc , dtype_blob , BLOB_SIZE , isc_blob_extfile , NULL , true , ODS_13_0) + FIELD(fld_shad_num , nam_shad_num , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_gen_name , nam_gen_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_gen_id , nam_gen_id , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_bound , nam_bound , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_dim , nam_dim , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_statistics , nam_statistics , dtype_double , sizeof(double) , 0 , NULL , true , ODS_13_0) + FIELD(fld_null_flag , nam_null_flag , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_con_name , nam_con_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_con_type , nam_con_type , dtype_text , 11 , 0 , NULL , true , ODS_13_0) + FIELD(fld_defer , nam_defer , dtype_text , 3 , 0 , dflt_no , true , ODS_13_0) + FIELD(fld_match , nam_match , dtype_text , 7 , 0 , dflt_full , true , ODS_13_0) + FIELD(fld_rule , nam_rule , dtype_text , 11 , 0 , dflt_restrict, true , ODS_13_0) + FIELD(fld_file_partitions, nam_file_partitions, dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_prc_blr , nam_prc_blr , dtype_blob , BLOB_SIZE , isc_blob_blr , NULL , true , ODS_13_0) + FIELD(fld_prc_id , nam_prc_id , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_prc_prm , nam_prc_prm , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_prc_name , nam_prc_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_prm_name , nam_prm_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_prm_number , nam_prm_number , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_prm_type , nam_prm_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + + FIELD(fld_charset_name , nam_charset_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_charset_id , nam_charset_id , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_collate_name , nam_collate_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_collate_id , nam_collate_id , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_num_chars , nam_num_chars , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_xcp_name , nam_xcp_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_xcp_number , nam_xcp_number , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_file_p_offset , nam_file_p_offset , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_f_precision , nam_f_precision , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + + FIELD(fld_backup_id , nam_backup_id , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_backup_level , nam_backup_level , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_guid , nam_guid , dtype_text , 38 , 0 , NULL , true , ODS_13_0) + FIELD(fld_scn , nam_scn , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + + FIELD(fld_specific_attr , nam_specific_attr , dtype_blob , BLOB_SIZE , isc_blob_text , NULL , true , ODS_13_0) + FIELD(fld_plugin_name , nam_plugin , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + + FIELD(fld_r_type , nam_r_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_prc_type , nam_prc_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + + FIELD(fld_att_id , nam_att_id , dtype_int64 , sizeof(SINT64) , 0 , NULL , true , ODS_13_0) + FIELD(fld_stmt_id , nam_stmt_id , dtype_int64 , sizeof(SINT64) , 0 , NULL , true , ODS_13_0) + FIELD(fld_call_id , nam_call_id , dtype_int64 , sizeof(SINT64) , 0 , NULL , true , ODS_13_0) + FIELD(fld_stat_id , nam_stat_id , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + + FIELD(fld_pid , nam_pid , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_state , nam_state , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_ods_number , nam_ods_number , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_page_size , nam_page_size , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_page_bufs , nam_page_bufs , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_shut_mode , nam_shut_mode , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_sql_dialect , nam_sql_dialect , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_sweep_int , nam_sweep_int , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_counter , nam_counter , dtype_int64 , sizeof(SINT64) , 0 , NULL , true , ODS_13_0) + + FIELD(fld_remote_proto , nam_remote_proto , dtype_varying , 10 , dsc_text_type_ascii , NULL , true , ODS_13_0) + FIELD(fld_remote_addr , nam_remote_addr , dtype_varying , 255 , dsc_text_type_ascii , NULL , true , ODS_13_0) + + FIELD(fld_iso_mode , nam_iso_mode , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_lock_timeout , nam_lock_timeout , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_backup_state , nam_backup_state , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_stat_group , nam_stat_group , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + + FIELD(fld_debug_info , nam_debug_info , dtype_blob , BLOB_SIZE , isc_blob_debug_info , NULL , true , ODS_13_0) + FIELD(fld_prm_mechanism , nam_prm_mechanism , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_src_info , nam_src_info , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + + FIELD(fld_ctx_var_name , nam_ctx_var_name , dtype_varying , 80 , 0 , NULL , true , ODS_13_0) + FIELD(fld_ctx_var_value , nam_ctx_var_value , dtype_varying , MAX_VARY_COLUMN_SIZE , 0 , NULL , true , ODS_13_0) + + FIELD(fld_engine_name , nam_engine_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + + FIELD(fld_pkg_name , nam_pkg_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + + FIELD(fld_fun_id , nam_fun_id , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_fun_blr , nam_fun_blr , dtype_blob , BLOB_SIZE , isc_blob_blr , NULL , true , ODS_13_0) + FIELD(fld_arg_name , nam_arg_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_arg_mechanism , nam_arg_mechanism , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + + FIELD(fld_identity_type , nam_identity_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_bool , nam_bool , dtype_boolean , 1 , 0 , NULL , true , ODS_13_0) + + FIELD(fld_user_name , nam_user_name , dtype_varying , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_attr_key , nam_sec_attr_key , dtype_varying , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_attr_value , nam_sec_attr_value, dtype_varying , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_name_part , nam_name_part , dtype_varying , 32 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_client_ver , nam_client_ver , dtype_varying , 255 , dsc_text_type_ascii , NULL , true , ODS_13_0) + FIELD(fld_remote_ver , nam_remote_ver , dtype_varying , 255 , dsc_text_type_ascii , NULL , true , ODS_13_0) + FIELD(fld_host_name , nam_host_name , dtype_varying , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_os_user , nam_os_user , dtype_varying , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_gen_val , nam_gen_val , dtype_int64 , sizeof(SINT64) , 0 , NULL , true , ODS_13_0) + FIELD(fld_auth_method , nam_auth_method , dtype_varying , 255 , dsc_text_type_ascii , NULL , true , ODS_13_0) + + FIELD(fld_linger , nam_linger , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_sec_db , nam_mon_secdb , dtype_text , 7 , dsc_text_type_ascii , NULL , false , ODS_13_0) + + FIELD(fld_map_name , nam_map_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , false , ODS_13_0) + FIELD(fld_map_using , nam_map_using , dtype_text , 1 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , false , ODS_13_0) + FIELD(fld_map_db , nam_map_db , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_map_from_type , nam_map_from_type , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , false , ODS_13_0) + FIELD(fld_map_from , nam_map_from , dtype_text , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_map_to , nam_map_to , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + + FIELD(fld_gen_increment , nam_gen_increment , dtype_long , sizeof(SLONG) , 0 , NULL , false , ODS_13_0) + FIELD(fld_plan , nam_plan , dtype_blob , BLOB_SIZE , isc_blob_text , NULL , true , ODS_13_0) + + FIELD(fld_system_privileges, nam_system_privileges, dtype_text, 8 , dsc_text_type_fixed , dflt_no_privs, true , ODS_13_0) + FIELD(fld_b_sql_security, nam_sql_security , dtype_boolean , 1 , 0 , NULL , true , ODS_13_0) + + FIELD(fld_idle_timeout , nam_idle_timeout , dtype_long , sizeof(SLONG) , 0 , NULL , false , ODS_13_0) + FIELD(fld_idle_timer , nam_idle_timer , dtype_timestamp_tz, TIMESTAMP_TZ_SIZE , 0 , NULL , true , ODS_13_0) + FIELD(fld_stmt_timeout , nam_stmt_timeout , dtype_long , sizeof(SLONG) , 0 , NULL , false , ODS_13_0) + FIELD(fld_stmt_timer , nam_stmt_timer , dtype_timestamp_tz, TIMESTAMP_TZ_SIZE , 0 , NULL , true , ODS_13_0) + + FIELD(fld_tz_id , nam_tz_id , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_tz_name , nam_tz_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_tz_offset , nam_tz_offset , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_timestamp_tz , nam_timestamp_tz , dtype_timestamp_tz, TIMESTAMP_TZ_SIZE , 0 , NULL , true , ODS_13_0) + + FIELD(fld_tz_db_version , nam_tz_db_version , dtype_varying , 10 , dsc_text_type_ascii , NULL , true , ODS_13_0) + + FIELD(fld_crypt_state , nam_crypt_state , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + FIELD(fld_remote_crypt , nam_wire_crypt_plugin, dtype_varying, MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + + FIELD(fld_pub_name , nam_pub_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , false , ODS_13_0) + FIELD(fld_file_id , nam_file_id , dtype_varying , 255 , dsc_text_type_ascii , NULL , false , ODS_13_0) + + FIELD(fld_cfg_id , nam_cfg_id , dtype_long , sizeof(SLONG) , 0 , NULL , false , ODS_13_0) + FIELD(fld_cfg_name , nam_cfg_name , dtype_varying , MAX_CONFIG_NAME_LEN , dsc_text_type_ascii , NULL , false , ODS_13_0) + FIELD(fld_cfg_value , nam_cfg_value , dtype_varying , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_cfg_is_set , nam_cfg_is_set , dtype_boolean , 1 , 0 , NULL , false , ODS_13_0) + + FIELD(fld_repl_mode , nam_repl_mode , dtype_short , sizeof(SSHORT) , 0 , NULL , true , ODS_13_0) + + FIELD(fld_keyword_name , nam_keyword_name , dtype_varying , METADATA_IDENTIFIER_CHAR_LEN, dsc_text_type_ascii , NULL , false , ODS_13_1) + FIELD(fld_keyword_reserved, nam_keyword_reserved, dtype_boolean, 1 , 0 , NULL , false , ODS_13_1) + + FIELD(fld_short_description, nam_short_description, dtype_varying, 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata, NULL , true , ODS_13_1) + FIELD(fld_seconds_interval, nam_seconds_interval, dtype_long, sizeof(SLONG) , 0 , NULL , true , ODS_13_1) + FIELD(fld_prof_ses_id , nam_prof_ses_id , dtype_int64 , sizeof(SINT64) , 0 , NULL , true , ODS_13_1) + + FIELD(fld_butil_handle , nam_butil_handle , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_1) + FIELD(fld_blob , nam_blob , dtype_blob , BLOB_SIZE , isc_blob_untyped , NULL , true , ODS_13_1) + FIELD(fld_varybinary_max, nam_varbinary_max , dtype_varying , MAX_VARY_COLUMN_SIZE , 0 , NULL , true , ODS_13_1) + FIELD(fld_integer , nam_integer , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_1) diff --git a/src/jrd/idx.h b/src/jrd/idx.h index 7960bd7e331..3fd62251440 100644 --- a/src/jrd/idx.h +++ b/src/jrd/idx.h @@ -38,6 +38,7 @@ struct ini_idx_t UCHAR ini_idx_relid; UCHAR ini_idx_flags; UCHAR ini_idx_segment_count; + USHORT ini_idx_ods; struct ini_idx_segment_t { UCHAR ini_idx_rfld_id; @@ -54,259 +55,259 @@ using Jrd::idx_string; using Jrd::idx_descending; using Jrd::idx_timestamp_tz; -#define INDEX(id, rel, unique, count) {(id), (UCHAR) (rel), (unique), (count), { +#define INDEX(id, rel, unique, count, ods) {(id), (UCHAR) (rel), (unique), (count), (ods), { #define SEGMENT(fld, type) {(fld), (type)} static const struct ini_idx_t indices[] = { // define index RDB$INDEX_0 for RDB$RELATIONS unique RDB$RELATION_NAME; - INDEX(0, rel_relations, idx_unique, 1) + INDEX(0, rel_relations, idx_unique, 1, ODS_13_0) SEGMENT(f_rel_name, idx_metadata) // relation name }}, // define index RDB$INDEX_1 for RDB$RELATIONS RDB$RELATION_ID; - INDEX(1, rel_relations, 0, 1) + INDEX(1, rel_relations, 0, 1, ODS_13_0) SEGMENT(f_rel_id, idx_numeric) // relation id }}, // define index RDB$INDEX_2 for RDB$FIELDS unique RDB$FIELD_NAME; - INDEX(2, rel_fields, idx_unique, 1) + INDEX(2, rel_fields, idx_unique, 1, ODS_13_0) SEGMENT(f_fld_name, idx_metadata) // field name }}, // define index RDB$INDEX_3 for RDB$RELATION_FIELDS RDB$FIELD_SOURCE; - INDEX(3, rel_rfr, 0, 1) + INDEX(3, rel_rfr, 0, 1, ODS_13_0) SEGMENT(f_rfr_sname, idx_metadata) // field source name }}, // define index RDB$INDEX_4 for RDB$RELATION_FIELDS RDB$RELATION_NAME; - INDEX(4, rel_rfr, 0, 1) + INDEX(4, rel_rfr, 0, 1, ODS_13_0) SEGMENT(f_rfr_rname, idx_metadata) // relation name in RFR }}, // define index RDB$INDEX_5 for RDB$INDICES unique RDB$INDEX_NAME; - INDEX(5, rel_indices, idx_unique, 1) + INDEX(5, rel_indices, idx_unique, 1, ODS_13_0) SEGMENT(f_idx_name, idx_metadata) // index name }}, // define index RDB$INDEX_6 for RDB$INDEX_SEGMENTS RDB$INDEX_NAME; - INDEX(6, rel_segments, 0, 1) + INDEX(6, rel_segments, 0, 1, ODS_13_0) SEGMENT(f_seg_name, idx_metadata) // index name in seg }}, // define index RDB$INDEX_7 for RDB$SECURITY_CLASSES unique RDB$SECURITY_CLASS; - INDEX(7, rel_classes, idx_unique, 1) + INDEX(7, rel_classes, idx_unique, 1, ODS_13_0) SEGMENT(f_cls_class, idx_metadata) // security class }}, // define index RDB$INDEX_8 for RDB$TRIGGERS unique RDB$TRIGGER_NAME; - INDEX(8, rel_triggers, idx_unique, 1) + INDEX(8, rel_triggers, idx_unique, 1, ODS_13_0) SEGMENT(f_trg_name, idx_metadata) // trigger name }}, // define index RDB$INDEX_9 for RDB$FUNCTIONS unique RDB$PACKAGE_NAME, RDB$FUNCTION_NAME; - INDEX(9, rel_funs, idx_unique, 2) + INDEX(9, rel_funs, idx_unique, 2, ODS_13_0) SEGMENT(f_fun_pkg_name, idx_metadata), // package name SEGMENT(f_fun_name, idx_metadata) // function name }}, // define index RDB$INDEX_10 for RDB$FUNCTION_ARGUMENTS RDB$PACKAGE_NAME, RDB$FUNCTION_NAME; - INDEX(10, rel_args, 0, 2) + INDEX(10, rel_args, 0, 2, ODS_13_0) SEGMENT(f_arg_pkg_name, idx_metadata), // package name SEGMENT(f_arg_fun_name, idx_metadata) // function name }}, // define index RDB$INDEX_11 for RDB$GENERATORS unique RDB$GENERATOR_NAME; - INDEX(11, rel_gens, idx_unique, 1) + INDEX(11, rel_gens, idx_unique, 1, ODS_13_0) SEGMENT(f_gen_name, idx_metadata) // Generator name }}, // define index RDB$INDEX_12 for RDB$RELATION_CONSTRAINTS unique RDB$CONSTRAINT_NAME; - INDEX(12, rel_rcon, idx_unique, 1) + INDEX(12, rel_rcon, idx_unique, 1, ODS_13_0) SEGMENT(f_rcon_cname, idx_metadata) // constraint name }}, // define index RDB$INDEX_13 for RDB$REF_CONSTRAINTS unique RDB$CONSTRAINT_NAME; - INDEX(13, rel_refc, idx_unique, 1) + INDEX(13, rel_refc, idx_unique, 1, ODS_13_0) SEGMENT(f_refc_cname, idx_metadata) // constraint name }}, // define index RDB$INDEX_14 for RDB$CHECK_CONSTRAINTS RDB$CONSTRAINT_NAME; - INDEX(14, rel_ccon, 0, 1) + INDEX(14, rel_ccon, 0, 1, ODS_13_0) SEGMENT(f_ccon_cname, idx_metadata) // constraint name }}, // define index RDB$INDEX_15 for RDB$RELATION_FIELDS unique RDB$FIELD_NAME, RDB$RELATION_NAME; - INDEX(15, rel_rfr, idx_unique, 2) + INDEX(15, rel_rfr, idx_unique, 2, ODS_13_0) SEGMENT(f_rfr_fname, idx_metadata), // field name SEGMENT(f_rfr_rname, idx_metadata) // relation name }}, // define index RDB$INDEX_16 for RDB$FORMATS RDB$RELATION_ID, RDB$FORMAT; - INDEX(16, rel_formats, 0, 2) + INDEX(16, rel_formats, 0, 2, ODS_13_0) SEGMENT(f_fmt_rid, idx_numeric), // relation id SEGMENT(f_fmt_format, idx_numeric) // format id }}, // define index RDB$INDEX_17 for RDB$FILTERS RDB$INPUT_SUB_TYPE, RDB$OUTPUT_SUB_TYPE; - INDEX(17, rel_filters, idx_unique, 2) + INDEX(17, rel_filters, idx_unique, 2, ODS_13_0) SEGMENT(f_flt_input, idx_numeric), // input subtype SEGMENT(f_flt_output, idx_numeric) // output subtype }}, // define index RDB$INDEX_18 for RDB$PROCEDURE_PARAMETERS unique RDB$PACKAGE_NAME, // RDB$PROCEDURE_NAME, RDB$PARAMETER_NAME; - INDEX(18, rel_prc_prms, idx_unique, 3) + INDEX(18, rel_prc_prms, idx_unique, 3, ODS_13_0) SEGMENT(f_prm_pkg_name, idx_metadata), // package name SEGMENT(f_prm_procedure, idx_metadata), // procedure name SEGMENT(f_prm_name, idx_metadata) // parameter name }}, // define index RDB$INDEX_19 for RDB$CHARACTER_SETS unique RDB$CHARACTER_SET_NAME; - INDEX(19, rel_charsets, idx_unique, 1) + INDEX(19, rel_charsets, idx_unique, 1, ODS_13_0) SEGMENT(f_cs_cs_name, idx_metadata) // character set name }}, // define index RDB$INDEX_20 for RDB$COLLATIONS unique RDB$COLLATION_NAME; - INDEX(20, rel_collations, idx_unique, 1) + INDEX(20, rel_collations, idx_unique, 1, ODS_13_0) SEGMENT(f_coll_name, idx_metadata) // collation name }}, // define index RDB$INDEX_21 for RDB$PROCEDURES unique RDB$PACKAGE_NAME, RDB$PROCEDURE_NAME; - INDEX(21, rel_procedures, idx_unique, 2) + INDEX(21, rel_procedures, idx_unique, 2, ODS_13_0) SEGMENT(f_prc_pkg_name, idx_metadata), // package name SEGMENT(f_prc_name, idx_metadata) // procedure name }}, // define index RDB$INDEX_22 for RDB$PROCEDURES unique RDB$PROCEDURE_ID; - INDEX(22, rel_procedures, idx_unique, 1) + INDEX(22, rel_procedures, idx_unique, 1, ODS_13_0) SEGMENT(f_prc_id, idx_numeric) // procedure id }}, // define index RDB$INDEX_23 for RDB$EXCEPTIONS unique RDB$EXCEPTION_NAME; - INDEX(23, rel_exceptions, idx_unique, 1) + INDEX(23, rel_exceptions, idx_unique, 1, ODS_13_0) SEGMENT(f_xcp_name, idx_metadata) // exception name }}, // define index RDB$INDEX_24 for RDB$EXCEPTIONS unique RDB$EXCEPTION_NUMBER; - INDEX(24, rel_exceptions, idx_unique, 1) + INDEX(24, rel_exceptions, idx_unique, 1, ODS_13_0) SEGMENT(f_xcp_number, idx_numeric) // exception number }}, // define index RDB$INDEX_25 for RDB$CHARACTER_SETS unique RDB$CHARACTER_SET_ID; - INDEX(25, rel_charsets, idx_unique, 1) + INDEX(25, rel_charsets, idx_unique, 1, ODS_13_0) SEGMENT(f_cs_id, idx_numeric) // character set id }}, // define index RDB$INDEX_26 for RDB$COLLATIONS unique RDB$COLLATION_ID, RDB$CHARACTER_SET_ID; - INDEX(26, rel_collations, idx_unique, 2) + INDEX(26, rel_collations, idx_unique, 2, ODS_13_0) SEGMENT(f_coll_id, idx_numeric), // collation id SEGMENT(f_coll_cs_id, idx_numeric) // character set id }}, // define index RDB$INDEX_27 for RDB$DEPENDENCIES RDB$DEPENDENT_NAME, RDB$DEPENDENT_TYPE; - INDEX(27, rel_dpds, 0, 2) + INDEX(27, rel_dpds, 0, 2, ODS_13_0) SEGMENT(f_dpd_name, idx_metadata), // dependent name SEGMENT(f_dpd_type, idx_numeric) // dependent type }}, // define index RDB$INDEX_28 for RDB$DEPENDENCIES RDB$DEPENDED_ON_NAME, RDB$DEPENDED_ON_TYPE, RDB$FIELD_NAME; - INDEX(28, rel_dpds, 0, 3) + INDEX(28, rel_dpds, 0, 3, ODS_13_0) SEGMENT(f_dpd_o_name, idx_metadata), // dependent on name SEGMENT(f_dpd_o_type, idx_numeric), // dependent on type SEGMENT(f_dpd_f_name, idx_metadata) // field name }}, // define index RDB$INDEX_29 for RDB$USER_PRIVILEGES RDB$RELATION_NAME; - INDEX(29, rel_priv, 0, 1) + INDEX(29, rel_priv, 0, 1, ODS_13_0) SEGMENT(f_prv_rname, idx_metadata) // relation name }}, // define index RDB$INDEX_30 for RDB$USER_PRIVILEGES RDB$USER; - INDEX(30, rel_priv, 0, 1) + INDEX(30, rel_priv, 0, 1, ODS_13_0) SEGMENT(f_prv_user, idx_metadata) // granted user }}, // define index RDB$INDEX_31 for RDB$INDICES RDB$RELATION_NAME; - INDEX(31, rel_indices, 0, 1) + INDEX(31, rel_indices, 0, 1, ODS_13_0) SEGMENT(f_idx_relation, idx_metadata) // indexed relation }}, // define index RDB$INDEX_32 for RDB$TRANSACTIONS unique RDB$TRANSACTION_ID; - INDEX(32, rel_trans, idx_unique, 1) + INDEX(32, rel_trans, idx_unique, 1, ODS_13_0) SEGMENT(f_trn_id, idx_numeric) // transaction id }}, // define index RDB$INDEX_33 for RDB$VIEW_RELATIONS RDB$VIEW_NAME; - INDEX(33, rel_vrel, 0, 1) + INDEX(33, rel_vrel, 0, 1, ODS_13_0) SEGMENT(f_vrl_vname, idx_metadata) // view name }}, // define index RDB$INDEX_34 for RDB$VIEW_RELATIONS RDB$RELATION_NAME; - INDEX(34, rel_vrel, 0, 1) + INDEX(34, rel_vrel, 0, 1, ODS_13_0) SEGMENT(f_vrl_rname, idx_metadata) // base relation name }}, // define index RDB$INDEX_35 for RDB$TRIGGER_MESSAGES RDB$TRIGGER_NAME; - INDEX(35, rel_msgs, 0, 1) + INDEX(35, rel_msgs, 0, 1, ODS_13_0) SEGMENT(f_msg_trigger, idx_metadata) // trigger name }}, // define index RDB$INDEX_36 for RDB$FIELD_DIMENSIONS RDB$FIELD_NAME; - INDEX(36, rel_dims, 0, 1) + INDEX(36, rel_dims, 0, 1, ODS_13_0) SEGMENT(f_dims_fname, idx_metadata) // array name }}, // define index RDB$INDEX_37 for RDB$TYPES RDB$TYPE_NAME; - INDEX(37, rel_types, 0, 1) + INDEX(37, rel_types, 0, 1, ODS_13_0) SEGMENT(f_typ_name, idx_metadata) // type name }}, // define index RDB$INDEX_38 for RDB$TRIGGERS RDB$RELATION_NAME; - INDEX(38, rel_triggers, 0, 1) + INDEX(38, rel_triggers, 0, 1, ODS_13_0) SEGMENT(f_trg_rname, idx_metadata) // triggered relation }}, // define index RDB$INDEX_39 for RDB$ROLES unique RDB$ROLE_NAME; - INDEX(39, rel_roles, idx_unique, 1) + INDEX(39, rel_roles, idx_unique, 1, ODS_13_0) SEGMENT(f_rol_name, idx_metadata) // role name }}, // define index RDB$INDEX_40 for RDB$CHECK_CONSTRAINTS RDB$TRIGGER_NAME; - INDEX(40, rel_ccon, 0, 1) + INDEX(40, rel_ccon, 0, 1, ODS_13_0) SEGMENT(f_ccon_tname, idx_metadata) // trigger name }}, // define index RDB$INDEX_41 for RDB$INDICES RDB$FOREIGN_KEY; - INDEX(41, rel_indices, 0, 1) + INDEX(41, rel_indices, 0, 1, ODS_13_0) SEGMENT(f_idx_foreign, idx_metadata) // foreign key name }}, // define index RDB$INDEX_42 for RDB$RELATION_CONSTRAINTS RDB$RELATION_NAME, RDB$CONSTRAINT_TYPE; - INDEX(42, rel_rcon, 0, 2) + INDEX(42, rel_rcon, 0, 2, ODS_13_0) SEGMENT(f_rcon_rname, idx_metadata), // relation name SEGMENT(f_rcon_ctype, idx_metadata) // constraint type }}, // define index RDB$INDEX_43 for RDB$RELATION_CONSTRAINTS RDB$INDEX_NAME; - INDEX(43, rel_rcon, 0, 1) + INDEX(43, rel_rcon, 0, 1, ODS_13_0) SEGMENT(f_rcon_iname, idx_metadata), // index name }}, // define index RDB$INDEX_44 for RDB$BACKUP_HISTORY RDB$LEVEL, RDB$BACKUP_ID; - INDEX(44, rel_backup_history, idx_unique | idx_descending, 2) + INDEX(44, rel_backup_history, idx_unique | idx_descending, 2, ODS_13_0) SEGMENT(f_backup_level, idx_numeric), // backup level SEGMENT(f_backup_id, idx_numeric) // backup id }}, // define index RDB$INDEX_45 for RDB$FILTERS RDB$FUNCTION_NAME; - INDEX(45, rel_filters, idx_unique, 1) + INDEX(45, rel_filters, idx_unique, 1, ODS_13_0) SEGMENT(f_flt_name, idx_metadata) // function name }}, // define index RDB$INDEX_46 for RDB$GENERATORS unique RDB$GENERATOR_ID; - INDEX(46, rel_gens, idx_unique, 1) + INDEX(46, rel_gens, idx_unique, 1, ODS_13_0) SEGMENT(f_gen_id, idx_numeric) // generator id }}, // define index RDB$INDEX_47 for RDB$PACKAGES unique RDB$PACKAGE_NAME; - INDEX(47, rel_packages, idx_unique, 1) + INDEX(47, rel_packages, idx_unique, 1, ODS_13_0) SEGMENT(f_pkg_name, idx_metadata) // package name }}, // define index RDB$INDEX_48 for RDB$PROCEDURE_PARAMETERS RDB$FIELD_SOURCE; - INDEX(48, rel_prc_prms, 0, 1) + INDEX(48, rel_prc_prms, 0, 1, ODS_13_0) SEGMENT(f_prm_sname, idx_metadata) // field source name }}, // define index RDB$INDEX_49 for RDB$FUNCTION_ARGUMENTS RDB$FIELD_SOURCE; - INDEX(49, rel_args, 0, 1) + INDEX(49, rel_args, 0, 1, ODS_13_0) SEGMENT(f_arg_sname, idx_metadata) // field source name }}, // define index RDB$INDEX_50 for RDB$PROCEDURE_PARAMETERS RDB$RELATION_NAME, RDB$FIELD_NAME; - INDEX(50, rel_prc_prms, 0, 2) + INDEX(50, rel_prc_prms, 0, 2, ODS_13_0) SEGMENT(f_prm_rname, idx_metadata), // relation name SEGMENT(f_prm_fname, idx_metadata) // field name }}, // define index RDB$INDEX_51 for RDB$FUNCTION_ARGUMENTS RDB$RELATION_NAME, RDB$FIELD_NAME; - INDEX(51, rel_args, 0, 2) + INDEX(51, rel_args, 0, 2, ODS_13_0) SEGMENT(f_arg_rname, idx_metadata), // relation name SEGMENT(f_arg_fname, idx_metadata) // field name }}, // define index RDB$INDEX_52 for RDB$AUTH_MAPPING RDB$MAP_NAME; - INDEX(52, rel_auth_mapping, 0, 1) + INDEX(52, rel_auth_mapping, 0, 1, ODS_13_0) SEGMENT(f_map_name, idx_metadata) // mapping name }}, // define index RDB$INDEX_53 for RDB$FUNCTIONS unique RDB$FUNCTION_ID; - INDEX(53, rel_funs, idx_unique, 1) + INDEX(53, rel_funs, idx_unique, 1, ODS_13_0) SEGMENT(f_fun_id, idx_numeric) // function id }}, // define index RDB$INDEX_54 for RDB$BACKUP_HISTORY RDB$GUID; - INDEX(54, rel_backup_history, idx_unique, 1) + INDEX(54, rel_backup_history, idx_unique, 1, ODS_13_0) SEGMENT(f_backup_guid, idx_string) // backup guid }}, // define index RDB$INDEX_55 for RDB$PUBLICATIONS unique RDB$PUBLICATION_NAME; - INDEX(55, rel_pubs, idx_unique, 1) + INDEX(55, rel_pubs, idx_unique, 1, ODS_13_0) SEGMENT(f_pub_name, idx_string) // publication name }}, // define index RDB$INDEX_56 for RDB$PUBLICATION_TABLES unique RDB$TABLE_NAME, RDB$PUBLICATION_NAME; - INDEX(56, rel_pub_tables, idx_unique, 2) + INDEX(56, rel_pub_tables, idx_unique, 2, ODS_13_0) SEGMENT(f_pubtab_tab_name, idx_string), // table name SEGMENT(f_pubtab_pub_name, idx_string) // publication name }}, // define index RDB$INDEX_57 for RDB$BACKUP_HISTORY RDB$TIMESTAMP; - INDEX(57, rel_backup_history, idx_descending, 1) + INDEX(57, rel_backup_history, idx_descending, 1, ODS_13_1) SEGMENT(f_backup_time, idx_timestamp_tz) // backup timestamp }}, }; diff --git a/src/jrd/ini.epp b/src/jrd/ini.epp index c78fc409a5c..24ccf775681 100644 --- a/src/jrd/ini.epp +++ b/src/jrd/ini.epp @@ -51,6 +51,7 @@ #include "../jrd/ini_proto.h" #include "../jrd/jrd_proto.h" #include "../jrd/met_proto.h" +#include "../jrd/tra_proto.h" #include "../jrd/obj.h" #include "../jrd/acl.h" #include "../jrd/dyn.h" @@ -66,599 +67,900 @@ 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; +namespace +{ + template void PAD(const char* string, char (&field)[N]) + { + jrd_vtof(string, field, sizeof(field)); + } + template void PAD(const MetaName& name, char (&field)[N]) + { + jrd_vtof(name.c_str(), field, sizeof(field)); + } -static void add_index_set(thread_db*); -static void add_security_to_sys_obj(thread_db*, AutoRequest&, AutoRequest&, AutoRequest&, - const MetaName&, USHORT, const MetaName&, USHORT = 0, const UCHAR* = NULL); -static void add_security_class(thread_db* tdbb, AutoRequest&, const MetaName& class_name, - USHORT acl_length, const UCHAR* acl); -static void add_security_to_sys_rel(thread_db*, AutoRequest&, AutoRequest&, AutoRequest&, const MetaName&, - const TEXT*, const USHORT, const UCHAR*); -static void store_default_pub(thread_db*, const MetaName&); -static void store_generator(thread_db*, const gen*, AutoRequest&, const MetaName&); -static void store_global_field(thread_db*, const gfld*, AutoRequest&, const MetaName&); -static void store_intlnames(thread_db*, const MetaName&); -static void store_message(thread_db*, const trigger_msg*, AutoRequest&); -static void store_relation_field(thread_db*, const int*, const int*, int, AutoRequest&); -static void store_packages(thread_db* tdbb, const MetaName& owner); -static void store_trigger(thread_db*, const jrd_trg*, AutoRequest&); -static void store_admin_grant(thread_db*, const char* grantee, USHORT grantee_type, - const char* object, USHORT object_type, const char* prvl, USHORT option = 0, bool dflt = false); -static void store_admin_role_grant(thread_db*, const char*); -static void store_admin_role(thread_db*, const MetaName&, MetaName, UserId::Privileges*); -static bool get_charset_by_text_type(SSHORT& charSet, const USHORT sub_type); - -// 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_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_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_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_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 char* owner, const char* 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(); - Jrd::Attachment* attachment = tdbb->getAttachment(); - Database* const dbb = tdbb->getDatabase(); + // 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 - fb_assert(owner && owner[0]); + 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_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_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 + + 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_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_24", 2, "integ_index_seg_mod", ODS_11_0 }, + { "RDB$TRIGGER_36", 1, "integ_index_seg_mod", ODS_11_0 }, + { 0, 0, 0, 0 } + }; + + bool getCharsetByTextType(SSHORT& charSet, const USHORT subType) + { + switch (subType) + { + case dsc_text_type_metadata: + charSet = CS_METADATA; + break; - // Uppercase owner name - MetaName ownerName(owner); + case dsc_text_type_ascii: + charSet = CS_ASCII; + break; - // Uppercase charset name - MetaName rdbCharSetName(charset && charset[0] ? charset : DEFAULT_DB_CHARACTER_SET_NAME); + case dsc_text_type_fixed: + charSet = CS_BINARY; + break; - const int* fld; + default: + return false; + } - // Make sure relations exist already + return true; + } - for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) + SLONG lookupGenerator(const MetaName& name) { - if (relfld[RFLD_R_TYPE] == rel_persistent) + for (const gen* generator = generators; generator->gen_name; generator++) { - DPM_create_relation(tdbb, MET_relation(tdbb, relfld[RFLD_R_ID])); + if (name == generator->gen_name) + return generator->gen_id; } - for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) - ; + fb_assert(false); + return -1; } - jrd_tra* transaction = attachment->getSysTransaction(); + void storeGrant(thread_db* tdbb, const char* user, USHORT user_type, + const char* object, USHORT object_type, const char* prvl) + { + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); - // Store RELATIONS and RELATION_FIELDS + AutoRequest handle; - SLONG rdbRelationId; - MetaName rdbRelationName; - SLONG rdbFieldId; - SLONG rdbSystemFlag = RDB_system; - SLONG rdbRelationType; + while (*prvl) + { + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + { + PAD(user, PRIV.RDB$USER); + PAD(object, PRIV.RDB$RELATION_NAME); + PRIV.RDB$FIELD_NAME.NULL = TRUE; + PRIV.RDB$PRIVILEGE[0] = *prvl++; + PRIV.RDB$PRIVILEGE[1] = 0; + PRIV.RDB$GRANT_OPTION = 0; + PRIV.RDB$USER_TYPE = user_type; + PRIV.RDB$OBJECT_TYPE = object_type; + PRIV.RDB$GRANTOR.NULL = TRUE; + } + END_STORE + } + } - PreparedStatement::Builder sql; - sql << "insert into rdb$relations (rdb$relation_id, rdb$relation_name, rdb$field_id," - << "rdb$format, rdb$system_flag, rdb$dbkey_length, rdb$owner_name, rdb$relation_type)" - << "values (" << rdbRelationId << ", " << rdbRelationName << ", " << rdbFieldId << ", 0," - << rdbSystemFlag << ", 8, " << ownerName << ", " << rdbRelationType << ")"; + class SecurityHelper + { + static const unsigned FB_MAX_ACL_SIZE = 4096; - AutoPreparedStatement ps(attachment->prepareStatement(tdbb, transaction, sql)); + public: + SecurityHelper(const MetaName& ownerName, AutoRequest& handle) + : userName(ownerName), reqAddSC(handle) + {} - AutoRequest handle1; - for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) - { - for (rdbFieldId = 0, fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) + const char* getOwnerName() const { - const int* pFld = fld; - const int* pRelFld = relfld; - store_relation_field(tdbb, pFld, pRelFld, rdbFieldId, handle1); - ++rdbFieldId; + return userName.c_str(); } - rdbRelationId = relfld[RFLD_R_ID]; - rdbRelationName = names[relfld[RFLD_R_NAME]]; - rdbRelationType = relfld[RFLD_R_TYPE]; - ps->execute(tdbb, transaction); - } + void addSecurityClass(thread_db* tdbb, const MetaName& className) + { + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); - handle1.reset(); + bid blobId; + attachment->storeBinaryBlob(tdbb, transaction, &blobId, ByteChunk(buffer, length)); - // Store global FIELDS + STORE(REQUEST_HANDLE reqAddSC TRANSACTION_HANDLE transaction) + CLS IN RDB$SECURITY_CLASSES + { + PAD(className, CLS.RDB$SECURITY_CLASS); + CLS.RDB$ACL = blobId; + } + END_STORE + } - for (const gfld* gfield = gfields; gfield->gfld_name; gfield++) - store_global_field(tdbb, gfield, handle1, ownerName); + protected: + UCHAR buffer[FB_MAX_ACL_SIZE]; + ULONG length = 0; - // Store DATABASE record + private: + const MetaName userName; + AutoRequest& reqAddSC; + }; + + class RelationSecurity : public SecurityHelper + { + public: + RelationSecurity(const MetaName& ownerName, AutoRequest& handle) + : SecurityHelper(ownerName, handle) + { + const size_t ownerNameLength = ownerName.length(); + fb_assert(ownerNameLength <= MAX_UCHAR); - sql = PreparedStatement::Builder(); - sql << "insert into rdb$database (rdb$relation_id, rdb$character_set_name) values (" - << rdbRelationId << ", " << rdbCharSetName << ")"; + const UCHAR REL_OWNER_ACL[] = + {ACL_priv_list, priv_control, priv_alter, priv_drop, + priv_select, priv_insert, priv_update, priv_delete, ACL_end}; - ps.reset(attachment->prepareStatement(tdbb, transaction, sql)); + const UCHAR REL_PUBLIC_ACL[] = + {ACL_priv_list, priv_select, ACL_end}; - rdbRelationId = USER_DEF_REL_INIT_ID; - ps->execute(tdbb, transaction); + fb_assert(sizeof(buffer) >= 8 + ownerNameLength + + sizeof(REL_OWNER_ACL) + sizeof(REL_PUBLIC_ACL)); - // Store default publication + UCHAR* acl = buffer; + *acl++ = ACL_version; + *acl++ = ACL_id_list; - store_default_pub(tdbb, ownerName); + *acl++ = id_person; - // Store system role + *acl++ = (UCHAR) ownerNameLength; + memcpy(acl, ownerName.c_str(), ownerNameLength); + acl += ownerNameLength; - store_admin_role(tdbb, ADMIN_ROLE, ownerName, NULL); + *acl++ = ACL_end; - // Store grants of admin role to valuable users + memcpy(acl, REL_OWNER_ACL, sizeof(REL_OWNER_ACL)); + acl += sizeof(REL_OWNER_ACL); - store_admin_role_grant(tdbb, DBA_USER_NAME); - if (ownerName != DBA_USER_NAME) - store_admin_role_grant(tdbb, ownerName.c_str()); + *acl++ = ACL_id_list; + *acl++ = ACL_end; - // Create indices for system relations + memcpy(acl, REL_PUBLIC_ACL, sizeof(REL_PUBLIC_ACL)); + acl += sizeof(REL_PUBLIC_ACL); - add_index_set(tdbb); + *acl++ = ACL_end; // Extra terminator to avoid scl.epp:walk_acl() missing the end - // Create parameter types + length = acl - buffer; + } - handle1.reset(); + void storeSecurityClass(thread_db* tdbb, MetaName& securityClass, MetaName& defaultClass) + { + securityClass.printf("%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, + DPM_gen_id(tdbb, lookupGenerator(SQL_SECCLASS_GENERATOR), false, 1)); - 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 + defaultClass.printf("%s%" SQUADFORMAT, DEFAULT_CLASS, + DPM_gen_id(tdbb, lookupGenerator(DEFAULT_CLASS), false, 1)); + + addSecurityClass(tdbb, securityClass); + addSecurityClass(tdbb, defaultClass); + } + + void storePrivileges(thread_db* tdbb, const char* relName) { - 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; + // Only the owner of the database has SELECT/INSERT/UPDATE/DELETE privileges + // on any system relations. Any other users only has SELECT privilege. + + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); + + const auto userName = getOwnerName(); + + for (int cnt = 0; cnt < 6; cnt++) + { + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + { + switch (cnt) + { + case 0: + strcpy(PRIV.RDB$USER, userName); + PRIV.RDB$PRIVILEGE[0] = 'S'; + PRIV.RDB$GRANT_OPTION = WITH_GRANT_OPTION; + break; + case 1: + strcpy(PRIV.RDB$USER, userName); + PRIV.RDB$PRIVILEGE[0] = 'I'; + PRIV.RDB$GRANT_OPTION = WITH_GRANT_OPTION; + break; + case 2: + strcpy(PRIV.RDB$USER, userName); + PRIV.RDB$PRIVILEGE[0] = 'U'; + PRIV.RDB$GRANT_OPTION = WITH_GRANT_OPTION; + break; + case 3: + strcpy(PRIV.RDB$USER, userName); + PRIV.RDB$PRIVILEGE[0] = 'D'; + PRIV.RDB$GRANT_OPTION = WITH_GRANT_OPTION; + break; + case 4: + strcpy(PRIV.RDB$USER, userName); + PRIV.RDB$PRIVILEGE[0] = 'R'; + PRIV.RDB$GRANT_OPTION = WITH_GRANT_OPTION; + break; + default: + strcpy(PRIV.RDB$USER, "PUBLIC"); + PRIV.RDB$PRIVILEGE[0] = 'S'; + PRIV.RDB$GRANT_OPTION = 0; + break; + } + + PRIV.RDB$PRIVILEGE[1] = 0; + PRIV.RDB$GRANTOR.NULL = TRUE; + strcpy(PRIV.RDB$RELATION_NAME, relName); + PRIV.RDB$FIELD_NAME.NULL = TRUE; + PRIV.RDB$USER_TYPE = obj_user; + PRIV.RDB$OBJECT_TYPE = obj_relation; + } + END_STORE + } } - 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; - } + private: + AutoRequest handle; + }; - for (const IntlManager::CharSetAliasDefinition* alias = IntlManager::defaultCharSetAliases; - alias->name; ++alias) + class NonRelationSecurity : public SecurityHelper { - // 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; - } + public: + NonRelationSecurity(const MetaName& ownerName, AutoRequest& handle, bool package) + : SecurityHelper(ownerName, handle) + { + const size_t ownerNameLength = ownerName.length(); + fb_assert(ownerNameLength <= MAX_UCHAR); - // Store symbols for international character sets & collations - store_intlnames(tdbb, ownerName); + const UCHAR privilege = package ? priv_execute : priv_usage; - // Create system generators + const UCHAR NON_REL_OWNER_ACL[] = + {ACL_priv_list, priv_control, priv_alter, priv_drop, privilege, ACL_end}; - handle1.reset(); + const UCHAR NON_REL_PUBLIC_ACL[] = + {ACL_priv_list, privilege, ACL_end}; - for (const gen* generator = generators; generator->gen_name; generator++) - store_generator(tdbb, generator, handle1, ownerName); + fb_assert(sizeof(buffer) >= 8 + ownerNameLength + + sizeof(NON_REL_OWNER_ACL) + sizeof(NON_REL_PUBLIC_ACL)); - // Adjust the value of the hidden generator RDB$GENERATORS - DPM_gen_id(tdbb, 0, true, FB_NELEM(generators) - 1); + UCHAR* acl = buffer; + *acl++ = ACL_version; + *acl++ = ACL_id_list; + *acl++ = id_person; - store_packages(tdbb, ownerName); + *acl++ = (UCHAR) ownerNameLength; + memcpy(acl, ownerName.c_str(), ownerNameLength); + acl += ownerNameLength; - const size_t ownerNameLength = ownerName.length(); - fb_assert(ownerNameLength <= MAX_UCHAR); + *acl++ = ACL_end; - // Add security for the non-relation system metadata objects + memcpy(acl, NON_REL_OWNER_ACL, sizeof(NON_REL_OWNER_ACL)); + acl += sizeof(NON_REL_OWNER_ACL); - const UCHAR NON_REL_OWNER_ACL[] = - {ACL_priv_list, priv_control, priv_alter, priv_drop, priv_usage, ACL_end}; + *acl++ = ACL_id_list; + *acl++ = ACL_end; - const UCHAR NON_REL_PUBLIC_USAGE_ACL[] = - {ACL_priv_list, priv_usage, ACL_end}; + memcpy(acl, NON_REL_PUBLIC_ACL, sizeof(NON_REL_PUBLIC_ACL)); + acl += sizeof(NON_REL_PUBLIC_ACL); - const UCHAR PKG_PUBLIC_EXECUTE_ACL[] = - {ACL_priv_list, priv_execute, ACL_end}; + *acl++ = ACL_end; // Extra terminator to avoid scl.epp:walk_acl() missing the end - UCHAR buffer[FB_MAX_ACL_SIZE]; - UCHAR* acl = buffer; - *acl++ = ACL_version; - *acl++ = ACL_id_list; - *acl++ = id_person; + length = acl - buffer; + } - *acl++ = (UCHAR) ownerNameLength; - memcpy(acl, ownerName.c_str(), ownerNameLength); - acl += ownerNameLength; + MetaName storeSecurityClass(thread_db* tdbb) + { + MetaName securityClass; + securityClass.printf("%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, + DPM_gen_id(tdbb, lookupGenerator(SQL_SECCLASS_GENERATOR), false, 1)); - *acl++ = ACL_end; + addSecurityClass(tdbb, securityClass); - memcpy(acl, NON_REL_OWNER_ACL, sizeof(NON_REL_OWNER_ACL)); - acl += sizeof(NON_REL_OWNER_ACL); + return securityClass; + } - *acl++ = ACL_id_list; - *acl++ = ACL_end; + void storePrivileges(thread_db* tdbb, const char* objName, ObjectType objType) + { + // Add security to system objects - UCHAR* aclPublicStart = acl; + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); - memcpy(acl, NON_REL_PUBLIC_USAGE_ACL, sizeof(NON_REL_PUBLIC_USAGE_ACL)); - acl += sizeof(NON_REL_PUBLIC_USAGE_ACL); - *acl++ = ACL_end; // Put an extra terminator to avoid scl.epp:walk_acl() missing the end. + const char* privileges = nullptr; - USHORT length = acl - buffer; + switch (objType) + { + case obj_field: + case obj_charset: + case obj_collation: + case obj_exception: + case obj_generator: + privileges = USAGE_PRIVILEGES; + break; - AutoRequest reqAddSC; + case obj_package_header: + privileges = EXEC_PRIVILEGES; + break; - { // scope - AutoRequest reqModObjSC, reqInsUserPriv; + default: + fb_assert(false); + } - for (const gfld* gfield = gfields; gfield->gfld_name; gfield++) - { - add_security_to_sys_obj(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, obj_field, - names[(USHORT)gfield->gfld_name], length, buffer); + fb_assert(privileges && privileges[0] && !privileges[1]); + + const auto userName = getOwnerName(); + fb_assert(userName && *userName); + fb_assert(objName); + + const char* users[] = {userName, "PUBLIC"}; + int grantOptions[] = {WITH_GRANT_OPTION, 0}; + + for (unsigned i = 0; i < FB_NELEM(users); i++) + { + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + { + PAD(users[i], PRIV.RDB$USER); + PAD(objName, PRIV.RDB$RELATION_NAME); + PRIV.RDB$PRIVILEGE[0] = *privileges; + PRIV.RDB$PRIVILEGE[1] = 0; + PRIV.RDB$GRANT_OPTION = grantOptions[i]; + PRIV.RDB$USER_TYPE = obj_user; + PRIV.RDB$OBJECT_TYPE = objType; + PRIV.RDB$GRANTOR.NULL = TRUE; + } + END_STORE + } } - reqModObjSC.reset(); - for (const gen* generator = generators; generator->gen_name; generator++) + private: + AutoRequest handle; + }; + + class RoleSecurity : public SecurityHelper + { + public: + RoleSecurity(const MetaName& ownerName, AutoRequest& handle) + : SecurityHelper(ownerName, handle) { - add_security_to_sys_obj(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, obj_generator, - generator->gen_name, length, buffer); + const size_t ownerNameLength = ownerName.length(); + fb_assert(ownerNameLength <= MAX_UCHAR); + + const UCHAR ROLE_OWNER_ACL[] = + {ACL_priv_list, priv_control, priv_alter, priv_drop, priv_usage, ACL_end}; + + fb_assert(sizeof(buffer) >= 6 + ownerNameLength + sizeof(ROLE_OWNER_ACL)); + + UCHAR* acl = buffer; + *acl++ = ACL_version; + *acl++ = ACL_id_list; + *acl++ = id_person; + + *acl++ = (UCHAR) ownerNameLength; + memcpy(acl, ownerName.c_str(), ownerNameLength); + acl += ownerNameLength; + + *acl++ = ACL_end; + + memcpy(acl, ROLE_OWNER_ACL, sizeof(ROLE_OWNER_ACL)); + acl += sizeof(ROLE_OWNER_ACL); + + *acl++ = ACL_end; // Extra terminator to avoid scl.epp:walk_acl() missing the end + + length = acl - buffer; } - reqModObjSC.reset(); - for (const IntlManager::CharSetDefinition* charset = IntlManager::defaultCharSets; - charset->name; - ++charset) + MetaName storeSecurityClass(thread_db* tdbb) { - add_security_to_sys_obj(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, obj_charset, - charset->name, length, buffer); + MetaName securityClass; + securityClass.printf("%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, + DPM_gen_id(tdbb, lookupGenerator(SQL_SECCLASS_GENERATOR), false, 1)); + + addSecurityClass(tdbb, securityClass); + + return securityClass; } - reqModObjSC.reset(); - for (const IntlManager::CollationDefinition* collation = IntlManager::defaultCollations; - collation->name; - ++collation) + void storePrivileges(thread_db* tdbb, const char* objName) { - add_security_to_sys_obj(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, obj_collation, - collation->name, length, buffer); + // Add security to system roles + + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); + + const auto userName = getOwnerName(); + fb_assert(userName && *userName); + fb_assert(objName); + + const char* users[] = {DBA_USER_NAME, userName}; + const unsigned usersCount = (MetaName(userName) != DBA_USER_NAME) ? 2 : 1; + + const char* privilege = "M"; + + for (unsigned i = 0; i < usersCount; i++) + { + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + { + PAD(users[i], PRIV.RDB$USER); + PAD(objName, PRIV.RDB$RELATION_NAME); + PRIV.RDB$PRIVILEGE[0] = *privilege; + PRIV.RDB$PRIVILEGE[1] = 0; + PRIV.RDB$GRANT_OPTION = WITH_ADMIN_OPTION; + PRIV.RDB$USER_TYPE = obj_user; + PRIV.RDB$OBJECT_TYPE = obj_sql_role; + PRIV.RDB$GRANTOR.NULL = TRUE; + + // Grant role as default + PRIV.RDB$FIELD_NAME[0] = 'D'; + PRIV.RDB$FIELD_NAME[1] = 0; + PRIV.RDB$FIELD_NAME.NULL = FALSE; + } + END_STORE + } } - reqModObjSC.reset(); - add_security_to_sys_obj(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, obj_sql_role, - ADMIN_ROLE, length, buffer); + private: + AutoRequest handle; + }; + + class DdlSecurity : public SecurityHelper + { + public: + DdlSecurity(const MetaName& ownerName, AutoRequest& handle) + : SecurityHelper(ownerName, handle) + { + const size_t ownerNameLength = ownerName.length(); + fb_assert(ownerNameLength <= MAX_UCHAR); + + const UCHAR DDL_OWNER_ACL[] = + {ACL_priv_list, priv_control, priv_alter, priv_drop, ACL_end}; + + const UCHAR DDL_PUBLIC_ACL[] = + {ACL_priv_list, ACL_end}; + + fb_assert(sizeof(buffer) >= 8 + ownerNameLength + + sizeof(DDL_OWNER_ACL) + sizeof(DDL_PUBLIC_ACL)); + + UCHAR* acl = buffer; + *acl++ = ACL_version; + *acl++ = ACL_id_list; + *acl++ = id_person; + + *acl++ = (UCHAR) ownerNameLength; + memcpy(acl, ownerName.c_str(), ownerNameLength); + acl += ownerNameLength; + + *acl++ = ACL_end; + + memcpy(acl, DDL_OWNER_ACL, sizeof(DDL_OWNER_ACL)); + acl += sizeof(DDL_OWNER_ACL); + + *acl++ = ACL_id_list; + *acl++ = ACL_end; + memcpy(acl, DDL_PUBLIC_ACL, sizeof(DDL_PUBLIC_ACL)); + acl += sizeof(DDL_PUBLIC_ACL); - // Must be last! - acl = aclPublicStart; - memcpy(acl, PKG_PUBLIC_EXECUTE_ACL, sizeof(PKG_PUBLIC_EXECUTE_ACL)); - acl += sizeof(PKG_PUBLIC_EXECUTE_ACL); - *acl++ = ACL_end; // Put an extra terminator to avoid scl.epp:walk_acl() missing the end. - length = acl - buffer; + *acl++ = ACL_end; // Extra terminator to avoid scl.epp:walk_acl() missing the end - reqModObjSC.reset(); - for (auto& systemPackage : SystemPackage::get()) + length = acl - buffer; + } + + void store(thread_db* tdbb) { - if (systemPackage.odsVersion > ENCODE_ODS(dbb->dbb_ods_version, dbb->dbb_minor_version)) - continue; + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); + + for (int obj = obj_database + 1; obj < obj_type_MAX; obj++) + { + if (isDdlObject(obj)) + addSecurityClass(tdbb, getSecurityClassName(obj)); + } + + MetaName securityClass; + securityClass.printf("%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, + DPM_gen_id(tdbb, lookupGenerator(SQL_SECCLASS_GENERATOR), false, 1)); + + addSecurityClass(tdbb, securityClass); - add_security_to_sys_obj(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, - obj_package_header, systemPackage.name, length, buffer); + FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + DB IN RDB$DATABASE + { + MODIFY DB USING + DB.RDB$SECURITY_CLASS.NULL = FALSE; + PAD(securityClass, DB.RDB$SECURITY_CLASS); + END_MODIFY + } + END_FOR } - } - // Add default DDL security + private: + AutoRequest handle; + }; - const UCHAR DDL_OWNER_ACL[] = - {ACL_priv_list, priv_control, priv_alter, priv_drop, ACL_end}; +}; // namespace - const UCHAR DDL_PUBLIC_ACL[] = - {ACL_priv_list, ACL_end}; +static void store_admin_role(thread_db*, const MetaName&, RoleSecurity&); +static void store_default_pub(thread_db*, const MetaName&); +static void store_generator(thread_db*, const gen*, AutoRequest&, NonRelationSecurity&); +static void store_global_field(thread_db*, const gfld*, AutoRequest&, NonRelationSecurity&); +static void store_indices(thread_db*, USHORT = 0); +static void store_intlnames(thread_db*, NonRelationSecurity&); +static void store_message(thread_db*, const trigger_msg*, AutoRequest&); +static void store_relation(thread_db*, int, const char*, int, int, AutoRequest&, RelationSecurity&); +static void store_relation_field(thread_db*, int, const char*, const char*, const char*, int, AutoRequest&); +static void store_packages(thread_db*, NonRelationSecurity&, USHORT = 0); +static void store_trigger(thread_db*, const jrd_trg*, AutoRequest&); - acl = buffer; - *acl++ = ACL_version; - *acl++ = ACL_id_list; - *acl++ = id_person; - *acl++ = (UCHAR) ownerNameLength; - memcpy(acl, ownerName.c_str(), ownerNameLength); - acl += ownerNameLength; +// +// Initialize system relations in the database. +// The full complement of metadata should be stored here. +// - *acl++ = ACL_end; +void INI_format(thread_db* tdbb, const string& charset) +{ + const auto dbb = tdbb->getDatabase(); + const auto attachment = tdbb->getAttachment(); - memcpy(acl, DDL_OWNER_ACL, sizeof(DDL_OWNER_ACL)); - acl += sizeof(DDL_OWNER_ACL); + const auto transaction = attachment->getSysTransaction(); + tdbb->setTransaction(transaction); - *acl++ = ACL_id_list; - *acl++ = ACL_end; - memcpy(acl, DDL_PUBLIC_ACL, sizeof(DDL_PUBLIC_ACL)); - acl += sizeof(DDL_PUBLIC_ACL); - *acl++ = ACL_end; // Put an extra terminator to avoid scl.epp:walk_acl() missing the end. + // Uppercase owner name + const auto ownerName = attachment->getUserName(); + fb_assert(ownerName.hasData()); - length = acl - buffer; + AutoRequest handle, reqAddSC; - for (int obj = obj_database + 1; obj < obj_type_MAX; obj++) - { - if (isDdlObject(obj)) - add_security_class(tdbb, reqAddSC, getSecurityClassName(obj), length, buffer); - } + { // scope for system relations + + RelationSecurity relSec(ownerName, reqAddSC); + + 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) + ; + } - { // scope - AutoRequest reqModObjSC, reqInsUserPriv; + // Store RELATIONS and RELATION_FIELDS - add_security_to_sys_obj(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, obj_database, - "", length, buffer); + AutoRequest handle2; + + for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) + { + int fieldId = 0; + + for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) + { + const gfld* gfield = &gfields[fld[RFLD_F_ID]]; + const auto relId = relfld[RFLD_R_ID]; + const auto relName = names[relfld[RFLD_R_NAME]]; + const auto fieldName = names[fld[RFLD_F_NAME]]; + const auto globalName = names[gfield->gfld_name]; + const auto updateFlag = fld[RFLD_F_UPDATE]; + + store_relation_field(tdbb, fieldId, relName, fieldName, globalName, + updateFlag, handle2); + ++fieldId; + } + + const auto relId = relfld[RFLD_R_ID]; + const auto relName = names[relfld[RFLD_R_NAME]]; + const auto relType = relfld[RFLD_R_TYPE]; + + store_relation(tdbb, relId, relName, fieldId, relType, handle, relSec); + } } - // Add security on system tables - const UCHAR REL_OWNER_ACL[] = - {ACL_priv_list, priv_control, priv_alter, priv_drop, - priv_select, priv_insert, priv_update, priv_delete, ACL_end}; + NonRelationSecurity nonRelSec(ownerName, reqAddSC, false); + + // Store global FIELDS + + handle.reset(); + + for (const gfld* gfield = gfields; gfield->gfld_name; gfield++) + store_global_field(tdbb, gfield, handle, nonRelSec); - const UCHAR REL_PUBLIC_ACL[] = - {ACL_priv_list, priv_select, ACL_end}; + // Store DATABASE record - acl = buffer; - *acl++ = ACL_version; - *acl++ = ACL_id_list; - *acl++ = id_person; + handle.reset(); - *acl++ = (UCHAR) ownerNameLength; - memcpy(acl, ownerName.c_str(), ownerNameLength); - acl += ownerNameLength; + // Uppercase charset name + MetaName charSetName(charset.hasData() ? charset : DEFAULT_DB_CHARACTER_SET_NAME); + + STORE(REQUEST_HANDLE handle) X IN RDB$DATABASE + { + X.RDB$RELATION_ID = (int) USER_DEF_REL_INIT_ID; + PAD(charSetName, X.RDB$CHARACTER_SET_NAME); + X.RDB$CHARACTER_SET_NAME.NULL = FALSE; + } + END_STORE - *acl++ = ACL_end; + // Create indices for system relations - memcpy(acl, REL_OWNER_ACL, sizeof(REL_OWNER_ACL)); - acl += sizeof(REL_OWNER_ACL); + store_indices(tdbb); - *acl++ = ACL_id_list; - *acl++ = ACL_end; - memcpy(acl, REL_PUBLIC_ACL, sizeof(REL_PUBLIC_ACL)); - acl += sizeof(REL_PUBLIC_ACL); - *acl++ = ACL_end; // Put an extra terminator to avoid scl.epp:walk_acl() missing the end. + // Create parameter types - length = acl - buffer; + handle.reset(); - { // scope - AutoRequest reqModObjSC, reqInsUserPriv; - for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) + 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 handle) X IN RDB$TYPES { - for (rdbFieldId = 0, fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) - ++rdbFieldId; + 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 + } - add_security_to_sys_rel(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, names[relfld[RFLD_R_NAME]], length, buffer); + 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 handle) 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 handle) 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; } - // store system-defined triggers + // Store symbols for international character sets & collations + + store_intlnames(tdbb, nonRelSec); - handle1.reset(); + // Create system generators + + handle.reset(); + + for (const gen* generator = generators; generator->gen_name; generator++) + store_generator(tdbb, generator, handle, nonRelSec); + + // Adjust the value of the hidden generator RDB$GENERATORS + DPM_gen_id(tdbb, 0, true, FB_NELEM(generators) - 1); + + // Store system-defined triggers + + handle.reset(); for (const jrd_trg* trigger = triggers; trigger->trg_relation; ++trigger) - store_trigger(tdbb, trigger, handle1); + store_trigger(tdbb, trigger, handle); - // store trigger messages to go with triggers + // Store trigger messages to go with triggers - handle1.reset(); + handle.reset(); for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message) - store_message(tdbb, message, handle1); + store_message(tdbb, message, handle); + + // Create system packages + + // Reset nonRelSec for package permissions, it should be its last usage in this function + new(&nonRelSec) NonRelationSecurity(ownerName, reqAddSC, true); + + store_packages(tdbb, nonRelSec); + + // Store default publication + + store_default_pub(tdbb, ownerName); + + // Store system role + + RoleSecurity roleSec(ownerName, reqAddSC); + store_admin_role(tdbb, ADMIN_ROLE, roleSec); - handle1.reset(); + // Add default DDL security + + DdlSecurity(ownerName, reqAddSC).store(tdbb); // Add additional grants MetaName buf; buf.printf("%d", USE_NBACKUP_UTILITY); - store_admin_grant(tdbb, buf.c_str(), obj_privilege, "RDB$BACKUP_HISTORY", obj_relation, "SIUDR"); - GRANT_privileges(tdbb, "RDB$BACKUP_HISTORY", obj_relation, attachment->getSysTransaction()); + storeGrant(tdbb, buf.c_str(), obj_privilege, "RDB$BACKUP_HISTORY", obj_relation, "SIUDR"); + GRANT_privileges(tdbb, "RDB$BACKUP_HISTORY", obj_relation, transaction); buf.printf("%d", CREATE_USER_TYPES); - store_admin_grant(tdbb, buf.c_str(), obj_privilege, "RDB$TYPES", obj_relation, "SIUDR"); - GRANT_privileges(tdbb, "RDB$TYPES", obj_relation, attachment->getSysTransaction()); + storeGrant(tdbb, buf.c_str(), obj_privilege, "RDB$TYPES", obj_relation, "SIUDR"); + GRANT_privileges(tdbb, "RDB$TYPES", obj_relation, transaction); buf.printf("%d", GRANT_REVOKE_ANY_DDL_RIGHT); - store_admin_grant(tdbb, buf.c_str(), obj_privilege, "RDB$DB_CREATORS", obj_relation, "SIUDR"); - GRANT_privileges(tdbb, "RDB$DB_CREATORS", obj_relation, attachment->getSysTransaction()); + storeGrant(tdbb, buf.c_str(), obj_privilege, "RDB$DB_CREATORS", obj_relation, "SIUDR"); + GRANT_privileges(tdbb, "RDB$DB_CREATORS", obj_relation, transaction); - DFW_perform_system_work(tdbb); + DFW_perform_work(tdbb, transaction); + + tdbb->setTransaction(nullptr); } -USHORT INI_get_trig_flags(const TEXT* trig_name) +// +// Return the trigger flags for a system trigger +// + +USHORT INI_get_trig_flags(const MetaName& triggerName) { -/********************************************* - * - * 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); - } + if (triggerName == trig->trg_name) + return trig->trg_flags; } - return (0); + return 0; } +// +// Initialize in-memory meta data +// + 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 auto dbb = tdbb->getDatabase(); + const auto attachment = tdbb->getAttachment(); - Jrd::Attachment* attachment = tdbb->getAttachment(); - MemoryPool* pool = attachment->att_pool; + const auto pool = attachment->att_pool; const int* fld; for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) @@ -667,13 +969,8 @@ void INI_init(thread_db* tdbb) relation->rel_flags |= REL_system; relation->rel_flags |= MET_get_rel_flags_from_TYPE(relfld[RFLD_R_TYPE]); 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. + // 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++) { @@ -684,130 +981,120 @@ void INI_init(thread_db* tdbb) } } - vec* fields = vec::newVector(*pool, n); - relation->rel_fields = fields; - vec::iterator itr = fields->begin(); - Format* format = Format::newFormat(*pool, n); - relation->rel_current_format = format; - vec* formats = vec::newVector(*pool, 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) + HalfStaticArray fieldNames; + for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) { - 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; - - if (desc->isText()) - { - if (!get_charset_by_text_type(desc->dsc_sub_type, gfield->gfld_sub_type)) - desc->dsc_sub_type = CS_NONE; - } - else - desc->dsc_sub_type = gfield->gfld_sub_type; + fieldNames.add(names[fld[RFLD_F_NAME]]); + } - if (desc->dsc_dtype == dtype_blob && desc->dsc_sub_type == isc_blob_text) - desc->dsc_scale = CS_METADATA; // blob charset + const auto fields = vec::newVector(*pool, fieldNames.getCount()); + relation->rel_fields = fields; - jrd_fld* field = FB_NEW_POOL(*pool) jrd_fld(*pool); - *itr = field; - field->fld_name = names[fld[RFLD_F_NAME]]; + ULONG fieldPos = 0; + for (auto iter = fields->begin(); iter != fields->end(); ++iter) + { + const auto field = FB_NEW_POOL(*pool) jrd_fld(*pool); + field->fld_name = fieldNames[fieldPos++]; + *iter = field; } - } -} + relation->rel_formats = vec::newVector(*pool, 1); -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 auto majorVersion = ODS_VERSION; + auto minorVersion = ODS_RELEASED; + unsigned formatNumber = 0, currentFormat = 0; - const USHORT major_version = dbb->dbb_ods_version; - const USHORT minor_version = dbb->dbb_minor_version; - vec* vector = tdbb->getAttachment()->att_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_version)) + while (minorVersion <= ODS_CURRENT) { - // 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; - delete relation; - (*vector)[id] = NULL; - fld = relfld + RFLD_RPT; - while (fld[RFLD_F_NAME]) + bool newFormat = false; + unsigned fieldCount = 0; + + for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) { - fld += RFLD_F_LENGTH; + if (fld[RFLD_F_ODS] > ENCODE_ODS(majorVersion, minorVersion)) + continue; + + if (!formatNumber || fld[RFLD_F_ODS] == ENCODE_ODS(majorVersion, minorVersion)) + newFormat = true; + + fieldCount++; } - } - 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 (!newFormat) { - if (ENCODE_ODS(major_version, minor_version) >= fld[RFLD_F_ODS]) - n++; + minorVersion++; + continue; } - relation->rel_fields->resize(n); - format->fmt_count = n; // We are using less than the allocated members. - format->fmt_length = FLAG_BYTES(n); - Format::fmt_desc_iterator desc = format->fmt_desc.begin(); + const auto format = Format::newFormat(*pool, fieldCount); + format->fmt_version = formatNumber; + format->fmt_length = FLAG_BYTES(format->fmt_count); + + if (minorVersion == dbb->dbb_minor_version) + currentFormat = formatNumber; + + relation->rel_formats->resize(formatNumber + 1); + (*relation->rel_formats)[formatNumber] = format; + + auto desc = format->fmt_desc.begin(); + for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH, ++desc) { - if (n-- > 0) + if (fld[RFLD_F_ODS] > ENCODE_ODS(majorVersion, minorVersion)) + continue; + + const gfld* gfield = &gfields[fld[RFLD_F_ID]]; + + desc->dsc_length = gfield->gfld_length; + if (gfield->gfld_dtype == dtype_varying) { - format->fmt_length = MET_align(&(*desc), format->fmt_length); - desc->dsc_address = (UCHAR*)(IPTR) format->fmt_length; - format->fmt_length += desc->dsc_length; + fb_assert(desc->dsc_length <= MAX_USHORT - sizeof(USHORT)); + desc->dsc_length += sizeof(USHORT); } + + desc->dsc_dtype = gfield->gfld_dtype; + + if (desc->isText()) + { + if (!getCharsetByTextType(desc->dsc_sub_type, gfield->gfld_sub_type)) + desc->dsc_sub_type = CS_NONE; + } + else + 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 + + format->fmt_length = MET_align(&(*desc), format->fmt_length); + desc->dsc_address = (UCHAR*)(IPTR) format->fmt_length; + format->fmt_length += desc->dsc_length; } + + minorVersion++; + formatNumber++; } + + fb_assert(currentFormat < relation->rel_formats->count()); + relation->rel_current_fmt = currentFormat; + relation->rel_current_format = (*relation->rel_formats)[currentFormat]; } } -// Load system objects into DSQL metadata cache. +// +// Load system objects into DSQL metadata cache +// + void INI_init_dsql(thread_db* tdbb, dsql_dbb* database) { - SET_TDBB(tdbb); + const auto dbb = tdbb->getDatabase(); - Database* const dbb = tdbb->getDatabase(); - const USHORT majorVersion = dbb->dbb_ods_version; - const USHORT minorVersion = dbb->dbb_minor_version; - const int* fld; + const auto majorVersion = dbb->dbb_ods_version; + const auto minorVersion = dbb->dbb_minor_version; // Load relation and fields. + const int* fld; for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) { if (relfld[RFLD_R_ODS] > ENCODE_ODS(majorVersion, minorVersion)) @@ -830,7 +1117,7 @@ void INI_init_dsql(thread_db* tdbb, dsql_dbb* database) for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) { - if (ENCODE_ODS(majorVersion, minorVersion) < fld[RFLD_F_ODS]) + if (fld[RFLD_F_ODS] > ENCODE_ODS(majorVersion, minorVersion)) continue; dsql_fld* field = FB_NEW_POOL(database->dbb_pool) dsql_fld(database->dbb_pool); @@ -863,7 +1150,7 @@ void INI_init_dsql(thread_db* tdbb, dsql_dbb* database) if (DTYPE_IS_TEXT(gfield->gfld_dtype)) { - if (get_charset_by_text_type(field->charSetId.value, gfield->gfld_sub_type)) + if (getCharsetByTextType(field->charSetId.value, gfield->gfld_sub_type)) field->charSetId.specified = true; } @@ -923,427 +1210,327 @@ void INI_init_dsql(thread_db* tdbb, dsql_dbb* database) } -static void add_index_set(thread_db* tdbb) +string INI_owner_privileges() { -/************************************** - * - * 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). - * - **************************************/ - SET_TDBB(tdbb); - Jrd::Attachment* attachment = tdbb->getAttachment(); + return string(gfields[fld_system_privileges].gfld_length, '\xff'); +} - index_desc idx; - AutoRequest handle1, handle2, handle3; +// +// Upgrade database to the current minor ODS version +// - for (int n = 0; n < SYSTEM_INDEX_COUNT; n++) - { - const ini_idx_t* index = &indices[n]; - jrd_rel* relation = MET_relation(tdbb, index->ini_idx_relid); +void INI_upgrade(thread_db* tdbb) +{ + const auto dbb = tdbb->getDatabase(); + const auto attachment = tdbb->getAttachment(); - MetaName indexName; - indexName.printf("RDB$INDEX_%d", index->ini_idx_index_id); + // If database is read-only, punt - STORE(REQUEST_HANDLE handle1) X IN RDB$INDICES - PAD(relation->rel_name.c_str(), X.RDB$RELATION_NAME); - PAD(indexName.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 (dbb->dbb_flags & DBB_read_only) + Arg::Gds(isc_read_only).raise(); - 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; + // Check current ODS version to see if we have work to do - X.RDB$SYSTEM_FLAG = RDB_system; - X.RDB$SYSTEM_FLAG.NULL = FALSE; - X.RDB$INDEX_INACTIVE = 0; + const auto majorVersion = dbb->dbb_ods_version; + fb_assert(majorVersion == ODS_VERSION); - // 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 auto minorVersion = dbb->dbb_minor_version; + if (minorVersion == ODS_CURRENT) + return; + + const auto odsVersion = ENCODE_ODS(majorVersion, minorVersion); + + const auto transaction = TRA_start(tdbb, TRA_no_auto_undo, 0); + tdbb->setTransaction(transaction); + + const int* fld; + const char* context = nullptr; + + try { + + // Disable most of the deferred work processing, + // as we do all the underlying work ourselves + + AutoSetRestoreFlag noDfw(&tdbb->tdbb_flags, TDBB_dont_post_dfw, true); + + // Get the database owner + + const auto ownerName = dbb->dbb_owner; + + AutoRequest handle, reqAddSC; + + // Create new system relations and new relation fields + + context = "relations"; + handle.reset(); + + { // scope for system relations + + RelationSecurity relSec(ownerName, reqAddSC); + + // Make sure relations exist already + + for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) + { + if (relfld[RFLD_R_TYPE] == rel_persistent && relfld[RFLD_R_ODS] > odsVersion) + DPM_create_relation(tdbb, MET_relation(tdbb, relfld[RFLD_R_ID])); + + for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) + ; + } + + AutoRequest handle2, handle3; + + for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) + { + const auto relId = relfld[RFLD_R_ID]; + const auto relName = names[relfld[RFLD_R_NAME]]; + const auto relType = relfld[RFLD_R_TYPE]; + + int fieldId = 0; + bool newFormat = false; + + for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) { - 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]; + if (fld[RFLD_F_ODS] > odsVersion) + { + const gfld* gfield = &gfields[fld[RFLD_F_ID]]; + const auto fieldName = names[fld[RFLD_F_NAME]]; + const auto globalName = names[gfield->gfld_name]; + const auto updateFlag = fld[RFLD_F_UPDATE]; - 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 + store_relation_field(tdbb, fieldId, relName, fieldName, globalName, + updateFlag, handle2); + + newFormat = true; + } + + ++fieldId; } - idx.idx_count = index->ini_idx_segment_count; - idx.idx_flags = index->ini_idx_flags; - SelectivityList selectivity(*tdbb->getDefaultPool()); + if (relfld[RFLD_R_ODS] > odsVersion) + { + store_relation(tdbb, relId, relName, fieldId, relType, handle, relSec); + } + else if (newFormat) + { + // New format number is the latest we're aware of - IDX_create_index(tdbb, relation, &idx, indexName.c_str(), NULL, - attachment->getSysTransaction(), selectivity); + const auto relation = MET_relation(tdbb, relId); + fb_assert(relation->rel_formats->count()); + const unsigned formatNumber = relation->rel_formats->count() - 1; + fb_assert(formatNumber < MAX_TABLE_VERSIONS); - X.RDB$INDEX_ID = idx.idx_id + 1; - END_STORE + FOR(REQUEST_HANDLE handle3 TRANSACTION_HANDLE transaction) + REL IN RDB$RELATIONS + WITH REL.RDB$RELATION_ID = relId + { + MODIFY REL USING + REL.RDB$FORMAT = formatNumber; + END_MODIFY + } + END_FOR - if (index->ini_idx_flags & idx_unique) - { - STORE(REQUEST_HANDLE handle3) RC IN RDB$RELATION_CONSTRAINTS - PAD(indexName.c_str(), RC.RDB$CONSTRAINT_NAME); - PAD(indexName.c_str(), RC.RDB$INDEX_NAME); - PAD(relation->rel_name.c_str(), RC.RDB$RELATION_NAME); - strcpy(RC.RDB$CONSTRAINT_TYPE, UNIQUE_CNSTRT); - strcpy(RC.RDB$DEFERRABLE, "NO"); - strcpy(RC.RDB$INITIALLY_DEFERRED, "NO"); - END_STORE + // Schedule metadata cache to be updated at the commit time + + dsc desc; + desc.makeText(static_cast(strlen(relName)), CS_METADATA, + (UCHAR*) relName); + DFW_post_work(transaction, dfw_update_format, &desc, 0); + } } } -} + NonRelationSecurity nonRelSec(ownerName, reqAddSC, false); -// 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, - AutoRequest& reqAddSC, - AutoRequest& reqModObjSC, - AutoRequest& reqInsUserPriv, - const MetaName& user_name, - const TEXT* rel_name, - const USHORT acl_length, - const UCHAR* acl) -{ -/************************************** - * - * 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. - * - **************************************/ - MetaName security_class, default_class; + // Create global fields added after the original minor ODS + + context = "domains"; + handle.reset(); - SET_TDBB(tdbb); - Jrd::Attachment* attachment = tdbb->getAttachment(); + for (const gfld* gfield = gfields; gfield->gfld_name; gfield++) + { + if (gfield->gfld_ods_version > odsVersion) + store_global_field(tdbb, gfield, handle, nonRelSec); + } - security_class.printf("%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, - DPM_gen_id(tdbb, MET_lookup_generator(tdbb, SQL_SECCLASS_GENERATOR), false, 1)); + // Create new system indexes - default_class.printf("%s%" SQUADFORMAT, DEFAULT_CLASS, - DPM_gen_id(tdbb, MET_lookup_generator(tdbb, DEFAULT_CLASS), false, 1)); + context = "indices"; + store_indices(tdbb, odsVersion); + // Create new system triggers and their trigger messages - add_security_class(tdbb, reqAddSC, security_class, acl_length, acl); - add_security_class(tdbb, reqAddSC, default_class, acl_length, acl); + context = "triggers"; + handle.reset(); - FOR(REQUEST_HANDLE reqModObjSC) REL IN RDB$RELATIONS - WITH REL.RDB$RELATION_NAME EQ rel_name + for (const jrd_trg* trigger = triggers; trigger->trg_relation; ++trigger) { - MODIFY REL USING - REL.RDB$SECURITY_CLASS.NULL = FALSE; - PAD(security_class.c_str(), REL.RDB$SECURITY_CLASS); - - REL.RDB$DEFAULT_CLASS.NULL = FALSE; - PAD(default_class.c_str(), REL.RDB$DEFAULT_CLASS); - END_MODIFY + if (trigger->trg_ods_version > odsVersion) + store_trigger(tdbb, trigger, handle); } - END_FOR - for (int cnt = 0; cnt < 6; cnt++) + context = "trigger messages"; + handle.reset(); + + for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message) { - STORE(REQUEST_HANDLE reqInsUserPriv) 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 = WITH_GRANT_OPTION; - break; - case 1: - strcpy(PRIV.RDB$USER, user_name.c_str()); - PRIV.RDB$PRIVILEGE[0] = 'I'; - PRIV.RDB$GRANT_OPTION = WITH_GRANT_OPTION; - break; - case 2: - strcpy(PRIV.RDB$USER, user_name.c_str()); - PRIV.RDB$PRIVILEGE[0] = 'U'; - PRIV.RDB$GRANT_OPTION = WITH_GRANT_OPTION; - break; - case 3: - strcpy(PRIV.RDB$USER, user_name.c_str()); - PRIV.RDB$PRIVILEGE[0] = 'D'; - PRIV.RDB$GRANT_OPTION = WITH_GRANT_OPTION; - break; - case 4: - strcpy(PRIV.RDB$USER, user_name.c_str()); - PRIV.RDB$PRIVILEGE[0] = 'R'; - PRIV.RDB$GRANT_OPTION = WITH_GRANT_OPTION; - break; - default: - strcpy(PRIV.RDB$USER, "PUBLIC"); - PRIV.RDB$PRIVILEGE[0] = 'S'; - PRIV.RDB$GRANT_OPTION = 0; - break; - } - PRIV.RDB$PRIVILEGE[1] = 0; - PRIV.RDB$GRANTOR.NULL = TRUE; - 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 + if (message->trg_ods_version > odsVersion) + store_message(tdbb, message, handle); } -} + // Create new system generators -// Add security to system objects. -static void add_security_to_sys_obj(thread_db* tdbb, - AutoRequest& reqAddSC, - AutoRequest& reqModObjSC, - AutoRequest& reqInsUserPriv, - const MetaName& user_name, - USHORT obj_type, - const MetaName& obj_name, - USHORT acl_length, - const UCHAR* acl) -{ - SET_TDBB(tdbb); - Jrd::Attachment* const attachment = tdbb->getAttachment(); + context = "generators"; + handle.reset(); - MetaName security_class; - security_class.printf("%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, - DPM_gen_id(tdbb, MET_lookup_generator(tdbb, SQL_SECCLASS_GENERATOR), false, 1)); + for (const gen* generator = generators; generator->gen_name; generator++) + { + if (generator->gen_ods_version > odsVersion) + store_generator(tdbb, generator, handle, nonRelSec); + } - add_security_class(tdbb, reqAddSC, security_class, acl_length, acl); + // Create new system packages - bool needsUsagePrivileges = false, needsExecPrivileges = false; + // Reset nonRelSec for package permissions, it should be its last usage in this function + new(&nonRelSec) NonRelationSecurity(ownerName, reqAddSC, true); - if (obj_type == obj_field) - { - FOR(REQUEST_HANDLE reqModObjSC) FLD IN RDB$FIELDS - WITH FLD.RDB$FIELD_NAME EQ obj_name.c_str() - { - MODIFY FLD USING - FLD.RDB$SECURITY_CLASS.NULL = FALSE; - PAD(security_class.c_str(), FLD.RDB$SECURITY_CLASS); - END_MODIFY + context = "packages"; + store_packages(tdbb, nonRelSec, odsVersion); - needsUsagePrivileges = true; - } - END_FOR - } - else if (obj_type == obj_charset) - { - FOR(REQUEST_HANDLE reqModObjSC) CS IN RDB$CHARACTER_SETS - WITH CS.RDB$CHARACTER_SET_NAME EQ obj_name.c_str() - { - MODIFY CS USING - CS.RDB$SECURITY_CLASS.NULL = FALSE; - PAD(security_class.c_str(), CS.RDB$SECURITY_CLASS); - END_MODIFY + // There are no new built-in charsets and collations introduced in ODS 13.1. + // But if it happens in some future minor ODS, the corresponding INTL structures + // should have the ODS field added and here we need code that conditionally adds + // the missing charsets/collations. + // + // The same about the new types being introduced in minor ODS versions. - needsUsagePrivileges = true; - } - END_FOR - } - else if (obj_type == obj_collation) - { - FOR(REQUEST_HANDLE reqModObjSC) COLL IN RDB$COLLATIONS - WITH COLL.RDB$COLLATION_NAME EQ obj_name.c_str() - { - MODIFY COLL USING - COLL.RDB$SECURITY_CLASS.NULL = FALSE; - PAD(security_class.c_str(), COLL.RDB$SECURITY_CLASS); - END_MODIFY + TRA_commit(tdbb, transaction, false); - needsUsagePrivileges = true; - } - END_FOR } - else if (obj_type == obj_exception) + catch (const Exception& ex) { - FOR(REQUEST_HANDLE reqModObjSC) XCP IN RDB$EXCEPTIONS - WITH XCP.RDB$EXCEPTION_NAME EQ obj_name.c_str() - { - MODIFY XCP USING - XCP.RDB$SECURITY_CLASS.NULL = FALSE; - PAD(security_class.c_str(), XCP.RDB$SECURITY_CLASS); - END_MODIFY + TRA_rollback(tdbb, transaction, false, true); - needsUsagePrivileges = true; - } - END_FOR - } - else if (obj_type == obj_generator) - { - FOR(REQUEST_HANDLE reqModObjSC) GEN IN RDB$GENERATORS - WITH GEN.RDB$GENERATOR_NAME EQ obj_name.c_str() - { - MODIFY GEN USING - GEN.RDB$SECURITY_CLASS.NULL = FALSE; - PAD(security_class.c_str(), GEN.RDB$SECURITY_CLASS); - END_MODIFY + // Delete relations we've just created - needsUsagePrivileges = true; - } - END_FOR - } - else if (obj_type == obj_sql_role) - { - FOR(REQUEST_HANDLE reqModObjSC) R IN RDB$ROLES - WITH R.RDB$ROLE_NAME EQ obj_name.c_str() - { - MODIFY R USING - R.RDB$SECURITY_CLASS.NULL = FALSE; - PAD(security_class.c_str(), R.RDB$SECURITY_CLASS); - END_MODIFY - } - END_FOR - } - else if (obj_type == obj_package_header) - { - FOR(REQUEST_HANDLE reqModObjSC) PKG IN RDB$PACKAGES - WITH PKG.RDB$PACKAGE_NAME EQ obj_name.c_str() + for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) { - MODIFY PKG USING - PKG.RDB$SECURITY_CLASS.NULL = FALSE; - PAD(security_class.c_str(), PKG.RDB$SECURITY_CLASS); - END_MODIFY + if (relfld[RFLD_R_TYPE] == rel_persistent && relfld[RFLD_R_ODS] > odsVersion) + { + const auto relation = MET_relation(tdbb, relfld[RFLD_R_ID]); + if (relation && relation->getBasePages()->rel_pages) + DPM_delete_relation(tdbb, relation); + } - needsExecPrivileges = true; + for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) + ; } - END_FOR - } - else if (obj_type == obj_database) - { - FOR(REQUEST_HANDLE reqModObjSC) DB IN RDB$DATABASE + + string msg; + msg.printf("Database: %s\n\t" + "Failed upgrading ODS from version %u.%u to version %u.%u", + attachment->att_filename.c_str(), + majorVersion, minorVersion, majorVersion, ODS_CURRENT); + iscLogException(msg.c_str(), ex); + + if (context) { - MODIFY DB USING - DB.RDB$SECURITY_CLASS.NULL = FALSE; - PAD(security_class.c_str(), DB.RDB$SECURITY_CLASS); - END_MODIFY + Arg::StatusVector error(ex); + error.prepend(Arg::Gds(isc_ods_upgrade_err) << Arg::Str(context)); + error.raise(); } - END_FOR + + throw; } - else - fb_assert(false); - const char* const privileges = - needsUsagePrivileges ? USAGE_PRIVILEGES : - needsExecPrivileges ? EXEC_PRIVILEGES : - NULL; + // If the database was successfully updated, mark it with the current minor ODS - if (privileges) - { - fb_assert(user_name.hasData()); - fb_assert(obj_name.hasData()); + win window(HEADER_PAGE_NUMBER); + auto header = (Ods::header_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_header); + CCH_MARK(tdbb, &window); - for (const char* p = privileges; *p; ++p) - { - STORE(REQUEST_HANDLE reqInsUserPriv) PRIV IN RDB$USER_PRIVILEGES - PAD(user_name.c_str(), PRIV.RDB$USER); - PAD(obj_name.c_str(), PRIV.RDB$RELATION_NAME); - PRIV.RDB$PRIVILEGE[0] = *p; - PRIV.RDB$PRIVILEGE[1] = 0; - PRIV.RDB$GRANT_OPTION = WITH_GRANT_OPTION; - PRIV.RDB$USER_TYPE = obj_user; - PRIV.RDB$OBJECT_TYPE = obj_type; - PRIV.RDB$GRANTOR.NULL = TRUE; - END_STORE - } - } -} + dbb->dbb_minor_version = header->hdr_ods_minor = ODS_CURRENT; + CCH_RELEASE(tdbb, &window); + string msg; + msg.printf("Database: %s\n\t" + "Successfully upgraded ODS from version %u.%u to version %u.%u", + attachment->att_filename.c_str(), + majorVersion, minorVersion, majorVersion, ODS_CURRENT); + gds__log(msg.c_str()); -static void store_admin_grant(thread_db* tdbb, const char* user, USHORT user_type, - const char* object, USHORT object_type, const char* prvl, USHORT option, bool dflt) -{ - Attachment* attachment = tdbb->getAttachment(); // needed for preprocessed code - AutoRequest handle; + // Invalidate new/modified relations in the DSQL metadata cache, + // thus forcing them to be reloaded on demand - while (*prvl) + if (const auto dbb = attachment->att_dsql_instance) { - STORE(REQUEST_HANDLE handle) PRIV IN RDB$USER_PRIVILEGES - PAD(user, PRIV.RDB$USER); - PAD(object, PRIV.RDB$RELATION_NAME); + for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) + { + bool invalidate = false; - if (dflt) + if (relfld[RFLD_R_ODS] > odsVersion) + invalidate = true; + + for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) { - PRIV.RDB$FIELD_NAME[0] = 'D'; - PRIV.RDB$FIELD_NAME[1] = 0; - PRIV.RDB$FIELD_NAME.NULL = FALSE; + if (fld[RFLD_F_ODS] > odsVersion) + invalidate = true; } - else - PRIV.RDB$FIELD_NAME.NULL = TRUE; - PRIV.RDB$PRIVILEGE[0] = *prvl++; - PRIV.RDB$PRIVILEGE[1] = 0; - PRIV.RDB$GRANT_OPTION = option; - PRIV.RDB$USER_TYPE = user_type; - PRIV.RDB$OBJECT_TYPE = object_type; - PRIV.RDB$GRANTOR.NULL = TRUE; - END_STORE - } -} + // Code below is the same as METD_drop_relation() but without a transaction + const auto relName = names[relfld[RFLD_R_NAME]]; + dsql_rel* relation; -static void store_admin_role_grant(thread_db* tdbb, const char* user) -{ - store_admin_grant(tdbb, user, obj_user, ADMIN_ROLE, obj_sql_role, "M", 2, true); + if (invalidate && dbb->dbb_relations.get(relName, relation)) + { + MET_dsql_cache_use(tdbb, SYM_relation, relName); + relation->rel_flags |= REL_dropped; + dbb->dbb_relations.remove(relName); + } + } + } } -static void store_admin_role(thread_db* tdbb, const MetaName& roleName, MetaName ownerName, - UserId::Privileges* priv) +static void store_admin_role(thread_db* tdbb, const MetaName& roleName, + RoleSecurity& security) { - if (!ownerName.hasData()) - ownerName = DBA_USER_NAME; + const MetaName ownerName = security.getOwnerName(); + const string p = INI_owner_privileges(); - string p; - if (priv) - priv->store(p.getBuffer(priv->BYTES_COUNT)); - else - p = INI_owner_privileges(); + const auto securityClass = security.storeSecurityClass(tdbb); PreparedStatement::Builder sql; - sql << "insert into rdb$roles(rdb$role_name, rdb$owner_name, rdb$system_flag, rdb$system_privileges)" - << "values (" << roleName << "," << ownerName << ", 1," << p << ")"; + sql << "insert into rdb$roles(rdb$role_name, rdb$owner_name, rdb$security_class, rdb$system_flag, rdb$system_privileges)" + << "values (" << roleName << "," << ownerName << "," << securityClass << ", 1," << p << ")"; + + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); - Attachment* attachment = tdbb->getAttachment(); - jrd_tra* transaction = attachment->getSysTransaction(); AutoPreparedStatement ps(attachment->prepareStatement(tdbb, transaction, sql)); ps->execute(tdbb, transaction); + + security.storePrivileges(tdbb, roleName.c_str()); } static void store_default_pub(thread_db* tdbb, const MetaName& ownerName) { - Attachment* const attachment = tdbb->getAttachment(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); + AutoRequest handle; - STORE(REQUEST_HANDLE handle) PUB IN RDB$PUBLICATIONS + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + PUB IN RDB$PUBLICATIONS { PAD(DEFAULT_PUBLICATION, PUB.RDB$PUBLICATION_NAME); PUB.RDB$PUBLICATION_NAME.NULL = FALSE; - PAD(ownerName.c_str(), PUB.RDB$OWNER_NAME); + PAD(ownerName, PUB.RDB$OWNER_NAME); PUB.RDB$OWNER_NAME.NULL = FALSE; PUB.RDB$SYSTEM_FLAG = RDB_system; @@ -1359,56 +1546,36 @@ static void store_default_pub(thread_db* tdbb, const MetaName& ownerName) } -// Add security class. -static void add_security_class(thread_db* tdbb, AutoRequest& handle, const MetaName& class_name, USHORT acl_length, const UCHAR* acl) +static void store_generator(thread_db* tdbb, const gen* generator, + AutoRequest& handle, NonRelationSecurity& security) { - SET_TDBB(tdbb); - Jrd::Attachment* const attachment = tdbb->getAttachment(); - - bid blob_id; - attachment->storeBinaryBlob(tdbb, attachment->getSysTransaction(), &blob_id, - ByteChunk(acl, acl_length)); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); - STORE(REQUEST_HANDLE handle) - CLS IN RDB$SECURITY_CLASSES - { - PAD(class_name.c_str(), CLS.RDB$SECURITY_CLASS); - CLS.RDB$ACL = blob_id; - } - END_STORE -} - - -static void store_generator(thread_db* tdbb, const gen* generator, AutoRequest& handle, - const MetaName& owner) -{ -/************************************** - * - * 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); - Jrd::Attachment* attachment = tdbb->getAttachment(); + const auto ownerName = security.getOwnerName(); + const auto securityClass = security.storeSecurityClass(tdbb); - STORE(REQUEST_HANDLE handle) X IN RDB$GENERATORS + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + 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; - PAD(owner.c_str(), X.RDB$OWNER_NAME); + + PAD(ownerName, X.RDB$OWNER_NAME); X.RDB$OWNER_NAME.NULL = FALSE; + + PAD(securityClass, X.RDB$SECURITY_CLASS); + X.RDB$SECURITY_CLASS.NULL = FALSE; + X.RDB$INITIAL_VALUE = 0; X.RDB$INITIAL_VALUE.NULL = FALSE; + if (generator->gen_description) { - attachment->storeMetaDataBlob(tdbb, attachment->getSysTransaction(), &X.RDB$DESCRIPTION, + attachment->storeMetaDataBlob(tdbb, transaction, &X.RDB$DESCRIPTION, generator->gen_description); X.RDB$DESCRIPTION.NULL = FALSE; } @@ -1418,43 +1585,48 @@ static void store_generator(thread_db* tdbb, const gen* generator, AutoRequest& X.RDB$GENERATOR_INCREMENT = 0; // only sys gens have zero default increment } END_STORE + + security.storePrivileges(tdbb, generator->gen_name, obj_generator); } -static void store_global_field(thread_db* tdbb, const gfld* gfield, AutoRequest& handle, - const MetaName& owner) +static void store_global_field(thread_db* tdbb, const gfld* gfield, + AutoRequest& handle, NonRelationSecurity& security) { -/************************************** - * - * 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); - Jrd::Attachment* attachment = tdbb->getAttachment(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); + + const auto objName = names[(USHORT)gfield->gfld_name]; + const auto ownerName = security.getOwnerName(); - STORE(REQUEST_HANDLE handle) X IN RDB$FIELDS + const auto securityClass = security.storeSecurityClass(tdbb); + + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + X IN RDB$FIELDS { - PAD(names[(USHORT)gfield->gfld_name], X.RDB$FIELD_NAME); + PAD(objName, 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; - PAD(owner.c_str(), X.RDB$OWNER_NAME); + + PAD(ownerName, X.RDB$OWNER_NAME); X.RDB$OWNER_NAME.NULL = FALSE; + + PAD(securityClass, X.RDB$SECURITY_CLASS); + X.RDB$SECURITY_CLASS.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; X.RDB$CHARACTER_LENGTH.NULL = TRUE; + if (gfield->gfld_dflt_blr) { - attachment->storeBinaryBlob(tdbb, attachment->getSysTransaction(), &X.RDB$DEFAULT_VALUE, + attachment->storeBinaryBlob(tdbb, transaction, &X.RDB$DEFAULT_VALUE, ByteChunk(gfield->gfld_dflt_blr, gfield->gfld_dflt_len)); X.RDB$DEFAULT_VALUE.NULL = FALSE; } @@ -1575,42 +1747,138 @@ static void store_global_field(thread_db* tdbb, const gfld* gfield, AutoRequest& X.RDB$NULL_FLAG = !gfield->gfld_nullable; } END_STORE + + security.storePrivileges(tdbb, objName, obj_field); } -static void store_intlnames(thread_db* tdbb, const MetaName& owner) +static void store_indices(thread_db* tdbb, USHORT odsVersion) { -/************************************** - * - * 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::Attachment* attachment = tdbb->getAttachment(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); + + index_desc idx; + + AutoRequest handle1, handle2, handle3; + + for (int n = 0; n < SYSTEM_INDEX_COUNT; n++) + { + const ini_idx_t* index = &indices[n]; + const auto relation = MET_relation(tdbb, index->ini_idx_relid); + + if (odsVersion && index->ini_idx_ods <= odsVersion) + continue; + + MetaName indexName; + indexName.printf("RDB$INDEX_%d", index->ini_idx_index_id); + + STORE(REQUEST_HANDLE handle1 TRANSACTION_HANDLE transaction) + X IN RDB$INDICES + { + PAD(relation->rel_name, X.RDB$RELATION_NAME); + PAD(indexName, 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 = RDB_system; + 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 auto segment = &index->ini_idx_segment[position]; + + STORE(REQUEST_HANDLE handle2 TRANSACTION_HANDLE transaction) + 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, 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, indexName.c_str(), NULL, + transaction, selectivity); + + X.RDB$INDEX_ID = idx.idx_id + 1; + } + END_STORE + + if (index->ini_idx_flags & idx_unique) + { + STORE(REQUEST_HANDLE handle3 TRANSACTION_HANDLE transaction) + RC IN RDB$RELATION_CONSTRAINTS + { + PAD(indexName, RC.RDB$CONSTRAINT_NAME); + PAD(indexName, RC.RDB$INDEX_NAME); + PAD(relation->rel_name, RC.RDB$RELATION_NAME); + strcpy(RC.RDB$CONSTRAINT_TYPE, UNIQUE_CNSTRT); + strcpy(RC.RDB$DEFERRABLE, "NO"); + strcpy(RC.RDB$INITIALLY_DEFERRED, "NO"); + } + END_STORE + } + } +} + + +static void store_intlnames(thread_db* tdbb, NonRelationSecurity& security) +{ + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); + + const auto ownerName = security.getOwnerName(); AutoRequest handle; for (const IntlManager::CharSetDefinition* charSet = IntlManager::defaultCharSets; charSet->name; ++charSet) { - STORE(REQUEST_HANDLE handle) X IN RDB$CHARACTER_SETS USING + const auto securityClass = security.storeSecurityClass(tdbb); + + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + 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; - PAD(owner.c_str(), X.RDB$OWNER_NAME); + + PAD(ownerName, X.RDB$OWNER_NAME); X.RDB$OWNER_NAME.NULL = FALSE; + + PAD(securityClass, X.RDB$SECURITY_CLASS); + X.RDB$SECURITY_CLASS.NULL = FALSE; } END_STORE + + security.storePrivileges(tdbb, charSet->name, obj_charset); } handle.reset(); @@ -1618,7 +1886,10 @@ static void store_intlnames(thread_db* tdbb, const MetaName& owner) for (const IntlManager::CollationDefinition* collation = IntlManager::defaultCollations; collation->name; ++collation) { - STORE(REQUEST_HANDLE handle) X IN RDB$COLLATIONS USING + const auto securityClass = security.storeSecurityClass(tdbb); + + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + X IN RDB$COLLATIONS USING { PAD(collation->name, X.RDB$COLLATION_NAME); @@ -1632,15 +1903,21 @@ static void store_intlnames(thread_db* tdbb, const MetaName& owner) 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; - PAD(owner.c_str(), X.RDB$OWNER_NAME); + + PAD(ownerName, X.RDB$OWNER_NAME); X.RDB$OWNER_NAME.NULL = FALSE; + + PAD(securityClass, X.RDB$SECURITY_CLASS); + X.RDB$SECURITY_CLASS.NULL = FALSE; + X.RDB$COLLATION_ATTRIBUTES = collation->attributes; if (collation->specificAttributes) { - attachment->storeMetaDataBlob(tdbb, attachment->getSysTransaction(), + attachment->storeMetaDataBlob(tdbb, transaction, &X.RDB$SPECIFIC_ATTRIBUTES, collation->specificAttributes); X.RDB$SPECIFIC_ATTRIBUTES.NULL = FALSE; } @@ -1648,28 +1925,19 @@ static void store_intlnames(thread_db* tdbb, const MetaName& owner) X.RDB$SPECIFIC_ATTRIBUTES.NULL = TRUE; } END_STORE + + security.storePrivileges(tdbb, collation->name, obj_collation); } } static void store_message(thread_db* tdbb, const trigger_msg* message, AutoRequest& handle) { -/************************************** - * - * s t o r e _ m e s s a g e - * - ************************************** - * - * Functional description - * Store system trigger messages. - * - **************************************/ - SET_TDBB(tdbb); - Jrd::Attachment* attachment = tdbb->getAttachment(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); - // store the trigger - - STORE(REQUEST_HANDLE handle) X IN RDB$TRIGGER_MESSAGES + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + X IN RDB$TRIGGER_MESSAGES { PAD(message->trigmsg_name, X.RDB$TRIGGER_NAME); X.RDB$MESSAGE_NUMBER = message->trigmsg_number; @@ -1679,79 +1947,121 @@ static void store_message(thread_db* tdbb, const trigger_msg* message, AutoReque } -static void store_relation_field(thread_db* tdbb, - const int* fld, - const int* relfld, - int field_id, - AutoRequest& handle) +static void store_relation(thread_db* tdbb, + int relId, + const char* relName, + int fieldId, + int relType, + AutoRequest& handle, + RelationSecurity& security) { -/************************************** - * - * 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); - Jrd::Attachment* attachment = tdbb->getAttachment(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); + + const auto ownerName = security.getOwnerName(); + + MetaName securityClass, defaultClass; + security.storeSecurityClass(tdbb, securityClass, defaultClass); + + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + X IN RDB$RELATIONS + { + X.RDB$RELATION_ID = relId; + PAD(relName, X.RDB$RELATION_NAME); + + PAD(ownerName, X.RDB$OWNER_NAME); + X.RDB$OWNER_NAME.NULL = FALSE; + + PAD(securityClass, X.RDB$SECURITY_CLASS); + X.RDB$SECURITY_CLASS.NULL = FALSE; - STORE(REQUEST_HANDLE handle) X IN RDB$RELATION_FIELDS + PAD(defaultClass, X.RDB$DEFAULT_CLASS); + X.RDB$DEFAULT_CLASS.NULL = FALSE; + + X.RDB$FIELD_ID = fieldId; + X.RDB$FORMAT = 0; + X.RDB$SYSTEM_FLAG = RDB_system; + X.RDB$DBKEY_LENGTH = 8; + } + END_STORE; + + security.storePrivileges(tdbb, relName); +} + +static void store_relation_field(thread_db* tdbb, + int fieldId, + const char* relName, + const char* fieldName, + const char* globalName, + int updateFlag, + AutoRequest& handle) +{ + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); + + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + X IN RDB$RELATION_FIELDS { - const gfld* gfield = &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; + PAD(relName, X.RDB$RELATION_NAME); + PAD(fieldName, X.RDB$FIELD_NAME); + PAD(globalName, X.RDB$FIELD_SOURCE); + X.RDB$FIELD_POSITION = fieldId; + X.RDB$FIELD_ID = fieldId; X.RDB$SYSTEM_FLAG = RDB_system; X.RDB$SYSTEM_FLAG.NULL = FALSE; - X.RDB$UPDATE_FLAG = fld[RFLD_F_UPDATE]; + X.RDB$UPDATE_FLAG = updateFlag; } END_STORE } -// Store system packages. -static void store_packages(thread_db* tdbb, const MetaName& owner) +static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHORT odsVersion) { - SET_TDBB(tdbb); - Jrd::Attachment* attachment = tdbb->getAttachment(); - Database* const dbb = tdbb->getDatabase(); - const USHORT majorVersion = dbb->dbb_ods_version; - const USHORT minorVersion = dbb->dbb_minor_version; + const auto dbb = tdbb->getDatabase(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); + + const auto ownerName = security.getOwnerName(); AutoRequest packageHandle, procedureHandle, procedureParameterHandle; AutoRequest functionHandle, functionReturnHandle, functionArgumentHandle; - SLONG procGen = MET_lookup_generator(tdbb, PROCEDURES_GENERATOR); - SLONG funcGen = MET_lookup_generator(tdbb, FUNCTIONS_GENERATOR); + const SLONG procGen = lookupGenerator(PROCEDURES_GENERATOR); + const SLONG funcGen = lookupGenerator(FUNCTIONS_GENERATOR); - for (auto& systemPackage : SystemPackage::get()) + for (const auto& systemPackage : SystemPackage::get()) { - if (systemPackage.odsVersion > ENCODE_ODS(majorVersion, minorVersion)) + if (odsVersion && systemPackage.odsVersion <= odsVersion) continue; - STORE (REQUEST_HANDLE packageHandle) PKG IN RDB$PACKAGES + const auto securityClass = security.storeSecurityClass(tdbb); + + STORE (REQUEST_HANDLE packageHandle TRANSACTION_HANDLE transaction) + PKG IN RDB$PACKAGES { PAD(systemPackage.name, PKG.RDB$PACKAGE_NAME); - PAD(owner.c_str(), PKG.RDB$OWNER_NAME); + PAD(ownerName, PKG.RDB$OWNER_NAME); + PKG.RDB$OWNER_NAME.NULL = FALSE; + + PAD(securityClass, PKG.RDB$SECURITY_CLASS); + PKG.RDB$SECURITY_CLASS.NULL = FALSE; + PKG.RDB$SYSTEM_FLAG = RDB_system; PKG.RDB$VALID_BODY_FLAG = TRUE; } END_STORE - for (auto& procedure : systemPackage.procedures) + security.storePrivileges(tdbb, systemPackage.name, obj_package_header); + + for (const auto& procedure : systemPackage.procedures) { - STORE (REQUEST_HANDLE procedureHandle) PRC IN RDB$PROCEDURES + STORE (REQUEST_HANDLE procedureHandle TRANSACTION_HANDLE transaction) + PRC IN RDB$PROCEDURES { PAD(systemPackage.name, PRC.RDB$PACKAGE_NAME); PAD(procedure.name, PRC.RDB$PROCEDURE_NAME); - PAD(owner.c_str(), PRC.RDB$OWNER_NAME); + PAD(ownerName, PRC.RDB$OWNER_NAME); PRC.RDB$SYSTEM_FLAG = RDB_system; PRC.RDB$PROCEDURE_ID = DPM_gen_id(tdbb, procGen, false, 1); @@ -1769,11 +2079,12 @@ static void store_packages(thread_db* tdbb, const MetaName& owner) { SSHORT paramNumber = -1; - for (auto& parameter : parameterType == 0 ? procedure.inputParameters : procedure.outputParameters) + for (const auto& parameter : parameterType == 0 ? procedure.inputParameters : procedure.outputParameters) { ++paramNumber; - STORE (REQUEST_HANDLE procedureParameterHandle) PP IN RDB$PROCEDURE_PARAMETERS + STORE (REQUEST_HANDLE procedureParameterHandle TRANSACTION_HANDLE transaction) + PP IN RDB$PROCEDURE_PARAMETERS { PAD(systemPackage.name, PP.RDB$PACKAGE_NAME); PAD(procedure.name, PP.RDB$PROCEDURE_NAME); @@ -1792,7 +2103,7 @@ static void store_packages(thread_db* tdbb, const MetaName& owner) if (parameter.defaultBlr.hasData()) { - attachment->storeMetaDataBlob(tdbb, attachment->getSysTransaction(), &PP.RDB$DEFAULT_SOURCE, + attachment->storeMetaDataBlob(tdbb, transaction, &PP.RDB$DEFAULT_SOURCE, string("default ") + parameter.defaultText); PP.RDB$DEFAULT_SOURCE.NULL = FALSE; @@ -1801,7 +2112,7 @@ static void store_packages(thread_db* tdbb, const MetaName& owner) blrData.append(parameter.defaultBlr); blrData.push(blr_eoc); - attachment->storeBinaryBlob(tdbb, attachment->getSysTransaction(), &PP.RDB$DEFAULT_VALUE, + attachment->storeBinaryBlob(tdbb, transaction, &PP.RDB$DEFAULT_VALUE, blrData); PP.RDB$DEFAULT_VALUE.NULL = FALSE; } @@ -1816,14 +2127,15 @@ static void store_packages(thread_db* tdbb, const MetaName& owner) } } - for (auto& function : systemPackage.functions) + for (const auto& function : systemPackage.functions) { - STORE (REQUEST_HANDLE functionHandle) FUN IN RDB$FUNCTIONS + STORE (REQUEST_HANDLE functionHandle TRANSACTION_HANDLE transaction) + FUN IN RDB$FUNCTIONS { PAD(systemPackage.name, FUN.RDB$PACKAGE_NAME); PAD(function.name, FUN.RDB$FUNCTION_NAME); - PAD(owner.c_str(), FUN.RDB$OWNER_NAME); + PAD(ownerName, FUN.RDB$OWNER_NAME); FUN.RDB$SYSTEM_FLAG = RDB_system; FUN.RDB$FUNCTION_ID = DPM_gen_id(tdbb, funcGen, false, 1); @@ -1837,7 +2149,8 @@ static void store_packages(thread_db* tdbb, const MetaName& owner) SSHORT paramNumber = 0; - STORE (REQUEST_HANDLE functionReturnHandle) ARG IN RDB$FUNCTION_ARGUMENTS + STORE (REQUEST_HANDLE functionReturnHandle TRANSACTION_HANDLE transaction) + ARG IN RDB$FUNCTION_ARGUMENTS { PAD(systemPackage.name, ARG.RDB$PACKAGE_NAME); PAD(function.name, ARG.RDB$FUNCTION_NAME); @@ -1851,11 +2164,12 @@ static void store_packages(thread_db* tdbb, const MetaName& owner) } END_STORE - for (auto& parameter : function.parameters) + for (const auto& parameter : function.parameters) { ++paramNumber; - STORE (REQUEST_HANDLE functionArgumentHandle) ARG IN RDB$FUNCTION_ARGUMENTS + STORE (REQUEST_HANDLE functionArgumentHandle TRANSACTION_HANDLE transaction) + ARG IN RDB$FUNCTION_ARGUMENTS { PAD(systemPackage.name, ARG.RDB$PACKAGE_NAME); PAD(function.name, ARG.RDB$FUNCTION_NAME); @@ -1872,7 +2186,7 @@ static void store_packages(thread_db* tdbb, const MetaName& owner) if (parameter.defaultBlr.hasData()) { - attachment->storeMetaDataBlob(tdbb, attachment->getSysTransaction(), &ARG.RDB$DEFAULT_SOURCE, + attachment->storeMetaDataBlob(tdbb, transaction, &ARG.RDB$DEFAULT_SOURCE, string("default ") + parameter.defaultText); ARG.RDB$DEFAULT_SOURCE.NULL = FALSE; @@ -1881,7 +2195,7 @@ static void store_packages(thread_db* tdbb, const MetaName& owner) blrData.append(parameter.defaultBlr); blrData.push(blr_eoc); - attachment->storeBinaryBlob(tdbb, attachment->getSysTransaction(), &ARG.RDB$DEFAULT_VALUE, + attachment->storeBinaryBlob(tdbb, transaction, &ARG.RDB$DEFAULT_VALUE, blrData); ARG.RDB$DEFAULT_VALUE.NULL = FALSE; } @@ -1900,29 +2214,22 @@ static void store_packages(thread_db* tdbb, const MetaName& owner) static void store_trigger(thread_db* tdbb, const jrd_trg* trigger, AutoRequest& 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); - Attachment* attachment = tdbb->getAttachment(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); + + // Indicate that the relation format needs revising + + const auto triggerName = names[trigger->trg_relation]; - // indicate that the relation format needs revising dsc desc; - desc.makeText(static_cast(strlen(names[trigger->trg_relation])), CS_METADATA, - (UCHAR*) names[trigger->trg_relation]); - DFW_post_system_work(tdbb, dfw_update_format, &desc, 0); + desc.makeText(static_cast(strlen(triggerName)), CS_METADATA, + (UCHAR*) triggerName); + DFW_post_work(transaction, dfw_update_format, &desc, 0); - // store the trigger + // Store the trigger - STORE(REQUEST_HANDLE handle) X IN RDB$TRIGGERS + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + X IN RDB$TRIGGERS { PAD(trigger->trg_name, X.RDB$TRIGGER_NAME); PAD(names[trigger->trg_relation], X.RDB$RELATION_NAME); @@ -1931,35 +2238,8 @@ static void store_trigger(thread_db* tdbb, const jrd_trg* trigger, AutoRequest& X.RDB$SYSTEM_FLAG.NULL = FALSE; X.RDB$TRIGGER_TYPE = trigger->trg_type; X.RDB$FLAGS = trigger->trg_flags; - attachment->storeBinaryBlob(tdbb, attachment->getSysTransaction(), &X.RDB$TRIGGER_BLR, + attachment->storeBinaryBlob(tdbb, transaction, &X.RDB$TRIGGER_BLR, ByteChunk(trigger->trg_blr, trigger->trg_length)); } END_STORE } - - -string INI_owner_privileges() -{ - return string(gfields[fld_system_privileges].gfld_length, '\xff'); -} - - -static bool get_charset_by_text_type(SSHORT& charSet, const USHORT sub_type) -{ - switch (sub_type) - { - case dsc_text_type_metadata: - charSet = CS_METADATA; - break; - case dsc_text_type_ascii: - charSet = CS_ASCII; - break; - case dsc_text_type_fixed: - charSet = CS_BINARY; - break; - default: - return false; - } - return true; -} - diff --git a/src/jrd/ini.h b/src/jrd/ini.h index 7813788991c..9cc22cf22f0 100644 --- a/src/jrd/ini.h +++ b/src/jrd/ini.h @@ -75,7 +75,7 @@ const USHORT TIMESTAMP_TZ_SIZE = 12; // Pick up global ids -#define FIELD(type, name, dtype, length, sub_type, dflt_blr, nullable) type, +#define FIELD(type, name, dtype, length, sub_type, dflt_blr, nullable, ods) type, enum gflds { #include "../jrd/fields.h" @@ -88,11 +88,11 @@ typedef gflds GFLDS; // Pick up actual global fields #ifndef GPRE -#define FIELD(type, name, dtype, length, sub_type, dflt_blr, nullable) \ - { (int) type, (int) name, dtype, length, sub_type, dflt_blr, sizeof(dflt_blr), nullable }, +#define FIELD(type, name, dtype, length, sub_type, dflt_blr, nullable, ods) \ + { (int) type, (int) name, dtype, length, sub_type, dflt_blr, sizeof(dflt_blr), nullable, ods }, #else -#define FIELD(type, name, dtype, length, sub_type, dflt_blr, nullable) \ - { (int) type, (int) name, dtype, length, sub_type, NULL, 0, true }, +#define FIELD(type, name, dtype, length, sub_type, dflt_blr, nullable, ods) \ + { (int) type, (int) name, dtype, length, sub_type, NULL, 0, true, ods }, #endif struct gfld @@ -105,12 +105,13 @@ struct gfld const UCHAR* gfld_dflt_blr; USHORT gfld_dflt_len; bool gfld_nullable; + USHORT gfld_ods_version; }; static const struct gfld gfields[] = { #include "../jrd/fields.h" - { 0, 0, dtype_unknown, 0, 0, NULL, 0, false } + { 0, 0, dtype_unknown, 0, 0, NULL, 0, false, 0 } }; #undef FIELD diff --git a/src/jrd/ini_proto.h b/src/jrd/ini_proto.h index 8c354587514..c75011a0cc1 100644 --- a/src/jrd/ini_proto.h +++ b/src/jrd/ini_proto.h @@ -29,11 +29,11 @@ namespace Jrd { class dsql_dbb; } -void INI_format(const char*, const char*); -USHORT INI_get_trig_flags(const TEXT*); +void INI_format(Jrd::thread_db*, const Firebird::string&); +USHORT INI_get_trig_flags(const Jrd::MetaName&); void INI_init(Jrd::thread_db*); -void INI_init2(Jrd::thread_db*); void INI_init_dsql(Jrd::thread_db*, Jrd::dsql_dbb* database); Firebird::string INI_owner_privileges(); +void INI_upgrade(Jrd::thread_db*); #endif // JRD_INI_PROTO_H diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index fd5525a86c0..d8506fcaeb5 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -1083,6 +1083,7 @@ namespace Jrd ReplicaMode dpb_replica_mode; bool dpb_set_db_replica; bool dpb_clear_map; + bool dpb_upgrade_db; // here begin compound objects // for constructor to work properly dpb_user_name @@ -1799,7 +1800,6 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch INI_init(tdbb); SHUT_init(tdbb); PAG_header_init(tdbb); - INI_init2(tdbb); PAG_init(tdbb); if (options.dpb_set_page_buffers) @@ -1859,7 +1859,6 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch jAtt->getStable()->manualAsyncUnlock(attachment->att_flags); INI_init(tdbb); - INI_init2(tdbb); PAG_header(tdbb, true); dbb->dbb_crypto_manager->attach(tdbb, attachment); } @@ -2058,6 +2057,18 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch USE_GSTAT_UTILITY); } + if (options.dpb_upgrade_db) + { + validateAccess(tdbb, attachment, USE_GFIX_UTILITY); + if (!CCH_exclusive(tdbb, LCK_EX, WAIT_PERIOD, NULL)) + { + ERR_post(Arg::Gds(isc_lock_timeout) << + Arg::Gds(isc_obj_in_use) << Arg::Str(org_filename)); + } + + INI_upgrade(tdbb); + } + if (options.dpb_verify) { validateAccess(tdbb, attachment, USE_GFIX_UTILITY); @@ -3057,7 +3068,6 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch dbb->dbb_monitoring_data = FB_NEW_POOL(*dbb->dbb_permanent) MonitoringData(dbb); PAG_format_header(tdbb); - INI_init2(tdbb); PAG_format_pip(tdbb, *pageSpace); dbb->dbb_page_manager.initTempPageSpace(tdbb); @@ -3072,7 +3082,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch PAG_set_no_reserve(tdbb, options.dpb_no_reserve); fb_assert(attachment->att_user); // set by UserId::sclInit() - INI_format(attachment->getUserName().c_str(), options.dpb_set_db_charset.c_str()); + INI_format(tdbb, options.dpb_set_db_charset); // If we have not allocated first TIP page, do it now. if (!dbb->dbb_t_pages || !dbb->dbb_t_pages->count()) @@ -7243,6 +7253,9 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli case isc_dpb_worker_attach: dpb_worker_attach = true; + + case isc_dpb_upgrade_db: + dpb_upgrade_db = true; break; default: diff --git a/src/jrd/met.epp b/src/jrd/met.epp index e4563804f2d..a339a4cc125 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -1443,6 +1443,10 @@ Format* MET_format(thread_db* tdbb, jrd_rel* relation, USHORT number) return format; } + // System relations don't have their formats stored inside RDB$FORMATS, + // so it's absolutely pointless trying to find one there + fb_assert(!relation->isSystem()); + format = NULL; AutoCacheRequest request(tdbb, irq_r_format, IRQ_REQUESTS); @@ -3827,10 +3831,6 @@ jrd_rel* MET_relation(thread_db* tdbb, USHORT id) if (relation) return relation; - // From ODS 9 onwards, the first 128 relation IDS have been - // reserved for system relations - const USHORT max_sys_rel = USER_DEF_REL_INIT_ID - 1; - relation = FB_NEW_POOL(*pool) jrd_rel(*pool); (*vector)[id] = relation; relation->rel_id = id; @@ -3849,8 +3849,7 @@ jrd_rel* MET_relation(thread_db* tdbb, USHORT id) lock->setKey(relation->rel_id); } - // This should check system flag instead. - if (relation->rel_id <= max_sys_rel) + if (relation->rel_id < rel_MAX) return relation; { // Scope block. @@ -5561,10 +5560,8 @@ static bool verify_TRG_ignore_perm(thread_db* tdbb, const MetaName& trig_name) // See if this is a system trigger, with the flag set as TRG_ignore_perm - if (INI_get_trig_flags(trig_name.c_str()) & TRG_ignore_perm) - { + if (INI_get_trig_flags(trig_name) & TRG_ignore_perm) return true; - } // See if this is a RI trigger diff --git a/src/jrd/trig.h b/src/jrd/trig.h index dfe416a2aa0..c80683474ca 100644 --- a/src/jrd/trig.h +++ b/src/jrd/trig.h @@ -62,6 +62,7 @@ struct gen const char* gen_name; USHORT gen_id; const char* gen_description; + USHORT gen_ods_version; }; } //namespace Jrd @@ -70,18 +71,18 @@ struct gen // Keep in sync with constants.h static const Jrd::gen generators[] = { - { "RDB$SECURITY_CLASS", 1, NULL }, - { "SQL$DEFAULT", 2, NULL }, - { PROCEDURES_GENERATOR, 3, "Procedure ID" }, - { "RDB$EXCEPTIONS", 4, "Exception ID" }, - { "RDB$CONSTRAINT_NAME", 5, "Implicit constraint name" }, - { "RDB$FIELD_NAME", 6, "Implicit domain name" }, - { "RDB$INDEX_NAME", 7, "Implicit index name" }, - { "RDB$TRIGGER_NAME", 8, "Implicit trigger name" }, - { "RDB$BACKUP_HISTORY", 9, "Nbackup technology" }, - { FUNCTIONS_GENERATOR, 10, "Function ID" }, - { "RDB$GENERATOR_NAME", 11, "Implicit generator name" }, - { nullptr, 0, nullptr } + { "RDB$SECURITY_CLASS", 1, NULL, ODS_13_0 }, + { "SQL$DEFAULT", 2, NULL, ODS_13_0 }, + { PROCEDURES_GENERATOR, 3, "Procedure ID", ODS_13_0 }, + { "RDB$EXCEPTIONS", 4, "Exception ID", ODS_13_0 }, + { "RDB$CONSTRAINT_NAME", 5, "Implicit constraint name", ODS_13_0 }, + { "RDB$FIELD_NAME", 6, "Implicit domain name", ODS_13_0 }, + { "RDB$INDEX_NAME", 7, "Implicit index name", ODS_13_0 }, + { "RDB$TRIGGER_NAME", 8, "Implicit trigger name", ODS_13_0 }, + { "RDB$BACKUP_HISTORY", 9, "Nbackup technology", ODS_13_0 }, + { FUNCTIONS_GENERATOR, 10, "Function ID", ODS_13_0 }, + { "RDB$GENERATOR_NAME", 11, "Implicit generator name", ODS_13_0 }, + { nullptr, 0, nullptr, 0 } }; diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index d864f06eb83..7fc268e0f1d 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -5261,7 +5261,6 @@ void Database::garbage_collector(Database* dbb) { LCK_init(tdbb, LCK_OWNER_attachment); INI_init(tdbb); - INI_init2(tdbb); PAG_header(tdbb, true); PAG_attachment_id(tdbb); TRA_init(attachment);