From f7f98b661dc857bb98940d2b8d082caf681345c0 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Fri, 5 Feb 2021 16:32:23 +0300 Subject: [PATCH 1/7] Basic implementation of the ODS upgrade --- src/alice/alice.h | 1 - src/alice/aliceswi.h | 7 +- src/alice/exe.cpp | 3 + src/include/firebird/impl/consts_pub.h | 2 + src/include/gen/Firebird.pas | 2 + src/jrd/fields.h | 408 ++++++++++++------------- src/jrd/idx.h | 117 +++---- src/jrd/ini.epp | 301 ++++++++++++++---- src/jrd/ini.h | 13 +- src/jrd/ini_proto.h | 1 + src/jrd/jrd.cpp | 10 + src/jrd/trig.h | 25 +- 12 files changed, 551 insertions(+), 339 deletions(-) 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..e100fd46e1c 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, 136, 2, NULL}, + // msg 136: \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/gen/Firebird.pas b/src/include/gen/Firebird.pas index 20edfdc1b3b..ded7b8fac4d 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); diff --git a/src/jrd/fields.h b/src/jrd/fields.h index 16daf6292f9..c224a0e9418 100644 --- a/src/jrd/fields.h +++ b/src/jrd/fields.h @@ -22,208 +22,208 @@ */ -// 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) +// 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) - 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_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) diff --git a/src/jrd/idx.h b/src/jrd/idx.h index 7960bd7e331..9461e02499d 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,254 +55,254 @@ 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 }}, diff --git a/src/jrd/ini.epp b/src/jrd/ini.epp index c78fc409a5c..4881415dbb3 100644 --- a/src/jrd/ini.epp +++ b/src/jrd/ini.epp @@ -70,7 +70,7 @@ DATABASE DB = FILENAME "ODS.RDB"; const int FB_MAX_ACL_SIZE = 4096; -static void add_index_set(thread_db*); +static void add_index_set(thread_db*, USHORT = 0); 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, @@ -82,8 +82,9 @@ 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_relation(thread_db*, int, const char*, const char*, int, int, AutoRequest&); +static void store_relation_field(thread_db*, int, const char*, const char*, const char*, int, AutoRequest&); +static void store_packages(thread_db* tdbb, const MetaName& owner, USHORT = 0); 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); @@ -246,7 +247,7 @@ void INI_format(const char* owner, const char* charset) MetaName ownerName(owner); // Uppercase charset name - MetaName rdbCharSetName(charset && charset[0] ? charset : DEFAULT_DB_CHARACTER_SET_NAME); + MetaName charSetName(charset && charset[0] ? charset : DEFAULT_DB_CHARACTER_SET_NAME); const int* fld; @@ -267,35 +268,32 @@ void INI_format(const char* owner, const char* charset) // Store RELATIONS and RELATION_FIELDS - SLONG rdbRelationId; - MetaName rdbRelationName; - SLONG rdbFieldId; - SLONG rdbSystemFlag = RDB_system; - SLONG rdbRelationType; + AutoRequest handle1, handle2; - 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 << ")"; - - AutoPreparedStatement ps(attachment->prepareStatement(tdbb, transaction, sql)); - - 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) + int fieldId = 0; + + for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) { - const int* pFld = fld; - const int* pRelFld = relfld; - store_relation_field(tdbb, pFld, pRelFld, rdbFieldId, handle1); - ++rdbFieldId; + 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, handle1); + ++fieldId; } - rdbRelationId = relfld[RFLD_R_ID]; - rdbRelationName = names[relfld[RFLD_R_NAME]]; - rdbRelationType = relfld[RFLD_R_TYPE]; - ps->execute(tdbb, transaction); + 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, ownerName.c_str(), + fieldId, relType, handle2); } handle1.reset(); @@ -307,14 +305,13 @@ void INI_format(const char* owner, const char* charset) // Store DATABASE record - sql = PreparedStatement::Builder(); - sql << "insert into rdb$database (rdb$relation_id, rdb$character_set_name) values (" - << rdbRelationId << ", " << rdbCharSetName << ")"; - - ps.reset(attachment->prepareStatement(tdbb, transaction, sql)); + handle1.reset(); - rdbRelationId = USER_DEF_REL_INIT_ID; - ps->execute(tdbb, transaction); + STORE(REQUEST_HANDLE handle1) X IN RDB$DATABASE + X.RDB$RELATION_ID = (int) USER_DEF_REL_INIT_ID; + PAD(charSetName.c_str(), X.RDB$CHARACTER_SET_NAME); + X.RDB$CHARACTER_SET_NAME.NULL = FALSE; + END_STORE // Store default publication @@ -536,6 +533,7 @@ void INI_format(const char* owner, const char* charset) add_security_to_sys_obj(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, obj_database, "", length, buffer); } + // Add security on system tables const UCHAR REL_OWNER_ACL[] = @@ -571,10 +569,13 @@ void INI_format(const char* owner, const char* charset) AutoRequest reqModObjSC, reqInsUserPriv; 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) - ++rdbFieldId; + int fieldId = 0; + for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) + ++fieldId; + + const auto relName = names[relfld[RFLD_R_NAME]]; - add_security_to_sys_rel(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, names[relfld[RFLD_R_NAME]], length, buffer); + add_security_to_sys_rel(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, relName, length, buffer); } } @@ -923,7 +924,168 @@ void INI_init_dsql(thread_db* tdbb, dsql_dbb* database) } -static void add_index_set(thread_db* tdbb) +void INI_upgrade(thread_db* tdbb) +{ +/************************************** + * + * I N I _ u p g r a d e + * + ************************************** + * + * Functional description + * Upgrade minor ODS version. + * + **************************************/ + const auto dbb = tdbb->getDatabase(); + const auto attachment = tdbb->getAttachment(); + + // If database is read-only, punt + if (dbb->dbb_flags & DBB_read_only) + Arg::Gds(isc_read_only).raise(); + + // Check current ODS version to see if we have work to do + + const auto majorVersion = dbb->dbb_ods_version; + fb_assert(majorVersion == ODS_VERSION); + + const auto minorVersion = dbb->dbb_minor_version; + if (minorVersion == ODS_CURRENT) + return; + + const auto odsVersion = ENCODE_ODS(majorVersion, minorVersion); + + 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 && + 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 handle1, handle2; + + // Get the database owner + + MetaName ownerName; + + FOR(REQUEST_HANDLE handle1) + FIRST 1 REL IN RDB$RELATIONS + WITH REL.RDB$RELATION_NAME EQ "RDB$DATABASE" + { + fb_assert(!REL.RDB$OWNER_NAME.NULL); + ownerName = REL.RDB$OWNER_NAME; + } + END_FOR + + // Create global fields added after the original minor ODS + + handle1.reset(); + + for (const gfld* gfield = gfields; gfield->gfld_name; gfield++) + { + if (gfield->gfld_ods_version > odsVersion) + store_global_field(tdbb, gfield, handle1, ownerName); + } + + // Create new system relations and new relation fields + + handle1.reset(); + + 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) + { + if (fld[RFLD_F_ODS] > odsVersion) + { + 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, handle1); + } + + ++fieldId; + } + + if (relfld[RFLD_R_ODS] > odsVersion) + { + 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, ownerName.c_str(), + fieldId, relType, handle2); + } + } + + // Create new system indexes + + add_index_set(tdbb, odsVersion); + + // Create new system triggers and their trigger messages + + handle1.reset(); + + for (const jrd_trg* trigger = triggers; trigger->trg_relation; ++trigger) + { + if (trigger->trg_ods_version > odsVersion) + store_trigger(tdbb, trigger, handle1); + } + + handle1.reset(); + + for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message) + { + if (message->trg_ods_version > odsVersion) + store_message(tdbb, message, handle1); + } + + // Create new system generators + + handle1.reset(); + + for (const gen* generator = generators; generator->gen_name; generator++) + { + if (generator->gen_ods_version > odsVersion) + store_generator(tdbb, generator, handle1, ownerName); + } + + // Create new system packages + + store_packages(tdbb, ownerName, odsVersion); + + // Should we also add new types? They are collected from multiple sources and + // don't have their corresponding ODS defined. + // The same for new charsets/collations. + + // If the database was successfully updated, mark it with the current minor ODS + + win window(HEADER_PAGE_NUMBER); + auto header = (Ods::header_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_header); + CCH_MARK(tdbb, &window); + + dbb->dbb_minor_version = header->hdr_ods_minor = ODS_CURRENT; + CCH_RELEASE(tdbb, &window); + + DFW_perform_system_work(tdbb); +} + + +static void add_index_set(thread_db* tdbb, USHORT odsVersion) { /************************************** * @@ -932,9 +1094,8 @@ static void add_index_set(thread_db* tdbb) ************************************** * * 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). + * Add system indices. If odsVersion is specified, then we are performing + * an ODS update, so add only the indices marked as newer than odsVersion. * **************************************/ SET_TDBB(tdbb); @@ -949,6 +1110,9 @@ static void add_index_set(thread_db* tdbb) const ini_idx_t* index = &indices[n]; jrd_rel* 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); @@ -1679,11 +1843,37 @@ 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, + const char* ownerName, + int fieldId, + int relType, + AutoRequest& handle) +{ + SET_TDBB(tdbb); + const auto attachment = tdbb->getAttachment(); + + STORE(REQUEST_HANDLE handle) 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; + X.RDB$FIELD_ID = fieldId; + X.RDB$FORMAT = 0; + X.RDB$SYSTEM_FLAG = RDB_system; + X.RDB$DBKEY_LENGTH = 8; + + END_STORE; +} + +static void store_relation_field(thread_db* tdbb, + int fieldId, + const char* relName, + const char* fieldName, + const char* globalName, + int updateFlag, + AutoRequest& handle) { /************************************** * @@ -1701,28 +1891,25 @@ static void store_relation_field(thread_db* tdbb, STORE(REQUEST_HANDLE handle) 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, const MetaName& owner, 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; AutoRequest packageHandle, procedureHandle, procedureParameterHandle; AutoRequest functionHandle, functionReturnHandle, functionArgumentHandle; @@ -1731,7 +1918,7 @@ static void store_packages(thread_db* tdbb, const MetaName& owner) for (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 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..18740948796 100644 --- a/src/jrd/ini_proto.h +++ b/src/jrd/ini_proto.h @@ -35,5 +35,6 @@ 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 5cb75995a47..168b5ac842b 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 @@ -1835,6 +1836,12 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch dbb->dbb_tip_cache = FB_NEW_POOL(*dbb->dbb_permanent) TipCache(dbb); dbb->dbb_tip_cache->initializeTpc(tdbb); + if (options.dpb_upgrade_db) + { + validateAccess(tdbb, attachment, USE_GFIX_UTILITY); + INI_upgrade(tdbb); + } + // linger dbb->dbb_linger_seconds = MET_get_linger(tdbb); @@ -7248,6 +7255,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/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 } }; From baa1dc79be833919130a7d3d325da53269b60fd3 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Thu, 29 Sep 2022 14:48:54 +0300 Subject: [PATCH 2/7] Fixed invalid switch ID. Proper error reporting. Make upgrade revertable in the case of error. --- src/alice/aliceswi.h | 4 +- src/include/firebird/impl/msg/gfix.h | 1 + src/include/firebird/impl/msg/jrd.h | 1 + src/include/gen/Firebird.pas | 1 + src/jrd/ini.epp | 322 ++++++++++++++++++--------- src/jrd/ini_proto.h | 4 +- src/jrd/jrd.cpp | 20 +- src/jrd/met.epp | 4 +- 8 files changed, 234 insertions(+), 123 deletions(-) diff --git a/src/alice/aliceswi.h b/src/alice/aliceswi.h index e100fd46e1c..73ce96f8cda 100644 --- a/src/alice/aliceswi.h +++ b/src/alice/aliceswi.h @@ -262,8 +262,8 @@ static const Switches::in_sw_tab_t alice_in_sw_table[] = // 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, 136, 2, NULL}, - // msg 136: \t-upgrade\t\tupgrade database ODS + 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/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 1b8ea1a9fb8..2ae6d3688f7 100644 --- a/src/include/firebird/impl/msg/jrd.h +++ b/src/include/firebird/impl/msg/jrd.h @@ -961,3 +961,4 @@ FB_IMPL_MSG(JRD, 959, quoted_str_miss, -901, "22", "024", "Missing terminating q FB_IMPL_MSG(JRD, 960, wrong_shmem_ver, -902, "08", "006", "@1: inconsistent shared memory type/version; found @2, expected @3") FB_IMPL_MSG(JRD, 961, wrong_shmem_bitness, -902, "08", "006", "@1-bit engine can't open database already opened by @2-bit engine") 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, 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 ded7b8fac4d..30c6625de9c 100644 --- a/src/include/gen/Firebird.pas +++ b/src/include/gen/Firebird.pas @@ -5304,6 +5304,7 @@ IProfilerStatsImpl = class(IProfilerStats) isc_wrong_shmem_ver = 335545280; isc_wrong_shmem_bitness = 335545281; isc_wrong_proc_plan = 335545282; + isc_ods_upgrade_err = 335545283; isc_gfix_db_name = 335740929; isc_gfix_invalid_sw = 335740930; isc_gfix_incmp_sw = 335740932; diff --git a/src/jrd/ini.epp b/src/jrd/ini.epp index 4881415dbb3..7fe3fdeb2c4 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" @@ -223,7 +224,7 @@ static const trigger_msg trigger_messages[] = -void INI_format(const char* owner, const char* charset) +void INI_format(thread_db* tdbb, const string& charset) { /************************************** * @@ -237,17 +238,18 @@ void INI_format(const char* owner, const char* charset) * stored here. * **************************************/ - thread_db* tdbb = JRD_get_thread_data(); - Jrd::Attachment* attachment = tdbb->getAttachment(); - Database* const dbb = tdbb->getDatabase(); + const auto dbb = tdbb->getDatabase(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = attachment->getSysTransaction(); - fb_assert(owner && owner[0]); + tdbb->setTransaction(transaction); // Uppercase owner name - MetaName ownerName(owner); + const auto ownerName = attachment->getUserName(); + fb_assert(ownerName.hasData()); // Uppercase charset name - MetaName charSetName(charset && charset[0] ? charset : DEFAULT_DB_CHARACTER_SET_NAME); + MetaName charSetName(charset.hasData() ? charset : DEFAULT_DB_CHARACTER_SET_NAME); const int* fld; @@ -256,16 +258,12 @@ void INI_format(const char* owner, const char* charset) 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) ; } - jrd_tra* transaction = attachment->getSysTransaction(); - // Store RELATIONS and RELATION_FIELDS AutoRequest handle1, handle2; @@ -308,9 +306,11 @@ void INI_format(const char* owner, const char* charset) handle1.reset(); STORE(REQUEST_HANDLE handle1) X IN RDB$DATABASE + { X.RDB$RELATION_ID = (int) USER_DEF_REL_INIT_ID; PAD(charSetName.c_str(), X.RDB$CHARACTER_SET_NAME); X.RDB$CHARACTER_SET_NAME.NULL = FALSE; + } END_STORE // Store default publication @@ -356,11 +356,13 @@ void INI_format(const char* owner, const char* 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; } @@ -370,11 +372,13 @@ void INI_format(const char* owner, const char* charset) // 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; } @@ -593,29 +597,29 @@ void INI_format(const char* owner, const char* charset) for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message) store_message(tdbb, message, handle1); - handle1.reset(); - // 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()); + 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()); + 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()); + GRANT_privileges(tdbb, "RDB$DB_CREATORS", obj_relation, transaction); DFW_perform_system_work(tdbb); + + tdbb->setTransaction(nullptr); } -USHORT INI_get_trig_flags(const TEXT* trig_name) +USHORT INI_get_trig_flags(const MetaName& triggerName) { /********************************************* * @@ -629,13 +633,11 @@ USHORT INI_get_trig_flags(const TEXT* trig_name) **************************************/ 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; } @@ -655,11 +657,9 @@ void INI_init(thread_db* tdbb) * **************************************/ SET_TDBB(tdbb); - Database* const dbb = tdbb->getDatabase(); - CHECK_DBB(dbb); - - Jrd::Attachment* attachment = tdbb->getAttachment(); - MemoryPool* pool = attachment->att_pool; + const auto dbb = tdbb->getDatabase(); + const auto attachment = tdbb->getAttachment(); + const auto pool = attachment->att_pool; const int* fld; for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) @@ -741,7 +741,7 @@ void INI_init2(thread_db* tdbb) * **************************************/ SET_TDBB(tdbb); - Database* const dbb = tdbb->getDatabase(); + const auto dbb = tdbb->getDatabase(); const USHORT major_version = dbb->dbb_ods_version; const USHORT minor_version = dbb->dbb_minor_version; @@ -801,8 +801,8 @@ void INI_init2(thread_db* tdbb) 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; @@ -956,15 +956,19 @@ void INI_upgrade(thread_db* tdbb) const int* fld; + const auto transaction = TRA_start(tdbb, TRA_no_auto_undo, 0); + tdbb->setTransaction(transaction); + + const char* context = "tables"; + + try { + // 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) - { + 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) ; @@ -974,19 +978,22 @@ void INI_upgrade(thread_db* tdbb) // Get the database owner - MetaName ownerName; - - FOR(REQUEST_HANDLE handle1) - FIRST 1 REL IN RDB$RELATIONS - WITH REL.RDB$RELATION_NAME EQ "RDB$DATABASE" + auto ownerName = dbb->dbb_owner; + if (ownerName.isEmpty()) { - fb_assert(!REL.RDB$OWNER_NAME.NULL); - ownerName = REL.RDB$OWNER_NAME; + FOR(REQUEST_HANDLE handle1) + FIRST 1 REL IN RDB$RELATIONS + WITH REL.RDB$RELATION_NAME EQ "RDB$DATABASE" + { + fb_assert(!REL.RDB$OWNER_NAME.NULL); + ownerName = REL.RDB$OWNER_NAME; + } + END_FOR } - END_FOR // Create global fields added after the original minor ODS + context = "domains"; handle1.reset(); for (const gfld* gfield = gfields; gfield->gfld_name; gfield++) @@ -997,6 +1004,7 @@ void INI_upgrade(thread_db* tdbb) // Create new system relations and new relation fields + context = "tables"; handle1.reset(); for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) @@ -1034,10 +1042,12 @@ void INI_upgrade(thread_db* tdbb) // Create new system indexes + context = "indices"; add_index_set(tdbb, odsVersion); // Create new system triggers and their trigger messages + context = "triggers"; handle1.reset(); for (const jrd_trg* trigger = triggers; trigger->trg_relation; ++trigger) @@ -1046,6 +1056,7 @@ void INI_upgrade(thread_db* tdbb) store_trigger(tdbb, trigger, handle1); } + context = "trigger messages"; handle1.reset(); for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message) @@ -1056,6 +1067,7 @@ void INI_upgrade(thread_db* tdbb) // Create new system generators + context = "generators"; handle1.reset(); for (const gen* generator = generators; generator->gen_name; generator++) @@ -1064,13 +1076,47 @@ void INI_upgrade(thread_db* tdbb) store_generator(tdbb, generator, handle1, ownerName); } + // Adjust the value of the hidden generator RDB$GENERATORS + DPM_gen_id(tdbb, 0, true, FB_NELEM(generators) - 1); + // Create new system packages + context = "packages"; store_packages(tdbb, ownerName, odsVersion); - // Should we also add new types? They are collected from multiple sources and - // don't have their corresponding ODS defined. - // The same for new charsets/collations. + // 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. + + TRA_commit(tdbb, transaction, false); + + } + catch (const Exception& ex) + { + TRA_rollback(tdbb, transaction, false, true); + + // Delete relations we've just created + + for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) + { + 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); + } + + for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) + ; + } + + Arg::StatusVector error(ex); + error.prepend(Arg::Gds(isc_ods_upgrade_err) << Arg::Str(context)); + error.raise(); + } // If the database was successfully updated, mark it with the current minor ODS @@ -1080,8 +1126,6 @@ void INI_upgrade(thread_db* tdbb) dbb->dbb_minor_version = header->hdr_ods_minor = ODS_CURRENT; CCH_RELEASE(tdbb, &window); - - DFW_perform_system_work(tdbb); } @@ -1099,7 +1143,8 @@ static void add_index_set(thread_db* tdbb, USHORT odsVersion) * **************************************/ SET_TDBB(tdbb); - Jrd::Attachment* attachment = tdbb->getAttachment(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); index_desc idx; @@ -1116,7 +1161,9 @@ static void add_index_set(thread_db* tdbb, USHORT odsVersion) MetaName indexName; indexName.printf("RDB$INDEX_%d", index->ini_idx_index_id); - STORE(REQUEST_HANDLE handle1) X IN RDB$INDICES + STORE(REQUEST_HANDLE handle1 TRANSACTION_HANDLE transaction) + 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; @@ -1138,8 +1185,11 @@ static void add_index_set(thread_db* tdbb, USHORT odsVersion) index_desc::idx_repeat* tail = idx.idx_rpt; for (USHORT position = 0; position < index->ini_idx_segment_count; position++, tail++) { - const ini_idx_t::ini_idx_segment_t* segment = &index->ini_idx_segment[position]; - STORE(REQUEST_HANDLE handle2) Y IN RDB$INDEX_SEGMENTS + 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; @@ -1148,6 +1198,7 @@ static void add_index_set(thread_db* tdbb, USHORT odsVersion) tail->idx_field = segment->ini_idx_rfld_id; tail->idx_itype = segment->ini_idx_type; tail->idx_selectivity = 0; + } END_STORE } @@ -1156,20 +1207,24 @@ static void add_index_set(thread_db* tdbb, USHORT odsVersion) SelectivityList selectivity(*tdbb->getDefaultPool()); IDX_create_index(tdbb, relation, &idx, indexName.c_str(), NULL, - attachment->getSysTransaction(), selectivity); + transaction, selectivity); X.RDB$INDEX_ID = idx.idx_id + 1; + } END_STORE if (index->ini_idx_flags & idx_unique) { - STORE(REQUEST_HANDLE handle3) RC IN RDB$RELATION_CONSTRAINTS + STORE(REQUEST_HANDLE handle3 TRANSACTION_HANDLE transaction) + 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 } } @@ -1202,10 +1257,11 @@ static void add_security_to_sys_rel(thread_db* tdbb, * privilege. * **************************************/ - MetaName security_class, default_class; - SET_TDBB(tdbb); - Jrd::Attachment* attachment = tdbb->getAttachment(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); + + MetaName security_class, default_class; security_class.printf("%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, DPM_gen_id(tdbb, MET_lookup_generator(tdbb, SQL_SECCLASS_GENERATOR), false, 1)); @@ -1217,7 +1273,8 @@ static void add_security_to_sys_rel(thread_db* tdbb, add_security_class(tdbb, reqAddSC, security_class, acl_length, acl); add_security_class(tdbb, reqAddSC, default_class, acl_length, acl); - FOR(REQUEST_HANDLE reqModObjSC) REL IN RDB$RELATIONS + FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) + REL IN RDB$RELATIONS WITH REL.RDB$RELATION_NAME EQ rel_name { MODIFY REL USING @@ -1232,7 +1289,9 @@ static void add_security_to_sys_rel(thread_db* tdbb, for (int cnt = 0; cnt < 6; cnt++) { - STORE(REQUEST_HANDLE reqInsUserPriv) PRIV IN RDB$USER_PRIVILEGES + STORE(REQUEST_HANDLE reqInsUserPriv TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + { switch (cnt) { case 0: @@ -1272,6 +1331,7 @@ static void add_security_to_sys_rel(thread_db* tdbb, PRIV.RDB$FIELD_NAME.NULL = TRUE; PRIV.RDB$USER_TYPE = obj_user; PRIV.RDB$OBJECT_TYPE = obj_relation; + } END_STORE } } @@ -1289,7 +1349,8 @@ static void add_security_to_sys_obj(thread_db* tdbb, const UCHAR* acl) { SET_TDBB(tdbb); - Jrd::Attachment* const attachment = tdbb->getAttachment(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); MetaName security_class; security_class.printf("%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, @@ -1301,7 +1362,8 @@ static void add_security_to_sys_obj(thread_db* tdbb, if (obj_type == obj_field) { - FOR(REQUEST_HANDLE reqModObjSC) FLD IN RDB$FIELDS + FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) + FLD IN RDB$FIELDS WITH FLD.RDB$FIELD_NAME EQ obj_name.c_str() { MODIFY FLD USING @@ -1315,7 +1377,8 @@ static void add_security_to_sys_obj(thread_db* tdbb, } else if (obj_type == obj_charset) { - FOR(REQUEST_HANDLE reqModObjSC) CS IN RDB$CHARACTER_SETS + FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) + CS IN RDB$CHARACTER_SETS WITH CS.RDB$CHARACTER_SET_NAME EQ obj_name.c_str() { MODIFY CS USING @@ -1329,7 +1392,8 @@ static void add_security_to_sys_obj(thread_db* tdbb, } else if (obj_type == obj_collation) { - FOR(REQUEST_HANDLE reqModObjSC) COLL IN RDB$COLLATIONS + FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) + COLL IN RDB$COLLATIONS WITH COLL.RDB$COLLATION_NAME EQ obj_name.c_str() { MODIFY COLL USING @@ -1343,7 +1407,8 @@ static void add_security_to_sys_obj(thread_db* tdbb, } else if (obj_type == obj_exception) { - FOR(REQUEST_HANDLE reqModObjSC) XCP IN RDB$EXCEPTIONS + FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) + XCP IN RDB$EXCEPTIONS WITH XCP.RDB$EXCEPTION_NAME EQ obj_name.c_str() { MODIFY XCP USING @@ -1357,7 +1422,8 @@ static void add_security_to_sys_obj(thread_db* tdbb, } else if (obj_type == obj_generator) { - FOR(REQUEST_HANDLE reqModObjSC) GEN IN RDB$GENERATORS + FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) + GEN IN RDB$GENERATORS WITH GEN.RDB$GENERATOR_NAME EQ obj_name.c_str() { MODIFY GEN USING @@ -1371,7 +1437,8 @@ static void add_security_to_sys_obj(thread_db* tdbb, } else if (obj_type == obj_sql_role) { - FOR(REQUEST_HANDLE reqModObjSC) R IN RDB$ROLES + FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) + R IN RDB$ROLES WITH R.RDB$ROLE_NAME EQ obj_name.c_str() { MODIFY R USING @@ -1383,7 +1450,8 @@ static void add_security_to_sys_obj(thread_db* tdbb, } else if (obj_type == obj_package_header) { - FOR(REQUEST_HANDLE reqModObjSC) PKG IN RDB$PACKAGES + FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) + PKG IN RDB$PACKAGES WITH PKG.RDB$PACKAGE_NAME EQ obj_name.c_str() { MODIFY PKG USING @@ -1397,7 +1465,8 @@ static void add_security_to_sys_obj(thread_db* tdbb, } else if (obj_type == obj_database) { - FOR(REQUEST_HANDLE reqModObjSC) DB IN RDB$DATABASE + FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) + DB IN RDB$DATABASE { MODIFY DB USING DB.RDB$SECURITY_CLASS.NULL = FALSE; @@ -1421,7 +1490,9 @@ static void add_security_to_sys_obj(thread_db* tdbb, for (const char* p = privileges; *p; ++p) { - STORE(REQUEST_HANDLE reqInsUserPriv) PRIV IN RDB$USER_PRIVILEGES + STORE(REQUEST_HANDLE reqInsUserPriv TRANSACTION_HANDLE transaction) + 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; @@ -1430,6 +1501,7 @@ static void add_security_to_sys_obj(thread_db* tdbb, PRIV.RDB$USER_TYPE = obj_user; PRIV.RDB$OBJECT_TYPE = obj_type; PRIV.RDB$GRANTOR.NULL = TRUE; + } END_STORE } } @@ -1439,12 +1511,16 @@ static void add_security_to_sys_obj(thread_db* tdbb, 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 + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); + AutoRequest handle; while (*prvl) { - STORE(REQUEST_HANDLE handle) PRIV IN RDB$USER_PRIVILEGES + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + { PAD(user, PRIV.RDB$USER); PAD(object, PRIV.RDB$RELATION_NAME); @@ -1463,6 +1539,7 @@ static void store_admin_grant(thread_db* tdbb, const char* user, USHORT user_typ PRIV.RDB$USER_TYPE = user_type; PRIV.RDB$OBJECT_TYPE = object_type; PRIV.RDB$GRANTOR.NULL = TRUE; + } END_STORE } } @@ -1490,8 +1567,9 @@ static void store_admin_role(thread_db* tdbb, const MetaName& roleName, MetaName sql << "insert into rdb$roles(rdb$role_name, rdb$owner_name, rdb$system_flag, rdb$system_privileges)" << "values (" << roleName << "," << ownerName << ", 1," << p << ")"; - Attachment* attachment = tdbb->getAttachment(); - jrd_tra* transaction = attachment->getSysTransaction(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); + AutoPreparedStatement ps(attachment->prepareStatement(tdbb, transaction, sql)); ps->execute(tdbb, transaction); } @@ -1499,10 +1577,13 @@ static void store_admin_role(thread_db* tdbb, const MetaName& roleName, MetaName 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; @@ -1527,13 +1608,13 @@ static void store_default_pub(thread_db* tdbb, const MetaName& ownerName) static void add_security_class(thread_db* tdbb, AutoRequest& handle, const MetaName& class_name, USHORT acl_length, const UCHAR* acl) { SET_TDBB(tdbb); - Jrd::Attachment* const attachment = tdbb->getAttachment(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); bid blob_id; - attachment->storeBinaryBlob(tdbb, attachment->getSysTransaction(), &blob_id, - ByteChunk(acl, acl_length)); + attachment->storeBinaryBlob(tdbb, transaction, &blob_id, ByteChunk(acl, acl_length)); - STORE(REQUEST_HANDLE handle) + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) CLS IN RDB$SECURITY_CLASSES { PAD(class_name.c_str(), CLS.RDB$SECURITY_CLASS); @@ -1558,9 +1639,11 @@ static void store_generator(thread_db* tdbb, const gen* generator, AutoRequest& * **************************************/ SET_TDBB(tdbb); - Jrd::Attachment* attachment = tdbb->getAttachment(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); - 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; @@ -1572,7 +1655,7 @@ static void store_generator(thread_db* tdbb, const gen* generator, AutoRequest& 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; } @@ -1600,9 +1683,11 @@ static void store_global_field(thread_db* tdbb, const gfld* gfield, AutoRequest& * **************************************/ SET_TDBB(tdbb); - Jrd::Attachment* attachment = tdbb->getAttachment(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); - STORE(REQUEST_HANDLE handle) X IN RDB$FIELDS + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + X IN RDB$FIELDS { PAD(names[(USHORT)gfield->gfld_name], X.RDB$FIELD_NAME); X.RDB$FIELD_LENGTH = gfield->gfld_length; @@ -1618,7 +1703,7 @@ static void store_global_field(thread_db* tdbb, const gfld* gfield, AutoRequest& 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; } @@ -1756,14 +1841,16 @@ static void store_intlnames(thread_db* tdbb, const MetaName& owner) * **************************************/ SET_TDBB(tdbb); - Jrd::Attachment* attachment = tdbb->getAttachment(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); AutoRequest handle; for (const IntlManager::CharSetDefinition* charSet = IntlManager::defaultCharSets; charSet->name; ++charSet) { - STORE(REQUEST_HANDLE handle) X IN RDB$CHARACTER_SETS USING + 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); @@ -1782,7 +1869,8 @@ 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 + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + X IN RDB$COLLATIONS USING { PAD(collation->name, X.RDB$COLLATION_NAME); @@ -1804,7 +1892,7 @@ static void store_intlnames(thread_db* tdbb, const MetaName& owner) if (collation->specificAttributes) { - attachment->storeMetaDataBlob(tdbb, attachment->getSysTransaction(), + attachment->storeMetaDataBlob(tdbb, transaction, &X.RDB$SPECIFIC_ATTRIBUTES, collation->specificAttributes); X.RDB$SPECIFIC_ATTRIBUTES.NULL = FALSE; } @@ -1829,11 +1917,13 @@ static void store_message(thread_db* tdbb, const trigger_msg* message, AutoReque * **************************************/ 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; @@ -1853,8 +1943,11 @@ static void store_relation(thread_db* tdbb, { SET_TDBB(tdbb); const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); - STORE(REQUEST_HANDLE handle) X IN RDB$RELATIONS + 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); @@ -1863,7 +1956,7 @@ static void store_relation(thread_db* tdbb, X.RDB$FORMAT = 0; X.RDB$SYSTEM_FLAG = RDB_system; X.RDB$DBKEY_LENGTH = 8; - + } END_STORE; } @@ -1887,9 +1980,11 @@ static void store_relation_field(thread_db* tdbb, * **************************************/ SET_TDBB(tdbb); - Jrd::Attachment* attachment = tdbb->getAttachment(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); - STORE(REQUEST_HANDLE handle) X IN RDB$RELATION_FIELDS + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + X IN RDB$RELATION_FIELDS { PAD(relName, X.RDB$RELATION_NAME); PAD(fieldName, X.RDB$FIELD_NAME); @@ -1908,8 +2003,9 @@ static void store_relation_field(thread_db* tdbb, static void store_packages(thread_db* tdbb, const MetaName& owner, USHORT odsVersion) { SET_TDBB(tdbb); - Jrd::Attachment* attachment = tdbb->getAttachment(); - Database* const dbb = tdbb->getDatabase(); + const auto dbb = tdbb->getDatabase(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); AutoRequest packageHandle, procedureHandle, procedureParameterHandle; AutoRequest functionHandle, functionReturnHandle, functionArgumentHandle; @@ -1918,10 +2014,11 @@ static void store_packages(thread_db* tdbb, const MetaName& owner, USHORT odsVer for (auto& systemPackage : SystemPackage::get()) { - if (odsVersion && systemPackage.odsVersion < odsVersion) + if (odsVersion && systemPackage.odsVersion <= odsVersion) continue; - STORE (REQUEST_HANDLE packageHandle) PKG IN RDB$PACKAGES + STORE (REQUEST_HANDLE packageHandle TRANSACTION_HANDLE transaction) + PKG IN RDB$PACKAGES { PAD(systemPackage.name, PKG.RDB$PACKAGE_NAME); @@ -1933,7 +2030,8 @@ static void store_packages(thread_db* tdbb, const MetaName& owner, USHORT odsVer for (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); @@ -1960,7 +2058,8 @@ static void store_packages(thread_db* tdbb, const MetaName& owner, USHORT odsVer { ++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); @@ -1979,7 +2078,7 @@ static void store_packages(thread_db* tdbb, const MetaName& owner, USHORT odsVer 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; @@ -1988,7 +2087,7 @@ static void store_packages(thread_db* tdbb, const MetaName& owner, USHORT odsVer 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; } @@ -2005,7 +2104,8 @@ static void store_packages(thread_db* tdbb, const MetaName& owner, USHORT odsVer for (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); @@ -2024,7 +2124,8 @@ static void store_packages(thread_db* tdbb, const MetaName& owner, USHORT odsVer 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); @@ -2042,7 +2143,8 @@ static void store_packages(thread_db* tdbb, const MetaName& owner, USHORT odsVer { ++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); @@ -2059,7 +2161,7 @@ static void store_packages(thread_db* tdbb, const MetaName& owner, USHORT odsVer 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; @@ -2068,7 +2170,7 @@ static void store_packages(thread_db* tdbb, const MetaName& owner, USHORT odsVer 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; } @@ -2099,7 +2201,8 @@ static void store_trigger(thread_db* tdbb, const jrd_trg* trigger, AutoRequest& * **************************************/ SET_TDBB(tdbb); - Attachment* attachment = tdbb->getAttachment(); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); // indicate that the relation format needs revising dsc desc; @@ -2109,7 +2212,8 @@ static void store_trigger(thread_db* tdbb, const jrd_trg* trigger, AutoRequest& // 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); @@ -2118,7 +2222,7 @@ 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 diff --git a/src/jrd/ini_proto.h b/src/jrd/ini_proto.h index 18740948796..5f6b1c1c942 100644 --- a/src/jrd/ini_proto.h +++ b/src/jrd/ini_proto.h @@ -29,8 +29,8 @@ 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); diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 168b5ac842b..9068661f069 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -1836,12 +1836,6 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch dbb->dbb_tip_cache = FB_NEW_POOL(*dbb->dbb_permanent) TipCache(dbb); dbb->dbb_tip_cache->initializeTpc(tdbb); - if (options.dpb_upgrade_db) - { - validateAccess(tdbb, attachment, USE_GFIX_UTILITY); - INI_upgrade(tdbb); - } - // linger dbb->dbb_linger_seconds = MET_get_linger(tdbb); @@ -2065,6 +2059,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); @@ -3079,7 +3085,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()) diff --git a/src/jrd/met.epp b/src/jrd/met.epp index e4563804f2d..5171de13aba 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -5561,10 +5561,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 From d70e43755795373b836c03563b338feaf5b9be01 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Wed, 16 Nov 2022 15:07:36 +0300 Subject: [PATCH 3/7] Refactor ACL and privileges manegement during database creation and upgrade. Fixed incorrect owner permissions for system packages. --- src/jrd/ini.epp | 2177 ++++++++++++++++++++++++----------------------- 1 file changed, 1107 insertions(+), 1070 deletions(-) diff --git a/src/jrd/ini.epp b/src/jrd/ini.epp index 7fe3fdeb2c4..a626843d060 100644 --- a/src/jrd/ini.epp +++ b/src/jrd/ini.epp @@ -67,599 +67,922 @@ 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; - - -static void add_index_set(thread_db*, USHORT = 0); -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(thread_db*, int, const char*, const char*, int, int, AutoRequest&); -static void store_relation_field(thread_db*, int, const char*, const char*, const char*, int, AutoRequest&); -static void store_packages(thread_db* tdbb, const MetaName& owner, USHORT = 0); -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[] = +namespace { - { "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 } -}; - + template void PAD(const char* string, TEXT (&field)[N]) + { + jrd_vtof(string, (char*) field, sizeof(field)); + } + template void PAD(const MetaName& name, TEXT (&field)[N]) + { + jrd_vtof(name.c_str(), (char*) field, sizeof(field)); + } -void INI_format(thread_db* tdbb, const string& 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. - * - **************************************/ - const auto dbb = tdbb->getDatabase(); - const auto attachment = tdbb->getAttachment(); - const auto transaction = attachment->getSysTransaction(); + // 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 - tdbb->setTransaction(transaction); + 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 - const auto ownerName = attachment->getUserName(); - fb_assert(ownerName.hasData()); + case dsc_text_type_ascii: + charSet = CS_ASCII; + break; - // Uppercase charset name - MetaName charSetName(charset.hasData() ? 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) - DPM_create_relation(tdbb, MET_relation(tdbb, relfld[RFLD_R_ID])); + for (const gen* generator = generators; generator->gen_name; generator++) + { + 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; } - // Store RELATIONS and RELATION_FIELDS - - AutoRequest handle1, handle2; - - for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) + void storeGrant(thread_db* tdbb, const char* user, USHORT user_type, + const char* object, USHORT object_type, const char* prvl) { - int fieldId = 0; + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); - 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]; + AutoRequest handle; - store_relation_field(tdbb, fieldId, relName, fieldName, globalName, - updateFlag, handle1); - ++fieldId; + 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 } + } - const auto relId = relfld[RFLD_R_ID]; - const auto relName = names[relfld[RFLD_R_NAME]]; - const auto relType = relfld[RFLD_R_TYPE]; + class SecurityHelper + { + static const unsigned FB_MAX_ACL_SIZE = 4096; - store_relation(tdbb, relId, relName, ownerName.c_str(), - fieldId, relType, handle2); - } + public: + SecurityHelper(const MetaName& ownerName, AutoRequest& handle) + : userName(ownerName), reqAddSC(handle) + {} - handle1.reset(); + const char* getOwnerName() const + { + return userName.c_str(); + } - // Store global FIELDS + void addSecurityClass(thread_db* tdbb, const MetaName& className) + { + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); - for (const gfld* gfield = gfields; gfield->gfld_name; gfield++) - store_global_field(tdbb, gfield, handle1, ownerName); + bid blobId; + attachment->storeBinaryBlob(tdbb, transaction, &blobId, ByteChunk(buffer, length)); - // Store DATABASE record + STORE(REQUEST_HANDLE reqAddSC TRANSACTION_HANDLE transaction) + CLS IN RDB$SECURITY_CLASSES + { + PAD(className, CLS.RDB$SECURITY_CLASS); + CLS.RDB$ACL = blobId; + } + END_STORE + } - handle1.reset(); + protected: + UCHAR buffer[FB_MAX_ACL_SIZE]; + ULONG length = 0; - STORE(REQUEST_HANDLE handle1) X IN RDB$DATABASE + private: + const MetaName userName; + AutoRequest& reqAddSC; + }; + + class RelationSecurity : public SecurityHelper { - X.RDB$RELATION_ID = (int) USER_DEF_REL_INIT_ID; - PAD(charSetName.c_str(), X.RDB$CHARACTER_SET_NAME); - X.RDB$CHARACTER_SET_NAME.NULL = FALSE; - } - END_STORE + public: + RelationSecurity(const MetaName& ownerName, AutoRequest& handle) + : SecurityHelper(ownerName, handle) + { + const size_t ownerNameLength = ownerName.length(); + fb_assert(ownerNameLength <= MAX_UCHAR); - // Store default publication + const UCHAR REL_OWNER_ACL[] = + {ACL_priv_list, priv_control, priv_alter, priv_drop, + priv_select, priv_insert, priv_update, priv_delete, ACL_end}; - store_default_pub(tdbb, ownerName); + const UCHAR REL_PUBLIC_ACL[] = + {ACL_priv_list, priv_select, ACL_end}; - // Store system role + fb_assert(sizeof(buffer) >= 8 + ownerNameLength + + sizeof(REL_OWNER_ACL) + sizeof(REL_PUBLIC_ACL)); - store_admin_role(tdbb, ADMIN_ROLE, ownerName, NULL); + UCHAR* acl = buffer; + *acl++ = ACL_version; + *acl++ = ACL_id_list; - // Store grants of admin role to valuable users + *acl++ = id_person; - store_admin_role_grant(tdbb, DBA_USER_NAME); - if (ownerName != DBA_USER_NAME) - store_admin_role_grant(tdbb, ownerName.c_str()); + *acl++ = (UCHAR) ownerNameLength; + memcpy(acl, ownerName.c_str(), ownerNameLength); + acl += ownerNameLength; - // Create indices for system relations + *acl++ = ACL_end; - add_index_set(tdbb); + memcpy(acl, REL_OWNER_ACL, sizeof(REL_OWNER_ACL)); + acl += sizeof(REL_OWNER_ACL); - // Create parameter types + *acl++ = ACL_id_list; + *acl++ = ACL_end; - handle1.reset(); + memcpy(acl, REL_PUBLIC_ACL, sizeof(REL_PUBLIC_ACL)); + acl += sizeof(REL_PUBLIC_ACL); - for (const rtyp* type = types; type->rtyp_name; ++type) - { - // this STORE should be compatible with two below, - // as they use the same compiled request - STORE(REQUEST_HANDLE handle1) X IN RDB$TYPES - { - PAD(names[type->rtyp_field], X.RDB$FIELD_NAME); - PAD(type->rtyp_name, X.RDB$TYPE_NAME); - X.RDB$TYPE = type->rtyp_value; - X.RDB$SYSTEM_FLAG = RDB_system; - X.RDB$SYSTEM_FLAG.NULL = FALSE; - } - END_STORE - } + *acl++ = ACL_end; // Extra terminator to avoid scl.epp:walk_acl() missing the end - 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; + length = acl - buffer; } - END_STORE; - } - for (const IntlManager::CharSetAliasDefinition* alias = IntlManager::defaultCharSetAliases; - alias->name; ++alias) - { - // this STORE should be compatible with two above, - // as they use the same compiled request - STORE(REQUEST_HANDLE handle1) X IN RDB$TYPES + void storeSecurityClass(thread_db* tdbb, MetaName& securityClass, MetaName& defaultClass) { - 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; - } + securityClass.printf("%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, + DPM_gen_id(tdbb, lookupGenerator(SQL_SECCLASS_GENERATOR), false, 1)); - // Store symbols for international character sets & collations - store_intlnames(tdbb, ownerName); - - // Create system generators + defaultClass.printf("%s%" SQUADFORMAT, DEFAULT_CLASS, + DPM_gen_id(tdbb, lookupGenerator(DEFAULT_CLASS), false, 1)); - handle1.reset(); + addSecurityClass(tdbb, securityClass); + addSecurityClass(tdbb, defaultClass); + } - for (const gen* generator = generators; generator->gen_name; generator++) - store_generator(tdbb, generator, handle1, ownerName); + void storePrivileges(thread_db* tdbb, const char* relName) + { + // Only the owner of the database has SELECT/INSERT/UPDATE/DELETE privileges + // on any system relations. Any other users only has SELECT privilege. - // Adjust the value of the hidden generator RDB$GENERATORS - DPM_gen_id(tdbb, 0, true, FB_NELEM(generators) - 1); + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); - store_packages(tdbb, ownerName); + const auto userName = getOwnerName(); - const size_t ownerNameLength = ownerName.length(); - fb_assert(ownerNameLength <= MAX_UCHAR); + 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; + } - // Add security for the non-relation system metadata objects + 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 + } + } - const UCHAR NON_REL_OWNER_ACL[] = - {ACL_priv_list, priv_control, priv_alter, priv_drop, priv_usage, ACL_end}; + private: + AutoRequest handle; + }; - const UCHAR NON_REL_PUBLIC_USAGE_ACL[] = - {ACL_priv_list, priv_usage, ACL_end}; + class NonRelationSecurity : public SecurityHelper + { + public: + NonRelationSecurity(const MetaName& ownerName, AutoRequest& handle, bool package) + : SecurityHelper(ownerName, handle) + { + const size_t ownerNameLength = ownerName.length(); + fb_assert(ownerNameLength <= MAX_UCHAR); - const UCHAR PKG_PUBLIC_EXECUTE_ACL[] = - {ACL_priv_list, priv_execute, ACL_end}; + const UCHAR privilege = package ? priv_execute : priv_usage; - UCHAR buffer[FB_MAX_ACL_SIZE]; - UCHAR* acl = buffer; - *acl++ = ACL_version; - *acl++ = ACL_id_list; - *acl++ = id_person; + const UCHAR NON_REL_OWNER_ACL[] = + {ACL_priv_list, priv_control, priv_alter, priv_drop, privilege, ACL_end}; - *acl++ = (UCHAR) ownerNameLength; - memcpy(acl, ownerName.c_str(), ownerNameLength); - acl += ownerNameLength; + const UCHAR NON_REL_PUBLIC_ACL[] = + {ACL_priv_list, privilege, ACL_end}; - *acl++ = ACL_end; + fb_assert(sizeof(buffer) >= 8 + ownerNameLength + + sizeof(NON_REL_OWNER_ACL) + sizeof(NON_REL_PUBLIC_ACL)); - memcpy(acl, NON_REL_OWNER_ACL, sizeof(NON_REL_OWNER_ACL)); - acl += sizeof(NON_REL_OWNER_ACL); + UCHAR* acl = buffer; + *acl++ = ACL_version; + *acl++ = ACL_id_list; + *acl++ = id_person; - *acl++ = ACL_id_list; - *acl++ = ACL_end; + *acl++ = (UCHAR) ownerNameLength; + memcpy(acl, ownerName.c_str(), ownerNameLength); + acl += ownerNameLength; - UCHAR* aclPublicStart = acl; + *acl++ = ACL_end; - 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. + memcpy(acl, NON_REL_OWNER_ACL, sizeof(NON_REL_OWNER_ACL)); + acl += sizeof(NON_REL_OWNER_ACL); - USHORT length = acl - buffer; + *acl++ = ACL_id_list; + *acl++ = ACL_end; - AutoRequest reqAddSC; + memcpy(acl, NON_REL_PUBLIC_ACL, sizeof(NON_REL_PUBLIC_ACL)); + acl += sizeof(NON_REL_PUBLIC_ACL); - { // scope - AutoRequest reqModObjSC, reqInsUserPriv; + *acl++ = ACL_end; // Extra terminator to avoid scl.epp:walk_acl() missing the end - 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); + length = acl - buffer; } - reqModObjSC.reset(); - for (const gen* generator = generators; generator->gen_name; generator++) + MetaName storeSecurityClass(thread_db* tdbb) { - add_security_to_sys_obj(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, obj_generator, - generator->gen_name, length, buffer); - } + MetaName securityClass; + securityClass.printf("%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, + DPM_gen_id(tdbb, lookupGenerator(SQL_SECCLASS_GENERATOR), false, 1)); - reqModObjSC.reset(); - for (const IntlManager::CharSetDefinition* charset = IntlManager::defaultCharSets; - charset->name; - ++charset) - { - add_security_to_sys_obj(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, obj_charset, - charset->name, length, buffer); - } + addSecurityClass(tdbb, securityClass); - reqModObjSC.reset(); - for (const IntlManager::CollationDefinition* collation = IntlManager::defaultCollations; - collation->name; - ++collation) - { - add_security_to_sys_obj(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, obj_collation, - collation->name, length, buffer); + return securityClass; } - reqModObjSC.reset(); - add_security_to_sys_obj(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, obj_sql_role, - ADMIN_ROLE, length, buffer); - - // 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; - - reqModObjSC.reset(); - for (auto& systemPackage : SystemPackage::get()) + void storePrivileges(thread_db* tdbb, const char* objName, ObjectType objType) { - if (systemPackage.odsVersion > ENCODE_ODS(dbb->dbb_ods_version, dbb->dbb_minor_version)) - continue; + // Add security to system objects - add_security_to_sys_obj(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, - obj_package_header, systemPackage.name, length, buffer); - } - } + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); - // Add default DDL security + const char* privileges = nullptr; - const UCHAR DDL_OWNER_ACL[] = - {ACL_priv_list, priv_control, priv_alter, priv_drop, ACL_end}; + switch (objType) + { + case obj_field: + case obj_charset: + case obj_collation: + case obj_exception: + case obj_generator: + privileges = USAGE_PRIVILEGES; + break; - const UCHAR DDL_PUBLIC_ACL[] = - {ACL_priv_list, ACL_end}; + case obj_package_header: + privileges = EXEC_PRIVILEGES; + break; - acl = buffer; - *acl++ = ACL_version; - *acl++ = ACL_id_list; - *acl++ = id_person; + default: + fb_assert(false); + } - *acl++ = (UCHAR) ownerNameLength; - memcpy(acl, ownerName.c_str(), ownerNameLength); - acl += ownerNameLength; + fb_assert(privileges && privileges[0] && !privileges[1]); - *acl++ = ACL_end; + auto userName = getOwnerName(); + fb_assert(userName && *userName); + fb_assert(objName); - memcpy(acl, DDL_OWNER_ACL, sizeof(DDL_OWNER_ACL)); - acl += sizeof(DDL_OWNER_ACL); + const char* users[] = {userName, "PUBLIC"}; + int grantOptions[] = {WITH_GRANT_OPTION, 0}; - *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. + 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 + } + } - length = acl - buffer; + private: + AutoRequest handle; + }; - for (int obj = obj_database + 1; obj < obj_type_MAX; obj++) + class RoleSecurity : public SecurityHelper { - if (isDdlObject(obj)) - add_security_class(tdbb, reqAddSC, getSecurityClassName(obj), length, buffer); - } + public: + RoleSecurity(const MetaName& ownerName, AutoRequest& handle) + : SecurityHelper(ownerName, handle) + { + const size_t ownerNameLength = ownerName.length(); + fb_assert(ownerNameLength <= MAX_UCHAR); - { // scope - AutoRequest reqModObjSC, reqInsUserPriv; + const UCHAR ROLE_OWNER_ACL[] = + {ACL_priv_list, priv_control, priv_alter, priv_drop, priv_usage, ACL_end}; - add_security_to_sys_obj(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, obj_database, - "", length, buffer); - } + fb_assert(sizeof(buffer) >= 6 + ownerNameLength + sizeof(ROLE_OWNER_ACL)); - // Add security on system tables + UCHAR* acl = buffer; + *acl++ = ACL_version; + *acl++ = ACL_id_list; + *acl++ = id_person; - const UCHAR REL_OWNER_ACL[] = - {ACL_priv_list, priv_control, priv_alter, priv_drop, - priv_select, priv_insert, priv_update, priv_delete, ACL_end}; + *acl++ = (UCHAR) ownerNameLength; + memcpy(acl, ownerName.c_str(), ownerNameLength); + acl += ownerNameLength; - const UCHAR REL_PUBLIC_ACL[] = - {ACL_priv_list, priv_select, ACL_end}; + *acl++ = ACL_end; - acl = buffer; - *acl++ = ACL_version; - *acl++ = ACL_id_list; - *acl++ = id_person; + memcpy(acl, ROLE_OWNER_ACL, sizeof(ROLE_OWNER_ACL)); + acl += sizeof(ROLE_OWNER_ACL); - *acl++ = (UCHAR) ownerNameLength; - memcpy(acl, ownerName.c_str(), ownerNameLength); - acl += ownerNameLength; + *acl++ = ACL_end; // Extra terminator to avoid scl.epp:walk_acl() missing the end - *acl++ = ACL_end; + length = acl - buffer; + } - memcpy(acl, REL_OWNER_ACL, sizeof(REL_OWNER_ACL)); - acl += sizeof(REL_OWNER_ACL); + 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_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. + addSecurityClass(tdbb, securityClass); - length = acl - buffer; + return securityClass; + } - { // scope - AutoRequest reqModObjSC, reqInsUserPriv; - for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) + void storePrivileges(thread_db* tdbb, const char* objName) { - int fieldId = 0; - for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) - ++fieldId; + // Add security to system roles - const auto relName = names[relfld[RFLD_R_NAME]]; + const auto attachment = tdbb->getAttachment(); + const auto transaction = tdbb->getTransaction(); - add_security_to_sys_rel(tdbb, reqAddSC, reqModObjSC, reqInsUserPriv, ownerName, relName, length, buffer); + 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 + } } - } - // store system-defined triggers + private: + AutoRequest handle; + }; - handle1.reset(); + 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); - for (const jrd_trg* trigger = triggers; trigger->trg_relation; ++trigger) - store_trigger(tdbb, trigger, handle1); + const UCHAR DDL_OWNER_ACL[] = + {ACL_priv_list, priv_control, priv_alter, priv_drop, ACL_end}; - // store trigger messages to go with triggers + const UCHAR DDL_PUBLIC_ACL[] = + {ACL_priv_list, ACL_end}; - handle1.reset(); + fb_assert(sizeof(buffer) >= 8 + ownerNameLength + + sizeof(DDL_OWNER_ACL) + sizeof(DDL_PUBLIC_ACL)); - for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message) - store_message(tdbb, message, handle1); + UCHAR* acl = buffer; + *acl++ = ACL_version; + *acl++ = ACL_id_list; + *acl++ = id_person; - // Add additional grants + *acl++ = (UCHAR) ownerNameLength; + memcpy(acl, ownerName.c_str(), ownerNameLength); + acl += ownerNameLength; - MetaName buf; + *acl++ = ACL_end; - 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, transaction); + memcpy(acl, DDL_OWNER_ACL, sizeof(DDL_OWNER_ACL)); + acl += sizeof(DDL_OWNER_ACL); - 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, transaction); + *acl++ = ACL_id_list; + *acl++ = ACL_end; + memcpy(acl, DDL_PUBLIC_ACL, sizeof(DDL_PUBLIC_ACL)); + acl += sizeof(DDL_PUBLIC_ACL); - 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, transaction); + *acl++ = ACL_end; // Extra terminator to avoid scl.epp:walk_acl() missing the end - DFW_perform_system_work(tdbb); + length = acl - buffer; + } - tdbb->setTransaction(nullptr); -} + void store(thread_db* tdbb) + { + 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)); + } -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 (triggerName == trig->trg_name) - return trig->trg_flags; - } + MetaName securityClass; + securityClass.printf("%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, + DPM_gen_id(tdbb, lookupGenerator(SQL_SECCLASS_GENERATOR), false, 1)); - return 0; -} + addSecurityClass(tdbb, securityClass); + + 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 + } + private: + AutoRequest handle; + }; -void INI_init(thread_db* tdbb) +}; // namespace + +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&); + + +void INI_format(thread_db* tdbb, const string& charset) { /************************************** * - * I N I _ i n i t + * I N I _ f o r m a 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. + * Initialize system relations in the database. + * The full complement of metadata should be + * stored here. * **************************************/ - SET_TDBB(tdbb); const auto dbb = tdbb->getDatabase(); const auto attachment = tdbb->getAttachment(); - const auto pool = attachment->att_pool; + const auto transaction = attachment->getSysTransaction(); + + tdbb->setTransaction(transaction); + + // Uppercase owner name + const auto ownerName = attachment->getUserName(); + fb_assert(ownerName.hasData()); + + AutoRequest handle, reqAddSC; + + NonRelationSecurity nonRelSec(ownerName, reqAddSC, false); + + { // 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) + ; + } + + // Store RELATIONS and RELATION_FIELDS + + 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); + } + } + + // Store global FIELDS + + handle.reset(); + + for (const gfld* gfield = gfields; gfield->gfld_name; gfield++) + store_global_field(tdbb, gfield, handle, nonRelSec); + + // Store DATABASE record + + handle.reset(); + + // 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 + + // Create indices for system relations + + store_indices(tdbb); + + // Create parameter types + + handle.reset(); + + 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 + { + PAD(names[type->rtyp_field], X.RDB$FIELD_NAME); + PAD(type->rtyp_name, X.RDB$TYPE_NAME); + X.RDB$TYPE = type->rtyp_value; + X.RDB$SYSTEM_FLAG = RDB_system; + X.RDB$SYSTEM_FLAG.NULL = FALSE; + } + END_STORE + } + + for (const IntlManager::CharSetDefinition* charSet = IntlManager::defaultCharSets; + charSet->name; ++charSet) + { + // this STORE should be compatible with one above and below, + // as they use the same compiled request + STORE(REQUEST_HANDLE 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 symbols for international character sets & collations + + store_intlnames(tdbb, nonRelSec); + + // 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, handle); + + // Store trigger messages to go with triggers + + handle.reset(); + + for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message) + 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); + + // Add default DDL security + + DdlSecurity(ownerName, reqAddSC).store(tdbb); + + // Add additional grants + + MetaName buf; + + buf.printf("%d", USE_NBACKUP_UTILITY); + 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); + 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); + 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); + + tdbb->setTransaction(nullptr); +} + + +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 (triggerName == trig->trg_name) + return trig->trg_flags; + } + + return 0; +} + + +void INI_init(thread_db* tdbb) +{ +/************************************** + * + * I N I _ i n i t + * + ************************************** + * + * Functional description + * Initialize in memory meta data. Assume that all meta data + * fields exist in the database even if this is not the case. + * Do not fill in the format length or the address in each + * format descriptor. + * + **************************************/ + SET_TDBB(tdbb); + const auto dbb = tdbb->getDatabase(); + const auto attachment = tdbb->getAttachment(); + const auto pool = attachment->att_pool; const int* fld; for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) @@ -709,7 +1032,7 @@ void INI_init(thread_db* tdbb) if (desc->isText()) { - if (!get_charset_by_text_type(desc->dsc_sub_type, gfield->gfld_sub_type)) + if (!getCharsetByTextType(desc->dsc_sub_type, gfield->gfld_sub_type)) desc->dsc_sub_type = CS_NONE; } else @@ -864,7 +1187,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; } @@ -924,6 +1247,12 @@ void INI_init_dsql(thread_db* tdbb, dsql_dbb* database) } +string INI_owner_privileges() +{ + return string(gfields[fld_system_privileges].gfld_length, '\xff'); +} + + void INI_upgrade(thread_db* tdbb) { /************************************** @@ -954,624 +1283,200 @@ void INI_upgrade(thread_db* tdbb) const auto odsVersion = ENCODE_ODS(majorVersion, minorVersion); - const int* fld; - const auto transaction = TRA_start(tdbb, TRA_no_auto_undo, 0); tdbb->setTransaction(transaction); - const char* context = "tables"; + const int* fld; + const char* context = nullptr; try { - // 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 handle1, handle2; - // Get the database owner - auto ownerName = dbb->dbb_owner; - if (ownerName.isEmpty()) - { - FOR(REQUEST_HANDLE handle1) - FIRST 1 REL IN RDB$RELATIONS - WITH REL.RDB$RELATION_NAME EQ "RDB$DATABASE" - { - fb_assert(!REL.RDB$OWNER_NAME.NULL); - ownerName = REL.RDB$OWNER_NAME; - } - END_FOR - } - - // Create global fields added after the original minor ODS + const auto ownerName = dbb->dbb_owner; - context = "domains"; - handle1.reset(); - - for (const gfld* gfield = gfields; gfield->gfld_name; gfield++) - { - if (gfield->gfld_ods_version > odsVersion) - store_global_field(tdbb, gfield, handle1, ownerName); - } + AutoRequest handle, reqAddSC; + NonRelationSecurity nonRelSec(ownerName, reqAddSC, false); // Create new system relations and new relation fields context = "tables"; - handle1.reset(); - - 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) - { - if (fld[RFLD_F_ODS] > odsVersion) - { - 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, handle1); - } - - ++fieldId; - } - - if (relfld[RFLD_R_ODS] > odsVersion) - { - 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, ownerName.c_str(), - fieldId, relType, handle2); - } - } - - // Create new system indexes - - context = "indices"; - add_index_set(tdbb, odsVersion); - - // Create new system triggers and their trigger messages - - context = "triggers"; - handle1.reset(); - - for (const jrd_trg* trigger = triggers; trigger->trg_relation; ++trigger) - { - if (trigger->trg_ods_version > odsVersion) - store_trigger(tdbb, trigger, handle1); - } - - context = "trigger messages"; - handle1.reset(); - - for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message) - { - if (message->trg_ods_version > odsVersion) - store_message(tdbb, message, handle1); - } - - // Create new system generators - - context = "generators"; - handle1.reset(); - - for (const gen* generator = generators; generator->gen_name; generator++) - { - if (generator->gen_ods_version > odsVersion) - store_generator(tdbb, generator, handle1, ownerName); - } - - // Adjust the value of the hidden generator RDB$GENERATORS - DPM_gen_id(tdbb, 0, true, FB_NELEM(generators) - 1); - - // Create new system packages - - context = "packages"; - store_packages(tdbb, ownerName, odsVersion); - - // 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. + handle.reset(); - TRA_commit(tdbb, transaction, false); + { // scope for system relations - } - catch (const Exception& ex) - { - TRA_rollback(tdbb, transaction, false, true); + RelationSecurity relSec(ownerName, reqAddSC); - // Delete relations we've just created + // 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) - { - const auto relation = MET_relation(tdbb, relfld[RFLD_R_ID]); - if (relation && relation->getBasePages()->rel_pages) - DPM_delete_relation(tdbb, relation); - } + DPM_create_relation(tdbb, MET_relation(tdbb, relfld[RFLD_R_ID])); for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) ; } - Arg::StatusVector error(ex); - error.prepend(Arg::Gds(isc_ods_upgrade_err) << Arg::Str(context)); - error.raise(); - } - - // If the database was successfully updated, mark it with the current minor ODS - - win window(HEADER_PAGE_NUMBER); - auto header = (Ods::header_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_header); - CCH_MARK(tdbb, &window); + AutoRequest handle2; - dbb->dbb_minor_version = header->hdr_ods_minor = ODS_CURRENT; - CCH_RELEASE(tdbb, &window); -} - - -static void add_index_set(thread_db* tdbb, USHORT odsVersion) -{ -/************************************** - * - * a d d _ i n d e x _ s e t - * - ************************************** - * - * Functional description - * Add system indices. If odsVersion is specified, then we are performing - * an ODS update, so add only the indices marked as newer than odsVersion. - * - **************************************/ - SET_TDBB(tdbb); - 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]; - jrd_rel* 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 + for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) { - 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 (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; + int fieldId = 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++) + for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) { - const auto segment = &index->ini_idx_segment[position]; - - STORE(REQUEST_HANDLE handle2 TRANSACTION_HANDLE transaction) - Y IN RDB$INDEX_SEGMENTS + if (fld[RFLD_F_ODS] > odsVersion) { - jrd_fld* field = (*relation->rel_fields)[segment->ini_idx_rfld_id]; - - Y.RDB$FIELD_POSITION = position; - PAD(X.RDB$INDEX_NAME, Y.RDB$INDEX_NAME); - PAD(field->fld_name.c_str(), Y.RDB$FIELD_NAME); - tail->idx_field = segment->ini_idx_rfld_id; - tail->idx_itype = segment->ini_idx_type; - tail->idx_selectivity = 0; + 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); } - 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.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"); + ++fieldId; } - END_STORE - } - } -} - -// 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. - * - **************************************/ - SET_TDBB(tdbb); - const auto attachment = tdbb->getAttachment(); - const auto transaction = tdbb->getTransaction(); - - MetaName security_class, default_class; - - security_class.printf("%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, - DPM_gen_id(tdbb, MET_lookup_generator(tdbb, SQL_SECCLASS_GENERATOR), false, 1)); - - default_class.printf("%s%" SQUADFORMAT, DEFAULT_CLASS, - DPM_gen_id(tdbb, MET_lookup_generator(tdbb, DEFAULT_CLASS), false, 1)); - - - add_security_class(tdbb, reqAddSC, security_class, acl_length, acl); - add_security_class(tdbb, reqAddSC, default_class, acl_length, acl); - - FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) - REL IN RDB$RELATIONS - WITH REL.RDB$RELATION_NAME EQ rel_name - { - 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 - } - END_FOR - - for (int cnt = 0; cnt < 6; cnt++) - { - STORE(REQUEST_HANDLE reqInsUserPriv TRANSACTION_HANDLE transaction) - PRIV IN RDB$USER_PRIVILEGES - { - switch (cnt) + if (relfld[RFLD_R_ODS] > odsVersion) { - 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; + 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); } - 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 } -} + // Create global fields added after the original minor ODS -// 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); - const auto attachment = tdbb->getAttachment(); - const auto transaction = tdbb->getTransaction(); - - MetaName security_class; - security_class.printf("%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, - DPM_gen_id(tdbb, MET_lookup_generator(tdbb, SQL_SECCLASS_GENERATOR), false, 1)); - - add_security_class(tdbb, reqAddSC, security_class, acl_length, acl); - - bool needsUsagePrivileges = false, needsExecPrivileges = false; + context = "domains"; + handle.reset(); - if (obj_type == obj_field) + for (const gfld* gfield = gfields; gfield->gfld_name; gfield++) { - FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) - 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 - - needsUsagePrivileges = true; - } - END_FOR + if (gfield->gfld_ods_version > odsVersion) + store_global_field(tdbb, gfield, handle, nonRelSec); } - else if (obj_type == obj_charset) - { - FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) - 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 - needsUsagePrivileges = true; - } - END_FOR - } - else if (obj_type == obj_collation) - { - FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) - 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 + // Create new system indexes - needsUsagePrivileges = true; - } - END_FOR - } - else if (obj_type == obj_exception) - { - FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) - 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 + context = "indices"; + store_indices(tdbb, odsVersion); - needsUsagePrivileges = true; - } - END_FOR - } - else if (obj_type == obj_generator) - { - FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) - 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 + // Create new system triggers and their trigger messages - needsUsagePrivileges = true; - } - END_FOR - } - else if (obj_type == obj_sql_role) + context = "triggers"; + handle.reset(); + + for (const jrd_trg* trigger = triggers; trigger->trg_relation; ++trigger) { - FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) - 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 + if (trigger->trg_ods_version > odsVersion) + store_trigger(tdbb, trigger, handle); } - else if (obj_type == obj_package_header) - { - FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) - PKG IN RDB$PACKAGES - WITH PKG.RDB$PACKAGE_NAME EQ obj_name.c_str() - { - MODIFY PKG USING - PKG.RDB$SECURITY_CLASS.NULL = FALSE; - PAD(security_class.c_str(), PKG.RDB$SECURITY_CLASS); - END_MODIFY - needsExecPrivileges = true; - } - END_FOR - } - else if (obj_type == obj_database) + context = "trigger messages"; + handle.reset(); + + for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message) { - FOR(REQUEST_HANDLE reqModObjSC TRANSACTION_HANDLE transaction) - DB IN RDB$DATABASE - { - MODIFY DB USING - DB.RDB$SECURITY_CLASS.NULL = FALSE; - PAD(security_class.c_str(), DB.RDB$SECURITY_CLASS); - END_MODIFY - } - END_FOR + if (message->trg_ods_version > odsVersion) + store_message(tdbb, message, handle); } - else - fb_assert(false); - const char* const privileges = - needsUsagePrivileges ? USAGE_PRIVILEGES : - needsExecPrivileges ? EXEC_PRIVILEGES : - NULL; + // Create new system generators - if (privileges) - { - fb_assert(user_name.hasData()); - fb_assert(obj_name.hasData()); + context = "generators"; + handle.reset(); - for (const char* p = privileges; *p; ++p) - { - STORE(REQUEST_HANDLE reqInsUserPriv TRANSACTION_HANDLE transaction) - 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 - } + for (const gen* generator = generators; generator->gen_name; generator++) + { + if (generator->gen_ods_version > odsVersion) + store_generator(tdbb, generator, handle, nonRelSec); } -} + // Create new system packages -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) -{ - const auto attachment = tdbb->getAttachment(); - const auto transaction = tdbb->getTransaction(); + // Reset nonRelSec for package permissions, it should be its last usage in this function + new(&nonRelSec) NonRelationSecurity(ownerName, reqAddSC, true); - AutoRequest handle; + context = "packages"; + store_packages(tdbb, nonRelSec, odsVersion); + + // 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. + + TRA_commit(tdbb, transaction, false); - while (*prvl) + } + catch (const Exception& ex) { - STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) - PRIV IN RDB$USER_PRIVILEGES - { - PAD(user, PRIV.RDB$USER); - PAD(object, PRIV.RDB$RELATION_NAME); + TRA_rollback(tdbb, transaction, false, true); - if (dflt) + // Delete relations we've just created + + for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) + { + if (relfld[RFLD_R_TYPE] == rel_persistent && relfld[RFLD_R_ODS] > odsVersion) { - PRIV.RDB$FIELD_NAME[0] = 'D'; - PRIV.RDB$FIELD_NAME[1] = 0; - PRIV.RDB$FIELD_NAME.NULL = FALSE; + const auto relation = MET_relation(tdbb, relfld[RFLD_R_ID]); + if (relation && relation->getBasePages()->rel_pages) + DPM_delete_relation(tdbb, relation); } - 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; + for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) + ; + } + + if (context) + { + Arg::StatusVector error(ex); + error.prepend(Arg::Gds(isc_ods_upgrade_err) << Arg::Str(context)); + error.raise(); } - END_STORE + + throw; } -} + // If the database was successfully updated, mark it with the current minor ODS -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); + win window(HEADER_PAGE_NUMBER); + auto header = (Ods::header_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_header); + CCH_MARK(tdbb, &window); + + dbb->dbb_minor_version = header->hdr_ods_minor = ODS_CURRENT; + CCH_RELEASE(tdbb, &window); } -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(); AutoPreparedStatement ps(attachment->prepareStatement(tdbb, transaction, sql)); ps->execute(tdbb, transaction); + + security.storePrivileges(tdbb, roleName.c_str()); } @@ -1588,7 +1493,7 @@ static void store_default_pub(thread_db* tdbb, const MetaName& ownerName) 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; @@ -1604,28 +1509,8 @@ 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) -{ - SET_TDBB(tdbb); - const auto attachment = tdbb->getAttachment(); - const auto transaction = tdbb->getTransaction(); - - bid blob_id; - attachment->storeBinaryBlob(tdbb, transaction, &blob_id, ByteChunk(acl, acl_length)); - - STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) - 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) +static void store_generator(thread_db* tdbb, const gen* generator, + AutoRequest& handle, NonRelationSecurity& security) { /************************************** * @@ -1642,17 +1527,27 @@ static void store_generator(thread_db* tdbb, const gen* generator, AutoRequest& const auto attachment = tdbb->getAttachment(); const auto transaction = tdbb->getTransaction(); + const auto ownerName = security.getOwnerName(); + const auto securityClass = security.storeSecurityClass(tdbb); + 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, transaction, &X.RDB$DESCRIPTION, @@ -1665,11 +1560,13 @@ 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) { /************************************** * @@ -1686,21 +1583,34 @@ static void store_global_field(thread_db* tdbb, const gfld* gfield, AutoRequest& const auto attachment = tdbb->getAttachment(); const auto transaction = tdbb->getTransaction(); + const auto objName = names[(USHORT)gfield->gfld_name]; + const auto ownerName = security.getOwnerName(); + + 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, transaction, &X.RDB$DEFAULT_VALUE, @@ -1824,10 +1734,116 @@ 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_indices(thread_db* tdbb, USHORT odsVersion) +{ +/************************************** + * + * s t o r e _ i n d i c e s + * + ************************************** + * + * Functional description + * Add system indices. If odsVersion is specified, then we are performing + * an ODS update, so add only the indices marked as newer than odsVersion. + * + **************************************/ + SET_TDBB(tdbb); + 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]; + jrd_rel* 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, const MetaName& owner) +static void store_intlnames(thread_db* tdbb, NonRelationSecurity& security) { /************************************** * @@ -1844,24 +1860,36 @@ static void store_intlnames(thread_db* tdbb, const MetaName& owner) 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) { + 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(); @@ -1869,6 +1897,8 @@ static void store_intlnames(thread_db* tdbb, const MetaName& owner) for (const IntlManager::CollationDefinition* collation = IntlManager::defaultCollations; collation->name; ++collation) { + const auto securityClass = security.storeSecurityClass(tdbb); + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) X IN RDB$COLLATIONS USING { @@ -1884,10 +1914,16 @@ 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) @@ -1900,6 +1936,8 @@ 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); } } @@ -1936,28 +1974,43 @@ static void store_message(thread_db* tdbb, const trigger_msg* message, AutoReque static void store_relation(thread_db* tdbb, int relId, const char* relName, - const char* ownerName, int fieldId, int relType, - AutoRequest& handle) + AutoRequest& handle, + RelationSecurity& security) { SET_TDBB(tdbb); 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; + + 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, @@ -2000,34 +2053,45 @@ static void store_relation_field(thread_db* tdbb, // Store system packages. -static void store_packages(thread_db* tdbb, const MetaName& owner, USHORT odsVersion) +static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHORT odsVersion) { SET_TDBB(tdbb); 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()) { if (odsVersion && systemPackage.odsVersion <= odsVersion) continue; + 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 + security.storePrivileges(tdbb, systemPackage.name, obj_package_header); + for (auto& procedure : systemPackage.procedures) { STORE (REQUEST_HANDLE procedureHandle TRANSACTION_HANDLE transaction) @@ -2036,7 +2100,7 @@ static void store_packages(thread_db* tdbb, const MetaName& owner, USHORT odsVer 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); @@ -2110,7 +2174,7 @@ static void store_packages(thread_db* tdbb, const MetaName& owner, USHORT odsVer 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); @@ -2227,30 +2291,3 @@ static void store_trigger(thread_db* tdbb, const jrd_trg* trigger, AutoRequest& } 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; -} - From 4963dc0064578656f0f0ecf82ff74628b9a329bf Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Wed, 16 Nov 2022 17:30:26 +0300 Subject: [PATCH 4/7] Fixed index after rebase and misc adjustments --- src/jrd/idx.h | 2 +- src/jrd/ini.epp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/jrd/idx.h b/src/jrd/idx.h index 9461e02499d..3fd62251440 100644 --- a/src/jrd/idx.h +++ b/src/jrd/idx.h @@ -307,7 +307,7 @@ static const struct ini_idx_t indices[] = 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 a626843d060..9e221e31b47 100644 --- a/src/jrd/ini.epp +++ b/src/jrd/ini.epp @@ -746,8 +746,6 @@ void INI_format(thread_db* tdbb, const string& charset) AutoRequest handle, reqAddSC; - NonRelationSecurity nonRelSec(ownerName, reqAddSC, false); - { // scope for system relations RelationSecurity relSec(ownerName, reqAddSC); @@ -795,6 +793,8 @@ void INI_format(thread_db* tdbb, const string& charset) } } + NonRelationSecurity nonRelSec(ownerName, reqAddSC, false); + // Store global FIELDS handle.reset(); @@ -1296,7 +1296,6 @@ void INI_upgrade(thread_db* tdbb) const auto ownerName = dbb->dbb_owner; AutoRequest handle, reqAddSC; - NonRelationSecurity nonRelSec(ownerName, reqAddSC, false); // Create new system relations and new relation fields @@ -1353,6 +1352,8 @@ void INI_upgrade(thread_db* tdbb) } } + NonRelationSecurity nonRelSec(ownerName, reqAddSC, false); + // Create global fields added after the original minor ODS context = "domains"; From e1c0747593b2b6f04d4e8c935943551971be55a2 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Fri, 25 Nov 2022 13:12:49 +0300 Subject: [PATCH 5/7] Allow different formats of system tables to co-exist in the metadata cache. Some related cleanup. Fixed remaining issues with using the current connection after isc_dpb_upgrade_db processing. --- src/jrd/RecordSourceNodes.cpp | 6 +- src/jrd/Relation.h | 31 ++- src/jrd/WorkerAttachment.cpp | 1 - src/jrd/dfw.epp | 39 --- src/jrd/dfw_proto.h | 2 - src/jrd/ini.epp | 449 +++++++++++++++------------------- src/jrd/ini_proto.h | 1 - src/jrd/jrd.cpp | 3 - src/jrd/met.epp | 11 +- src/jrd/vio.cpp | 1 - 10 files changed, 216 insertions(+), 328 deletions(-) diff --git a/src/jrd/RecordSourceNodes.cpp b/src/jrd/RecordSourceNodes.cpp index 12ef7a65952..0f47debd335 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 0ecef31811d..97789af6faa 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/ini.epp b/src/jrd/ini.epp index 9e221e31b47..952957b6e44 100644 --- a/src/jrd/ini.epp +++ b/src/jrd/ini.epp @@ -515,7 +515,7 @@ namespace fb_assert(privileges && privileges[0] && !privileges[1]); - auto userName = getOwnerName(); + const auto userName = getOwnerName(); fb_assert(userName && *userName); fb_assert(objName); @@ -720,24 +720,17 @@ static void store_packages(thread_db*, NonRelationSecurity&, USHORT = 0); static void store_trigger(thread_db*, const jrd_trg*, AutoRequest&); +// +// Initialize system relations in the database. +// The full complement of metadata should be stored here. +// + void INI_format(thread_db* tdbb, const string& 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. - * - **************************************/ const auto dbb = tdbb->getDatabase(); const auto attachment = tdbb->getAttachment(); - const auto transaction = attachment->getSysTransaction(); + const auto transaction = attachment->getSysTransaction(); tdbb->setTransaction(transaction); // Uppercase owner name @@ -936,24 +929,18 @@ void INI_format(thread_db* tdbb, const string& charset) 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); } +// +// 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 (triggerName == trig->trg_name) @@ -964,24 +951,15 @@ USHORT INI_get_trig_flags(const MetaName& triggerName) } +// +// 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); const auto dbb = tdbb->getDatabase(); const auto attachment = tdbb->getAttachment(); + const auto pool = attachment->att_pool; const int* fld; @@ -991,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++) { @@ -1008,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 (!getCharsetByTextType(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); - const auto dbb = tdbb->getDatabase(); - - const USHORT major_version = dbb->dbb_ods_version; - const USHORT minor_version = dbb->dbb_minor_version; - vec* vector = tdbb->getAttachment()->att_relations; + const auto majorVersion = ODS_VERSION; + auto minorVersion = ODS_RELEASED; + unsigned formatNumber = 0, currentFormat = 0; - 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(); - 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)) @@ -1154,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); @@ -1253,22 +1216,17 @@ string INI_owner_privileges() } +// +// Upgrade database to the current minor ODS version +// + void INI_upgrade(thread_db* tdbb) { -/************************************** - * - * I N I _ u p g r a d e - * - ************************************** - * - * Functional description - * Upgrade minor ODS version. - * - **************************************/ const auto dbb = tdbb->getDatabase(); const auto attachment = tdbb->getAttachment(); // If database is read-only, punt + if (dbb->dbb_flags & DBB_read_only) Arg::Gds(isc_read_only).raise(); @@ -1291,6 +1249,11 @@ void INI_upgrade(thread_db* tdbb) 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; @@ -1299,7 +1262,7 @@ void INI_upgrade(thread_db* tdbb) // Create new system relations and new relation fields - context = "tables"; + context = "relations"; handle.reset(); { // scope for system relations @@ -1317,25 +1280,30 @@ void INI_upgrade(thread_db* tdbb) ; } - AutoRequest handle2; + 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) { if (fld[RFLD_F_ODS] > odsVersion) { 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); + + newFormat = true; } ++fieldId; @@ -1343,12 +1311,34 @@ void INI_upgrade(thread_db* tdbb) if (relfld[RFLD_R_ODS] > odsVersion) { - 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); } + else if (newFormat) + { + // New format number is the latest we're aware of + + 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); + + 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 + + // 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); + } } } @@ -1456,6 +1446,38 @@ void INI_upgrade(thread_db* tdbb) dbb->dbb_minor_version = header->hdr_ods_minor = ODS_CURRENT; CCH_RELEASE(tdbb, &window); + + // Invalidate new/modified relations in the DSQL metadata cache, + // thus forcing them to be reloaded on demand + + if (const auto dbb = attachment->att_dsql_instance) + { + for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) + { + bool invalidate = false; + + if (relfld[RFLD_R_ODS] > odsVersion) + invalidate = true; + + for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) + { + if (fld[RFLD_F_ODS] > odsVersion) + invalidate = true; + } + + // Code below is the same as METD_drop_relation() but without a transaction + + const auto relName = names[relfld[RFLD_R_NAME]]; + dsql_rel* relation; + + 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); + } + } + } } @@ -1513,18 +1535,6 @@ static void store_default_pub(thread_db* tdbb, const MetaName& ownerName) static void store_generator(thread_db* tdbb, const gen* generator, AutoRequest& handle, NonRelationSecurity& security) { -/************************************** - * - * 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); const auto attachment = tdbb->getAttachment(); const auto transaction = tdbb->getTransaction(); @@ -1569,18 +1579,6 @@ static void store_generator(thread_db* tdbb, const gen* generator, 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); const auto attachment = tdbb->getAttachment(); const auto transaction = tdbb->getTransaction(); @@ -1742,18 +1740,6 @@ static void store_global_field(thread_db* tdbb, const gfld* gfield, static void store_indices(thread_db* tdbb, USHORT odsVersion) { -/************************************** - * - * s t o r e _ i n d i c e s - * - ************************************** - * - * Functional description - * Add system indices. If odsVersion is specified, then we are performing - * an ODS update, so add only the indices marked as newer than odsVersion. - * - **************************************/ - SET_TDBB(tdbb); const auto attachment = tdbb->getAttachment(); const auto transaction = tdbb->getTransaction(); @@ -1764,7 +1750,7 @@ static void store_indices(thread_db* tdbb, USHORT odsVersion) 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); + const auto relation = MET_relation(tdbb, index->ini_idx_relid); if (odsVersion && index->ini_idx_ods <= odsVersion) continue; @@ -1846,18 +1832,6 @@ static void store_indices(thread_db* tdbb, USHORT odsVersion) static void store_intlnames(thread_db* tdbb, NonRelationSecurity& security) { -/************************************** - * - * 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); const auto attachment = tdbb->getAttachment(); const auto transaction = tdbb->getTransaction(); @@ -1945,22 +1919,9 @@ static void store_intlnames(thread_db* tdbb, NonRelationSecurity& security) 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); const auto attachment = tdbb->getAttachment(); const auto transaction = tdbb->getTransaction(); - // store the trigger - STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) X IN RDB$TRIGGER_MESSAGES { @@ -1980,7 +1941,6 @@ static void store_relation(thread_db* tdbb, AutoRequest& handle, RelationSecurity& security) { - SET_TDBB(tdbb); const auto attachment = tdbb->getAttachment(); const auto transaction = tdbb->getTransaction(); @@ -2022,18 +1982,6 @@ static void store_relation_field(thread_db* tdbb, int updateFlag, AutoRequest& handle) { -/************************************** - * - * 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); const auto attachment = tdbb->getAttachment(); const auto transaction = tdbb->getTransaction(); @@ -2053,10 +2001,8 @@ static void store_relation_field(thread_db* tdbb, } -// Store system packages. static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHORT odsVersion) { - SET_TDBB(tdbb); const auto dbb = tdbb->getDatabase(); const auto attachment = tdbb->getAttachment(); const auto transaction = tdbb->getTransaction(); @@ -2068,7 +2014,7 @@ static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHOR const SLONG procGen = lookupGenerator(PROCEDURES_GENERATOR); const SLONG funcGen = lookupGenerator(FUNCTIONS_GENERATOR); - for (auto& systemPackage : SystemPackage::get()) + for (const auto& systemPackage : SystemPackage::get()) { if (odsVersion && systemPackage.odsVersion <= odsVersion) continue; @@ -2093,7 +2039,7 @@ static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHOR security.storePrivileges(tdbb, systemPackage.name, obj_package_header); - for (auto& procedure : systemPackage.procedures) + for (const auto& procedure : systemPackage.procedures) { STORE (REQUEST_HANDLE procedureHandle TRANSACTION_HANDLE transaction) PRC IN RDB$PROCEDURES @@ -2119,7 +2065,7 @@ static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHOR { SSHORT paramNumber = -1; - for (auto& parameter : parameterType == 0 ? procedure.inputParameters : procedure.outputParameters) + for (const auto& parameter : parameterType == 0 ? procedure.inputParameters : procedure.outputParameters) { ++paramNumber; @@ -2167,7 +2113,7 @@ static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHOR } } - for (auto& function : systemPackage.functions) + for (const auto& function : systemPackage.functions) { STORE (REQUEST_HANDLE functionHandle TRANSACTION_HANDLE transaction) FUN IN RDB$FUNCTIONS @@ -2204,7 +2150,7 @@ static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHOR } END_STORE - for (auto& parameter : function.parameters) + for (const auto& parameter : function.parameters) { ++paramNumber; @@ -2254,28 +2200,19 @@ static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHOR 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); const auto attachment = tdbb->getAttachment(); const auto transaction = tdbb->getTransaction(); - // indicate that the relation format needs revising + // Indicate that the relation format needs revising + + const auto triggerName = names[trigger->trg_relation]; + 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 TRANSACTION_HANDLE transaction) X IN RDB$TRIGGERS diff --git a/src/jrd/ini_proto.h b/src/jrd/ini_proto.h index 5f6b1c1c942..c75011a0cc1 100644 --- a/src/jrd/ini_proto.h +++ b/src/jrd/ini_proto.h @@ -32,7 +32,6 @@ namespace Jrd { 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*); diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 9068661f069..b2658a36b4f 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -1800,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) @@ -1860,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); } @@ -3070,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); diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 5171de13aba..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. 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); From e132e933db7bdde5cdff55137d52e4871979f549 Mon Sep 17 00:00:00 2001 From: dyemanov Date: Sat, 26 Nov 2022 10:32:22 +0300 Subject: [PATCH 6/7] Fixed Windows build. --- src/jrd/ini.epp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/jrd/ini.epp b/src/jrd/ini.epp index 952957b6e44..576d170224e 100644 --- a/src/jrd/ini.epp +++ b/src/jrd/ini.epp @@ -69,14 +69,14 @@ DATABASE DB = FILENAME "ODS.RDB"; namespace { - template void PAD(const char* string, TEXT (&field)[N]) + template void PAD(const char* string, char (&field)[N]) { - jrd_vtof(string, (char*) field, sizeof(field)); + jrd_vtof(string, field, sizeof(field)); } - template void PAD(const MetaName& name, TEXT (&field)[N]) + template void PAD(const MetaName& name, char (&field)[N]) { - jrd_vtof(name.c_str(), (char*) field, sizeof(field)); + jrd_vtof(name.c_str(), field, sizeof(field)); } // This is the table used in defining triggers; note that From 6a28470192c024f6959eb4dcafc78e05b5873c94 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Tue, 10 Jan 2023 21:16:56 +0300 Subject: [PATCH 7/7] Log record about ODS upgrade --- src/jrd/ini.epp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/jrd/ini.epp b/src/jrd/ini.epp index 576d170224e..24ccf775681 100644 --- a/src/jrd/ini.epp +++ b/src/jrd/ini.epp @@ -1428,6 +1428,13 @@ void INI_upgrade(thread_db* tdbb) ; } + 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) { Arg::StatusVector error(ex); @@ -1447,6 +1454,13 @@ void INI_upgrade(thread_db* tdbb) 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()); + // Invalidate new/modified relations in the DSQL metadata cache, // thus forcing them to be reloaded on demand