From de87348dedb7d39500ca9b75f1399b465149a661 Mon Sep 17 00:00:00 2001 From: Roman Simakov Date: Fri, 17 Apr 2020 16:57:07 +0300 Subject: [PATCH 01/97] Port of TABLESPACES implementation from RedDatabase --- builds/posix/make.shared.targets | 3 + builds/win32/msvc10/engine.vcxproj | 5 +- builds/win32/msvc10/engine.vcxproj.filters | 11 +- builds/win32/msvc12/engine.vcxproj | 3 + builds/win32/msvc12/engine.vcxproj.filters | 9 + builds/win32/msvc14/engine.vcxproj | 5 +- builds/win32/msvc14/engine.vcxproj.filters | 11 +- builds/win32/msvc15/engine.vcxproj | 3 + builds/win32/msvc15/engine.vcxproj.filters | 9 + builds/win32/preprocess.bat | 4 +- lang_helpers/gds_codes.ftn | 18 + lang_helpers/gds_codes.pas | 18 + src/CMakeLists.txt | 2 + src/burp/OdsDetection.epp | 1 + src/burp/OdsDetection.h | 1 + src/burp/backup.epp | 73 +++ src/burp/burp.cpp | 53 ++ src/burp/burp.h | 30 +- src/burp/burpswi.h | 2 + src/burp/restore.epp | 132 +++++ src/common/keywords.cpp | 5 + src/dsql/DdlNodes.epp | 153 ++++- src/dsql/DdlNodes.h | 29 +- src/dsql/Parser.h | 1 + src/dsql/TablespaceNodes.epp | 290 ++++++++++ src/dsql/TablespaceNodes.h | 110 ++++ src/dsql/btyacc_fb.ske | 1 + src/dsql/dsql.h | 6 +- src/dsql/parse-conflicts.txt | 2 +- src/dsql/parse.y | 164 +++++- src/include/gen/codetext.h | 9 + src/include/gen/iberror.h | 22 +- src/include/gen/msgs.h | 9 + src/include/gen/sql_code.h | 9 + src/include/gen/sql_state.h | 9 + src/isql/extract.epp | 89 ++- src/isql/isql.h | 4 + src/isql/show.epp | 127 ++++- src/jrd/Attachment.cpp | 19 + src/jrd/Attachment.h | 19 + src/jrd/JrdStatement.cpp | 29 + src/jrd/Relation.cpp | 5 + src/jrd/Relation.h | 13 + src/jrd/Tablespace.cpp | 50 ++ src/jrd/Tablespace.h | 68 +++ src/jrd/btr.cpp | 227 ++++++-- src/jrd/btr.h | 3 +- src/jrd/btr_proto.h | 4 +- src/jrd/cch.cpp | 17 +- src/jrd/cch_proto.h | 13 +- src/jrd/constants.h | 8 +- src/jrd/dfw.epp | 490 +++++++++++++++- src/jrd/dfw_proto.h | 2 +- src/jrd/dpm.epp | 485 ++++++++++++++-- src/jrd/dpm_proto.h | 4 +- src/jrd/drq.h | 5 + src/jrd/fields.h | 6 + src/jrd/idx.cpp | 7 +- src/jrd/idx.h | 10 + src/jrd/ini.epp | 1 + src/jrd/irq.h | 14 + src/jrd/jrd.cpp | 36 ++ src/jrd/lck.cpp | 1 + src/jrd/lck.h | 3 +- src/jrd/met.epp | 216 ++++++- src/jrd/met_proto.h | 6 + src/jrd/names.h | 9 + src/jrd/obj.h | 8 +- src/jrd/ods.h | 54 +- src/jrd/os/pio_proto.h | 1 + src/jrd/os/posix/unix.cpp | 11 + src/jrd/os/win32/winnt.cpp | 12 + src/jrd/pag.cpp | 47 +- src/jrd/pag.h | 8 +- src/jrd/recsrc/IndexTableScan.cpp | 2 +- src/jrd/relations.h | 19 + src/jrd/replication/Applier.cpp | 2 +- src/jrd/scl.epp | 38 ++ src/jrd/scl.h | 1 + src/jrd/scl_proto.h | 1 + src/jrd/tra.cpp | 43 +- src/jrd/tra.h | 7 + src/jrd/trig.h | 1 + src/jrd/validation.cpp | 631 ++++++++++++--------- src/jrd/validation.h | 22 +- src/jrd/vio.cpp | 61 +- src/msgs/facilities2.sql | 10 +- src/msgs/messages2.sql | 31 +- src/msgs/system_errors2.sql | 9 + src/utilities/gstat/dba.epp | 2 +- 90 files changed, 3748 insertions(+), 475 deletions(-) create mode 100644 src/dsql/TablespaceNodes.epp create mode 100644 src/dsql/TablespaceNodes.h create mode 100644 src/jrd/Tablespace.cpp create mode 100644 src/jrd/Tablespace.h diff --git a/builds/posix/make.shared.targets b/builds/posix/make.shared.targets index ae5ee5951dc..fa9f97bdabb 100644 --- a/builds/posix/make.shared.targets +++ b/builds/posix/make.shared.targets @@ -78,6 +78,9 @@ $(OBJ)/dsql/DdlNodes.cpp: $(SRC_ROOT)/dsql/DdlNodes.epp $(OBJ)/dsql/PackageNodes.cpp: $(SRC_ROOT)/dsql/PackageNodes.epp $(GPRE_CURRENT) $(JRD_GPRE_FLAGS) $< $@ +$(OBJ)/dsql/TablespaceNodes.cpp: $(SRC_ROOT)/dsql/TablespaceNodes.epp + $(GPRE_CURRENT) $(JRD_GPRE_FLAGS) $< $@ + # Adding resources as prerequisite for some files $(FilesToAddVersionInfo): $(GEN_ROOT)/jrd/version.res diff --git a/builds/win32/msvc10/engine.vcxproj b/builds/win32/msvc10/engine.vcxproj index a35c0a9542d..a39481005e3 100644 --- a/builds/win32/msvc10/engine.vcxproj +++ b/builds/win32/msvc10/engine.vcxproj @@ -22,6 +22,7 @@ + @@ -142,6 +143,7 @@ + @@ -341,6 +343,7 @@ + Document @@ -539,4 +542,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc10/engine.vcxproj.filters b/builds/win32/msvc10/engine.vcxproj.filters index b0e4dd370e9..87fc5a355bf 100644 --- a/builds/win32/msvc10/engine.vcxproj.filters +++ b/builds/win32/msvc10/engine.vcxproj.filters @@ -425,6 +425,9 @@ DSQL\preprocesed + + + DSQL\preprocesed Services @@ -443,6 +446,9 @@ JRD files + + + JRD files JRD files @@ -999,6 +1005,9 @@ DSQL\GPRE files + + + DSQL\GPRE files JRD files\GPRE files @@ -1040,4 +1049,4 @@ Resource files - \ No newline at end of file + diff --git a/builds/win32/msvc12/engine.vcxproj b/builds/win32/msvc12/engine.vcxproj index 6ecc29ecc2c..a0440ee8bab 100644 --- a/builds/win32/msvc12/engine.vcxproj +++ b/builds/win32/msvc12/engine.vcxproj @@ -22,6 +22,7 @@ + @@ -151,6 +152,7 @@ + @@ -354,6 +356,7 @@ + Document diff --git a/builds/win32/msvc12/engine.vcxproj.filters b/builds/win32/msvc12/engine.vcxproj.filters index 610013a3710..183b661649c 100644 --- a/builds/win32/msvc12/engine.vcxproj.filters +++ b/builds/win32/msvc12/engine.vcxproj.filters @@ -428,6 +428,9 @@ DSQL\preprocesed + + + DSQL\preprocesed Services @@ -446,6 +449,9 @@ JRD files + + + JRD files JRD files @@ -1041,6 +1047,9 @@ DSQL\GPRE files + + + DSQL\GPRE files JRD files\GPRE files diff --git a/builds/win32/msvc14/engine.vcxproj b/builds/win32/msvc14/engine.vcxproj index 0ef26d8ee7d..195863ddfe2 100644 --- a/builds/win32/msvc14/engine.vcxproj +++ b/builds/win32/msvc14/engine.vcxproj @@ -22,6 +22,7 @@ + @@ -151,6 +152,7 @@ + @@ -353,6 +355,7 @@ + Document @@ -555,4 +558,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc14/engine.vcxproj.filters b/builds/win32/msvc14/engine.vcxproj.filters index 7014950fa81..213722a3dea 100644 --- a/builds/win32/msvc14/engine.vcxproj.filters +++ b/builds/win32/msvc14/engine.vcxproj.filters @@ -431,6 +431,9 @@ DSQL\preprocesed + + + DSQL\preprocesed Services @@ -449,6 +452,9 @@ JRD files + + + JRD files JRD files @@ -1038,6 +1044,9 @@ DSQL\GPRE files + + + DSQL\GPRE files JRD files\GPRE files @@ -1079,4 +1088,4 @@ Resource files - \ No newline at end of file + diff --git a/builds/win32/msvc15/engine.vcxproj b/builds/win32/msvc15/engine.vcxproj index f552b6cc89b..3f1d8246dad 100644 --- a/builds/win32/msvc15/engine.vcxproj +++ b/builds/win32/msvc15/engine.vcxproj @@ -22,6 +22,7 @@ + @@ -151,6 +152,7 @@ + @@ -353,6 +355,7 @@ + Document diff --git a/builds/win32/msvc15/engine.vcxproj.filters b/builds/win32/msvc15/engine.vcxproj.filters index 7014950fa81..eabda364e39 100644 --- a/builds/win32/msvc15/engine.vcxproj.filters +++ b/builds/win32/msvc15/engine.vcxproj.filters @@ -431,6 +431,9 @@ DSQL\preprocesed + + + DSQL\preprocesed Services @@ -449,6 +452,9 @@ JRD files + + + JRD files JRD files @@ -1038,6 +1044,9 @@ DSQL\GPRE files + + + DSQL\GPRE files JRD files\GPRE files diff --git a/builds/win32/preprocess.bat b/builds/win32/preprocess.bat index 377da3d1324..958309ed808 100644 --- a/builds/win32/preprocess.bat +++ b/builds/win32/preprocess.bat @@ -62,7 +62,7 @@ goto :EOF @set GPRE=%FB_BIN_DIR%\gpre_boot @for %%i in (alice_meta) do @call :PREPROCESS alice %%i @for %%i in (array, blob) do @call :PREPROCESS yvalve %%i -@for %%i in (metd, DdlNodes, PackageNodes) do @call :PREPROCESS dsql %%i -gds_cxx +@for %%i in (metd, DdlNodes, PackageNodes, TablespaceNodes) do @call :PREPROCESS dsql %%i -gds_cxx @for %%i in (gpre_meta) do @call :PREPROCESS gpre/std %%i @for %%i in (dfw, dpm, dyn_util, fun, grant, ini, met, scl, Function) do @call :PREPROCESS jrd %%i -gds_cxx @for %%i in (stats) do @call :PREPROCESS utilities %%i @@ -76,7 +76,7 @@ goto :EOF @for %%i in (backup, restore, OdsDetection) do @call :PREPROCESS burp %%i -ocxx -m @for %%i in (array, blob) do @call :PREPROCESS yvalve %%i @for %%i in (metd) do @call :PREPROCESS dsql %%i -gds_cxx -@for %%i in (DdlNodes, PackageNodes) do @call :PREPROCESS dsql %%i -gds_cxx +@for %%i in (DdlNodes, PackageNodes, TablespaceNodes) do @call :PREPROCESS dsql %%i -gds_cxx @for %%i in (gpre_meta) do @call :PREPROCESS gpre/std %%i @for %%i in (dfw, dpm, dyn_util, fun, grant, ini, met, scl, Function) do @call :PREPROCESS jrd %%i -gds_cxx @for %%i in (codes) do @call :PREPROCESS misc %%i diff --git a/lang_helpers/gds_codes.ftn b/lang_helpers/gds_codes.ftn index a7db936f68e..5e2961e1a6d 100644 --- a/lang_helpers/gds_codes.ftn +++ b/lang_helpers/gds_codes.ftn @@ -1948,6 +1948,10 @@ C -- PARAMETER (GDS__truncate_monitor = 335545267) INTEGER*4 GDS__truncate_context PARAMETER (GDS__truncate_context = 335545268) + INTEGER*4 GDS__ts_file_exists + PARAMETER (GDS__ts_file_exists = 335545269) + INTEGER*4 GDS__tablespace_name + PARAMETER (GDS__tablespace_name = 335545270) INTEGER*4 GDS__gfix_db_name PARAMETER (GDS__gfix_db_name = 335740929) INTEGER*4 GDS__gfix_invalid_sw @@ -2260,6 +2264,10 @@ C -- PARAMETER (GDS__dyn_gen_not_exist = 336068916) INTEGER*4 GDS__dyn_fld_not_exist PARAMETER (GDS__dyn_fld_not_exist = 336068917) + INTEGER*4 GDS__dyn_ts_not_found + PARAMETER (GDS__dyn_ts_not_found = 336068918) + INTEGER*4 GDS__dyn_cant_alter_ts + PARAMETER (GDS__dyn_cant_alter_ts = 336068919) INTEGER*4 GDS__gbak_unknown_switch PARAMETER (GDS__gbak_unknown_switch = 336330753) INTEGER*4 GDS__gbak_page_size_missing @@ -2716,6 +2724,16 @@ C -- PARAMETER (GDS__dsql_max_nesting = 336397333) INTEGER*4 GDS__dsql_recreate_user_failed PARAMETER (GDS__dsql_recreate_user_failed = 336397334) + INTEGER*4 GDS__dsql_create_ts_failed + PARAMETER (GDS__dsql_create_ts_failed = 336397335) + INTEGER*4 GDS__dsql_alter_ts_failed + PARAMETER (GDS__dsql_alter_ts_failed = 336397336) + INTEGER*4 GDS__dsql_create_alter_ts_failed + PARAMETER (GDS__dsql_create_alter_ts_failed = 336397337) + INTEGER*4 GDS__dsql_drop_ts_failed + PARAMETER (GDS__dsql_drop_ts_failed = 336397338) + INTEGER*4 GDS__dsql_recreate_ts_failed + PARAMETER (GDS__dsql_recreate_ts_failed = 336397339) INTEGER*4 GDS__gsec_cant_open_db PARAMETER (GDS__gsec_cant_open_db = 336723983) INTEGER*4 GDS__gsec_switches_error diff --git a/lang_helpers/gds_codes.pas b/lang_helpers/gds_codes.pas index 7e77fadd535..104270498b7 100644 --- a/lang_helpers/gds_codes.pas +++ b/lang_helpers/gds_codes.pas @@ -1943,6 +1943,10 @@ gds_truncate_monitor = 335545267; isc_truncate_context = 335545268; gds_truncate_context = 335545268; + isc_ts_file_exists = 335545269; + gds_ts_file_exists = 335545269; + isc_tablespace_name = 335545270; + gds_tablespace_name = 335545270; isc_gfix_db_name = 335740929; gds_gfix_db_name = 335740929; isc_gfix_invalid_sw = 335740930; @@ -2255,6 +2259,10 @@ gds_dyn_gen_not_exist = 336068916; isc_dyn_fld_not_exist = 336068917; gds_dyn_fld_not_exist = 336068917; + isc_dyn_ts_not_found = 336068918; + gds_dyn_ts_not_found = 336068918; + isc_dyn_cant_alter_ts = 336068919; + gds_dyn_cant_alter_ts = 336068919; isc_gbak_unknown_switch = 336330753; gds_gbak_unknown_switch = 336330753; isc_gbak_page_size_missing = 336330754; @@ -2711,6 +2719,16 @@ gds_dsql_max_nesting = 336397333; isc_dsql_recreate_user_failed = 336397334; gds_dsql_recreate_user_failed = 336397334; + isc_dsql_create_ts_failed = 336397335; + gds_dsql_create_ts_failed = 336397335; + isc_dsql_alter_ts_failed = 336397336; + gds_dsql_alter_ts_failed = 336397336; + isc_dsql_create_alter_ts_failed = 336397337; + gds_dsql_create_alter_ts_failed = 336397337; + isc_dsql_drop_ts_failed = 336397338; + gds_dsql_drop_ts_failed = 336397338; + isc_dsql_recreate_ts_failed = 336397339; + gds_dsql_recreate_ts_failed = 336397339; isc_gsec_cant_open_db = 336723983; gds_gsec_cant_open_db = 336723983; isc_gsec_switches_error = 336723984; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b890c4ea8b8..9b1bd381426 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,6 +47,7 @@ set(epp_boot_gds_files dsql/metd.epp dsql/DdlNodes.epp dsql/PackageNodes.epp + dsql/TablespaceNodes.epp jrd/dfw.epp jrd/dpm.epp jrd/dyn_util.epp @@ -481,6 +482,7 @@ set(engine_generated_src dsql/DdlNodes.epp dsql/metd.epp dsql/PackageNodes.epp + dsql/TablespaceNodes.epp jrd/dfw.epp jrd/dpm.epp jrd/dyn_util.epp diff --git a/src/burp/OdsDetection.epp b/src/burp/OdsDetection.epp index cbe4e2032af..79072daf5a3 100644 --- a/src/burp/OdsDetection.epp +++ b/src/burp/OdsDetection.epp @@ -44,6 +44,7 @@ namespace {"RDB$PROCEDURES", 0, DB_VERSION_DDL8}, // IB4 {"RDB$ROLES", 0, DB_VERSION_DDL9}, // IB5 {"RDB$PACKAGES", 0, DB_VERSION_DDL12}, // FB3 + {"RDB$TABLESPACES", 0, DB_VERSION_DDL13}, // TODO: fix version {0, 0, 0} }; diff --git a/src/burp/OdsDetection.h b/src/burp/OdsDetection.h index c1cd77f45e9..309fc470d58 100644 --- a/src/burp/OdsDetection.h +++ b/src/burp/OdsDetection.h @@ -66,6 +66,7 @@ const int DB_VERSION_DDL11 = 110; // ods11 db, FB2 const int DB_VERSION_DDL11_1 = 111; // ods11.1 db, FB2.1 const int DB_VERSION_DDL11_2 = 112; // ods11.2 db, FB2.5 const int DB_VERSION_DDL12 = 120; // ods12.0 db, FB3.0 +const int DB_VERSION_DDL13 = 130; // TODO: check this constant before branch merging const int DB_VERSION_OLDEST_SUPPORTED = DB_VERSION_DDL8; // IB4.0 is ods8 diff --git a/src/burp/backup.epp b/src/burp/backup.epp index e412928bb9c..a3f2ca95219 100644 --- a/src/burp/backup.epp +++ b/src/burp/backup.epp @@ -142,6 +142,7 @@ void write_rel_constraints(); void write_relations(); void write_secclasses(); void write_shadow_files(); +void write_tablespaces(); void write_triggers(); void write_trigger_messages(); void write_types(); @@ -340,6 +341,12 @@ int BACKUP_backup(const TEXT* dbb_file, const TEXT* file_name) write_packages(); } + if (tdgbl->runtimeODS >= DB_VERSION_DDL13) // TODO: fix version + { + // Write tablespaces + BURP_verbose(396); // msg 396 writing tablespaces + write_tablespaces(); + } // Now go back and write all data for (burp_rel* relation = tdgbl->relations; relation; relation = relation->rel_next) @@ -682,6 +689,9 @@ burp_fld* get_fields( burp_rel* relation) field->fld_identity_type = X.RDB$IDENTITY_TYPE; } + if (!X.RDB$TABLESPACE_NAME.NULL) + COPY(X.RDB$TABLESPACE_NAME, field->fld_tablespace); + field_list.add(field); } END_FOR @@ -1823,6 +1833,8 @@ void put_index( burp_rel* relation) put_blr_blob (att_index_expression_blr, X.RDB$EXPRESSION_BLR); if (!X.RDB$FOREIGN_KEY.NULL) PUT_TEXT (att_index_foreign_key, X.RDB$FOREIGN_KEY); + if (!X.RDB$TABLESPACE_NAME.NULL) // For old versions I expect it will be NULL here. Right? + PUT_TEXT(att_index_tablespace_name, X.RDB$TABLESPACE_NAME); put(tdgbl, att_end); END_FOR; @@ -2107,6 +2119,9 @@ void put_relation( burp_rel* relation) put_int32(att_field_identity_type, field->fld_identity_type); } + if (field->fld_tablespace[0]) + PUT_TEXT(att_field_tablespace_name, field->fld_tablespace); + put(tdgbl, att_end); } @@ -3830,6 +3845,9 @@ void write_relations() if (!X.RDB$SQL_SECURITY.NULL) put_boolean(att_relation_sql_security, X.RDB$SQL_SECURITY); + if (!X.RDB$TABLESPACE_NAME.NULL) // For old versions I expect it will be NULL here. Right? + PUT_TEXT(att_relation_tablespace_name, X.RDB$TABLESPACE_NAME); + put(tdgbl, att_end); burp_rel* relation = (burp_rel*) BURP_alloc_zero (sizeof(burp_rel)); relation->rel_next = tdgbl->relations; @@ -4116,6 +4134,61 @@ void write_mapping() MISC_release_request_silent(req_handle); } +void write_tablespaces() +{ +/************************************** + * + * w r i t e _ t a b l e s p a c e s + * + ************************************** + * + * Functional description + * write a record in the burp file for + * each tablespace. + * + **************************************/ + TEXT temp[GDS_NAME_LEN]; + Firebird::IRequest* req_handle1 = nullptr; + + BurpGlobals* tdgbl = BurpGlobals::getSpecific(); + + FOR (REQUEST_HANDLE req_handle1) + X IN RDB$TABLESPACES + { + put(tdgbl, rec_tablespace); + + const SSHORT l = PUT_TEXT(att_ts_name, X.RDB$TABLESPACE_NAME); + MISC_terminate(X.RDB$TABLESPACE_NAME, temp, l, sizeof(temp)); + + BURP_verbose(397, temp); // msg 397 writing tablespace @1 + + if (!X.RDB$SECURITY_CLASS.NULL) + PUT_TEXT(att_ts_security_class, X.RDB$SECURITY_CLASS); + + if (!X.RDB$DESCRIPTION.NULL) + put_source_blob(att_ts_description, att_ts_description, X.RDB$DESCRIPTION); + + if (!X.RDB$OWNER_NAME.NULL) + PUT_TEXT(att_ts_owner_name, X.RDB$OWNER_NAME); + + if (!X.RDB$FILE_NAME.NULL) + PUT_TEXT(att_ts_file, X.RDB$FILE_NAME); + + if (!X.RDB$OFFLINE.NULL) + put_int32(att_ts_offline, X.RDB$OFFLINE); + + if (!X.RDB$READ_ONLY.NULL) + put_int32(att_ts_readonly, X.RDB$READ_ONLY); + + put(tdgbl, att_end); + } + END_FOR + ON_ERROR + general_on_error(); + END_ERROR + + MISC_release_request_silent(req_handle1); +} void write_db_creators() { diff --git a/src/burp/burp.cpp b/src/burp/burp.cpp index 42585f7b03b..7909ddbf46f 100644 --- a/src/burp/burp.cpp +++ b/src/burp/burp.cpp @@ -1050,6 +1050,13 @@ int gbak(Firebird::UtilSvc* uSvc) tdgbl->gbl_sw_transportable = true; transportableMentioned = true; break; + case IN_SW_BURP_TS_MAPPING_FILE: + if (++itr >= argc) + { + BURP_error(401, true); // msg 401 tablespace mapping file parameter missing + } + tdgbl->loadMapping(argv[itr], tdgbl->tablespace_mapping, false); + break; } } // for @@ -2805,6 +2812,52 @@ void BurpGlobals::print_stats_header() burp_output(false, "\n"); } + +void BurpGlobals::loadMapping(const char* mapping_file, StringMap& map, bool caseSensitive) +{ + FILE* f = os_utils::fopen(mapping_file, fopen_read_type); + if (!f) + { + BURP_error(402, true, SafeArg() << mapping_file); // msg 402 cannot open mapping file @1 + } + + //Read lines from file, split by space and add to mapping + map.clear(); + bool end = false; + do + { + Firebird::string line; + char buffer[MAX_USHORT]; + + if (fgets(buffer, sizeof(buffer), f) != NULL) + { + size_t lineSize = strlen(buffer); + if (buffer[lineSize - 1] == '\n') + buffer[--lineSize] = '\0'; + const char* ch = strchr(buffer, ' '); + if (!ch) + continue; + Firebird::string func(buffer, ch - buffer); + Firebird::string args(ch + 1, lineSize - func.size() - 1); + func.trim(); + args.trim(); + if (!func.empty() && !args.empty()) + { + if (!caseSensitive) + func.upper(); + map.put(func, args); + } + } + else + { + end = true; + } + } while (!end); + + fclose(f); +} + + void BURP_makeSymbol(BurpGlobals* tdgbl, Firebird::string& name) // add double quotes to string { if (tdgbl->gbl_dialect < SQL_DIALECT_V6) diff --git a/src/burp/burp.h b/src/burp/burp.h index aeac8df9873..a6374d907be 100644 --- a/src/burp/burp.h +++ b/src/burp/burp.h @@ -46,6 +46,7 @@ #include "../common/status.h" #include "../common/sha.h" #include "../common/classes/ImplementHelper.h" +#include "../common/classes/GenericMap.h" #ifdef HAVE_UNISTD_H #include @@ -115,7 +116,8 @@ enum rec_type { rec_sql_roles, // SQL roles rec_mapping, // Mapping of security names rec_package, // Package - rec_db_creator // Database creator + rec_db_creator, // Database creator + rec_tablespace // Tablespace }; @@ -272,6 +274,7 @@ enum att_type { att_relation_ext_file_name, // name of file for external tables att_relation_type, att_relation_sql_security, + att_relation_tablespace_name, // Field attributes (used for both global and local fields) @@ -332,6 +335,9 @@ enum att_type { att_field_generator_name, att_field_identity_type, + //TODO: FB???.???, ODS???_??? + att_field_tablespace_name, + // Index attributes att_index_name = SERIES, @@ -345,6 +351,7 @@ enum att_type { att_index_description2, att_index_expression_source, att_index_expression_blr, + att_index_tablespace_name, // Data record @@ -630,7 +637,16 @@ enum att_type { // Database creators att_dbc_user = SERIES, - att_dbc_type + att_dbc_type, + + // Tablespace attributes + att_ts_name = SERIES, + att_ts_security_class, + att_ts_description, + att_ts_owner_name, + att_ts_file, + att_ts_offline, + att_ts_readonly }; @@ -702,6 +718,7 @@ struct burp_fld SSHORT fld_collation_id; RCRD_OFFSET fld_sql; RCRD_OFFSET fld_null; + TEXT fld_tablespace[GDS_NAME_LEN]; }; enum fld_flags_vals { @@ -938,7 +955,8 @@ class BurpGlobals : public Firebird::ThreadData, public GblPool verboseInterval(10000), flag_on_line(true), firstMap(true), - stdIoMode(false) + stdIoMode(false), + tablespace_mapping(*getDefaultMemoryPool()) { // this is VERY dirty hack to keep current (pre-FB2) behaviour memset (&gbl_database_file_name, 0, @@ -1112,6 +1130,7 @@ class BurpGlobals : public Firebird::ThreadData, public GblPool Firebird::IRequest* handles_get_type_req_handle1; Firebird::IRequest* handles_get_user_privilege_req_handle1; Firebird::IRequest* handles_get_view_req_handle1; + Firebird::IRequest* handles_get_ts_req_handle1; // The handles_put.. are for backup. Firebird::IRequest* handles_put_index_req_handle1; @@ -1132,6 +1151,9 @@ class BurpGlobals : public Firebird::ThreadData, public GblPool bool hdr_forced_writes; TEXT database_security_class[GDS_NAME_LEN]; // To save database security class for deferred update + typedef Firebird::GenericMap > > StringMap; + static inline BurpGlobals* getSpecific() { return (BurpGlobals*) ThreadData::getSpecific(); @@ -1147,6 +1169,7 @@ class BurpGlobals : public Firebird::ThreadData, public GblPool void setupSkipData(const Firebird::string& regexp); void setupIncludeData(const Firebird::string& regexp); bool skipRelation(const char* name); + void loadMapping(const char* mapping_file, StringMap& map, bool caseSensitive = true); char veryEnd; //starting after this members must be initialized in constructor explicitly @@ -1164,6 +1187,7 @@ class BurpGlobals : public Firebird::ThreadData, public GblPool bool stdIoMode; // stdin or stdout is used as backup file Firebird::AutoPtr skipDataMatcher; Firebird::AutoPtr includeDataMatcher; + StringMap tablespace_mapping; // Will be used to overwrite filename of tablespace with given name public: Firebird::string toSystem(const Firebird::PathName& from); diff --git a/src/burp/burpswi.h b/src/burp/burpswi.h index 97ba37fac4f..cc6f377b5c4 100644 --- a/src/burp/burpswi.h +++ b/src/burp/burpswi.h @@ -97,6 +97,7 @@ const int IN_SW_BURP_KEYNAME = 50; // name of crypt key const int IN_SW_BURP_CRYPT = 51; // name of crypt plugin const int IN_SW_BURP_INCLUDE_DATA = 52; // backup data from tables +const int IN_SW_BURP_TS_MAPPING_FILE = 53; // mapping file for tablespaces /**************************************************************************/ @@ -220,6 +221,7 @@ static const Switches::in_sw_tab_t reference_burp_in_sw_table[] = {IN_SW_BURP_HIDDEN_RDONLY, isc_spb_res_am_readonly, "MODE READ_ONLY", 0, 0, 0, false, false, 0, 14, NULL, boRestore}, {IN_SW_BURP_HIDDEN_RDWRITE, isc_spb_res_am_readwrite, "MODE READ_WRITE", 0, 0, 0, false, false, 0, 15, NULL, boRestore}, /**************************************************************************/ + {IN_SW_BURP_TS_MAPPING_FILE, 0, "TABLESPACE_MAPPING_FILE", 0, 0, 0, false, false, 1014, 14, NULL, boRestore}, //TODO: Check message no (1014) {IN_SW_BURP_0, 0, NULL, 0, 0, 0, false, false, 0, 0, NULL, boGeneral} }; diff --git a/src/burp/restore.epp b/src/burp/restore.epp index b1a3617e91b..b2c67f69518 100644 --- a/src/burp/restore.epp +++ b/src/burp/restore.epp @@ -139,6 +139,7 @@ void get_misc_blob(BurpGlobals* tdgbl, ISC_QUAD&, bool); SLONG get_int32(BurpGlobals* tdgbl); SINT64 get_int64(BurpGlobals* tdgbl); bool get_package(BurpGlobals* tdgbl); +bool get_tablespace(BurpGlobals* tdgbl); bool get_procedure(BurpGlobals* tdgbl); bool get_procedure_prm (BurpGlobals* tdgbl, GDS_NAME, GDS_NAME); bool get_ref_constraint(BurpGlobals* tdgbl); @@ -4317,6 +4318,7 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation) // ODS 12 X.RDB$GENERATOR_NAME.NULL = TRUE; X.RDB$IDENTITY_TYPE.NULL = TRUE; + X.RDB$TABLESPACE_NAME.NULL = TRUE; skip_init(&scan_next_attr); while (get_attribute(&attribute, tdgbl) != att_end) @@ -4485,6 +4487,11 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation) X.RDB$IDENTITY_TYPE = (SSHORT) get_int32(tdgbl); break; + case att_field_tablespace_name: + GET_TEXT(X.RDB$TABLESPACE_NAME); + X.RDB$TABLESPACE_NAME.NULL = FALSE; + break; + default: bad_attribute(scan_next_attr, attribute, 84); // msg 84 column @@ -7070,6 +7077,7 @@ bool get_index(BurpGlobals* tdgbl, const burp_rel* relation) X.RDB$EXPRESSION_BLR.NULL = TRUE; X.RDB$SYSTEM_FLAG = 0; X.RDB$SYSTEM_FLAG.NULL = FALSE; + X.RDB$TABLESPACE_NAME.NULL = TRUE; skip_init(&scan_next_attr); while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end) @@ -7162,6 +7170,11 @@ bool get_index(BurpGlobals* tdgbl, const burp_rel* relation) GET_TEXT(X.RDB$FOREIGN_KEY); break; + case att_index_tablespace_name: + GET_TEXT(X.RDB$TABLESPACE_NAME); + X.RDB$TABLESPACE_NAME.NULL = FALSE; + break; + default: bad_attribute(scan_next_attr, attribute, 93); // msg 93 index @@ -7405,6 +7418,108 @@ bool get_package(BurpGlobals* tdgbl) return true; } +bool get_tablespace(BurpGlobals* tdgbl) +{ +/************************************** + * + * g e t _ t a b l e s p a c e + * + ************************************** + * + * Functional description + * Reconstruct a tablespace. + * + **************************************/ + att_type attribute; + TEXT temp[GDS_NAME_LEN]; + SSHORT len; + scan_attr_t scan_next_attr; + + // TODO: Fix format version for the current version after merge. + // Check other places of RDB$TABLESPACE_NAME usage + if (tdgbl->RESTORE_format < 11) + return false; + +// Firebird::ITransaction* local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans; + + STORE (REQUEST_HANDLE tdgbl->handles_get_ts_req_handle1) + X IN RDB$TABLESPACES + { + X.RDB$TABLESPACE_NAME.NULL = TRUE; + X.RDB$SECURITY_CLASS.NULL = TRUE; + X.RDB$SYSTEM_FLAG = 0; + X.RDB$SYSTEM_FLAG.NULL = FALSE; + X.RDB$DESCRIPTION.NULL = TRUE; + X.RDB$OWNER_NAME.NULL = TRUE; + X.RDB$FILE_NAME.NULL = TRUE; + X.RDB$OFFLINE.NULL = TRUE; + X.RDB$READ_ONLY.NULL = TRUE; + + skip_init(&scan_next_attr); + while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end) + { + switch (attribute) + { + case att_ts_name: + len = GET_TEXT(X.RDB$TABLESPACE_NAME); + X.RDB$TABLESPACE_NAME.NULL = FALSE; + MISC_terminate(X.RDB$TABLESPACE_NAME, temp, len, sizeof(temp)); + BURP_verbose(398, temp); // msg 398 restoring tablespace %s + break; + + case att_ts_security_class: + GET_TEXT(X.RDB$SECURITY_CLASS); + fix_security_class_name(tdgbl, X.RDB$SECURITY_CLASS, false); + X.RDB$SECURITY_CLASS.NULL = FALSE; + break; + + case att_ts_description: + get_source_blob(tdgbl, X.RDB$DESCRIPTION, true); + X.RDB$DESCRIPTION.NULL = FALSE; + break; + + case att_ts_owner_name: + GET_TEXT(X.RDB$OWNER_NAME); + X.RDB$OWNER_NAME.NULL = FALSE; + break; + + case att_ts_file: + GET_TEXT(X.RDB$FILE_NAME); + X.RDB$FILE_NAME.NULL = FALSE; + break; + + case att_ts_offline: + X.RDB$OFFLINE = (USHORT) get_int32(tdgbl); + X.RDB$OFFLINE.NULL = FALSE; + break; + + case att_ts_readonly: + X.RDB$READ_ONLY = (USHORT) get_int32(tdgbl); + X.RDB$READ_ONLY.NULL = FALSE; + break; + + default: + bad_attribute(scan_next_attr, attribute, 399); // msg 399 tablespace + break; + } + } + + Firebird::string newFile; + if (tdgbl->tablespace_mapping.get(X.RDB$TABLESPACE_NAME, newFile)) + { + X.RDB$FILE_NAME.NULL = FALSE; + strcpy(X.RDB$FILE_NAME, newFile.c_str()); + } + + } + END_STORE + ON_ERROR + general_on_error(); + END_ERROR + + return true; +} + bool get_procedure(BurpGlobals* tdgbl) { /************************************** @@ -8106,6 +8221,10 @@ bool get_relation(BurpGlobals* tdgbl) ext_file_name[0] = '\0'; bool ext_file_name_null = true; + BASED_ON RDB$RELATIONS.RDB$TABLESPACE_NAME tableSpace; + tableSpace[0] = '\0'; + bool tableSpaceNull = true; + // Before starting to restore relations, commit everything that was restored // prior to this point. This ensures that no pending error can later affect // other metadata being restored. @@ -8236,6 +8355,11 @@ bool get_relation(BurpGlobals* tdgbl) sql_security = get_boolean(tdgbl); break; + case att_relation_tablespace_name: + tableSpaceNull = false; + GET_TEXT(tableSpace); + break; + default: bad_attribute(scan_next_attr, attribute, 111); // msg 111 table @@ -8267,6 +8391,7 @@ bool get_relation(BurpGlobals* tdgbl) X.RDB$EXTERNAL_FILE.NULL = ext_file_name_null; X.RDB$RELATION_TYPE.NULL = FALSE; X.RDB$SQL_SECURITY.NULL = sql_security_null; + X.RDB$TABLESPACE_NAME.NULL = tableSpaceNull; X.RDB$SYSTEM_FLAG = (USHORT) sys_flag; X.RDB$FLAGS = (USHORT) rel_flags; @@ -8281,6 +8406,7 @@ bool get_relation(BurpGlobals* tdgbl) X.RDB$RELATION_TYPE = (USHORT) type; X.RDB$SQL_SECURITY = (FB_BOOLEAN) sql_security; + strcpy(X.RDB$TABLESPACE_NAME, tableSpace); END_STORE; ON_ERROR @@ -10969,6 +11095,12 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file flag = true; break; + case rec_tablespace: + if (!get_tablespace(tdgbl)) + return false; + flag = true; + break; + case rec_procedure: if (!get_procedure(tdgbl)) return false; diff --git a/src/common/keywords.cpp b/src/common/keywords.cpp index 4be029274d4..ec98152179d 100644 --- a/src/common/keywords.cpp +++ b/src/common/keywords.cpp @@ -136,6 +136,7 @@ static const TOK tokens[] = {TOK_CONSISTENCY, "CONSISTENCY", true}, {TOK_CONSTRAINT, "CONSTRAINT", false}, {TOK_CONTAINING, "CONTAINING", true}, + {TOK_CONTENTS, "CONTENTS", true}, {TOK_CONTINUE, "CONTINUE", true}, {TOK_CORR, "CORR", false}, {TOK_COS, "COS", true}, @@ -245,6 +246,7 @@ static const TOK tokens[] = {TOK_IIF, "IIF", true}, {TOK_IN, "IN", false}, {TOK_INACTIVE, "INACTIVE", true}, + {TOK_INCLUDING, "INCLUDING", true}, {TOK_INCREMENT, "INCREMENT", true}, {TOK_INDEX, "INDEX", false}, {TOK_INNER, "INNER", false}, @@ -330,6 +332,8 @@ static const TOK tokens[] = {TOK_OFFSET, "OFFSET", false}, {TOK_OLDEST, "OLDEST", true}, {TOK_ON, "ON", false}, + {TOK_OFFLINE, "OFFLINE", true}, + {TOK_ONLINE, "ONLINE", true}, {TOK_ONLY, "ONLY", false}, {TOK_OPEN, "OPEN", false}, {TOK_OPTION, "OPTION", true}, @@ -475,6 +479,7 @@ static const TOK tokens[] = {TOK_SUSPEND, "SUSPEND", true}, {TOK_SYSTEM, "SYSTEM", true}, {TOK_TABLE, "TABLE", false}, + {TOK_TABLESPACE, "TABLESPACE", true}, {TOK_TAGS, "TAGS", true}, {TOK_TAN, "TAN", true}, {TOK_TANH, "TANH", true}, diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 4586aa97b55..26826adf728 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -113,6 +113,8 @@ static void updateRdbFields(const TypeClause* type, SSHORT& collationIdNull, SSHORT& collationId, SSHORT& segmentLengthNull, SSHORT& segmentLength); +static bool checkObjectExist(thread_db* tdbb, jrd_tra* transaction, const MetaName& name, int type); + static const char* const CHECK_CONSTRAINT_EXCEPTION = "check_constraint"; DATABASE DB = STATIC "ODS.RDB"; @@ -6016,7 +6018,8 @@ RelationNode::RelationNode(MemoryPool& p, RelationSourceNode* aDsqlNode) : DdlNode(p), dsqlNode(aDsqlNode), name(p, dsqlNode->dsqlName), - clauses(p) + clauses(p), + tableSpace(p) { } @@ -6115,6 +6118,7 @@ void RelationNode::FieldDefinition::store(thread_db* tdbb, jrd_tra* transaction) RFR.RDB$VIEW_CONTEXT.NULL = TRUE; RFR.RDB$BASE_FIELD.NULL = TRUE; ///RFR.RDB$UPDATE_FLAG.NULL = TRUE; + RFR.RDB$TABLESPACE_NAME.NULL = TRUE; if (collationId.specified) { @@ -6183,6 +6187,14 @@ void RelationNode::FieldDefinition::store(thread_db* tdbb, jrd_tra* transaction) DYN_UTIL_find_field_source(tdbb, transaction, relationName, viewContext.value, baseField.c_str(), RFR.RDB$FIELD_SOURCE); } + + if (tableSpace.hasData()) + { + if (!checkObjectExist(tdbb, transaction, tableSpace, obj_tablespaces)) + status_exception::raise(Arg::PrivateDyn(310) << tableSpace.c_str()); //Tablespace @1 not found + RFR.RDB$TABLESPACE_NAME.NULL = FALSE; + strcpy(RFR.RDB$TABLESPACE_NAME, tableSpace.c_str()); + } } END_STORE } @@ -6501,6 +6513,9 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch if (clause->collate.hasData()) fieldDefinition.collationId = field->collationId; + if (field->fld_ts_name.hasData()) + fieldDefinition.tableSpace = field->fld_ts_name; + fieldDefinition.store(tdbb, transaction); // Define the field constraints. @@ -7427,6 +7442,16 @@ void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat REL.RDB$VIEW_SOURCE.NULL = TRUE; REL.RDB$EXTERNAL_FILE.NULL = TRUE; + if (!tableSpace.isEmpty()) + { + if (!checkObjectExist(tdbb, transaction, tableSpace, obj_tablespaces)) + status_exception::raise(Arg::PrivateDyn(310) << tableSpace.c_str()); //Tablespace @1 not found + REL.RDB$TABLESPACE_NAME.NULL = FALSE; + strcpy(REL.RDB$TABLESPACE_NAME, tableSpace.c_str()); + } + else + REL.RDB$TABLESPACE_NAME.NULL = TRUE; + if (externalFile) { if (externalFile->length() >= sizeof(REL.RDB$EXTERNAL_FILE)) @@ -7787,6 +7812,57 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc break; } + case Clause::TYPE_ALTER_TABLESPACE: + { + AutoRequest request; + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + REL IN RDB$RELATIONS + WITH REL.RDB$RELATION_NAME EQ name.c_str() + { + // RS: We need to have relation in the cache with current pageSpaceId + // to copy data from it. So check it in assert. + jrd_rel* rel = MET_lookup_relation_id(tdbb, REL.RDB$RELATION_ID, false); + fb_assert(rel); + + if (rel->isTemporary()) + { + // msg 311: "Cannot alter tablespace for temporary table @1" + status_exception::raise(Arg::PrivateDyn(311) << name); + } + + const MetaName& tableSpaceName = + static_cast(i->getObject())->name; + + // Check if we are try to change tablespace name to the already set + if ( (REL.RDB$TABLESPACE_NAME.NULL && tableSpaceName.isEmpty()) || + (!REL.RDB$TABLESPACE_NAME.NULL && (tableSpaceName == REL.RDB$TABLESPACE_NAME) ) ) + { + break; + } + + MODIFY REL + { + + if (tableSpaceName.hasData()) + { + REL.RDB$TABLESPACE_NAME.NULL = FALSE; + strcpy(REL.RDB$TABLESPACE_NAME, tableSpaceName.c_str()); + } + else + { + REL.RDB$TABLESPACE_NAME.NULL = TRUE; + REL.RDB$TABLESPACE_NAME[0] = 0; + } + DFW_post_work(transaction, dfw_move_relation, name.c_str(), REL.RDB$RELATION_ID); + } + END_MODIFY + } + END_FOR + + break; + } + default: fb_assert(false); break; @@ -8380,6 +8456,15 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch } } + if (!view) + { + RelationPages* relPages = rel_drop->getBasePages(); + if (!relPages->rel_pages || (relPages->rel_pages->count() == 0)) + DPM_scan_pages(tdbb, pag_pointer, rel_drop->rel_id); + if (!relPages->rel_index_root) + DPM_scan_pages(tdbb, pag_root, rel_drop->rel_id); + } + const int ddlTriggerAction = (view ? DDL_TRIGGER_DROP_VIEW : DDL_TRIGGER_DROP_TABLE); // run all statements under savepoint control @@ -9414,6 +9499,9 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam IDX.RDB$RELATION_NAME.NULL = FALSE; IDX.RDB$SYSTEM_FLAG = 0; IDX.RDB$SYSTEM_FLAG.NULL = FALSE; // Probably redundant. + IDX.RDB$TABLESPACE_NAME.NULL = FALSE; + + MetaName relationTablespace; // Check if the table is actually a view. @@ -9428,6 +9516,8 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam // msg 181: "attempt to index a view" status_exception::raise(Arg::PrivateDyn(181)); } + if (!VREL.RDB$TABLESPACE_NAME.NULL) + relationTablespace = VREL.RDB$TABLESPACE_NAME; } END_FOR @@ -9449,6 +9539,22 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam IDX.RDB$INDEX_TYPE = SSHORT(definition.descending.value); } + if (definition.tableSpace.hasData()) + { + if (!checkObjectExist(tdbb, transaction, definition.tableSpace, obj_tablespaces)) + status_exception::raise(Arg::PrivateDyn(310) << definition.tableSpace.c_str()); //Tablespace @1 not found + strcpy(IDX.RDB$TABLESPACE_NAME, definition.tableSpace.c_str()); + } + else + { + /** + * if tablespace for the index is not defined we use relation tablespace. + * It's necessary to write it explicitly since later we can move relation + * into another tablespace. + */ + strcpy(IDX.RDB$TABLESPACE_NAME, relationTablespace.c_str()); + } + request2.reset(tdbb, drq_l_lfield, DYN_REQUESTS); for (FB_SIZE_T i = 0; i < definition.columns.getCount(); ++i) @@ -9784,6 +9890,8 @@ void CreateIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, attachment->storeBinaryBlob(tdbb, transaction, &definition.expressionBlr, computedValue); } + definition.tableSpace = tableSpace; + store(tdbb, transaction, name, definition); executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_INDEX, @@ -9801,7 +9909,8 @@ string AlterIndexNode::internalPrint(NodePrinter& printer) const DdlNode::internalPrint(printer); NODE_PRINT(printer, name); - NODE_PRINT(printer, active); + NODE_PRINT(printer, op); + NODE_PRINT(printer, tableSpace); return "AlterIndexNode"; } @@ -9834,10 +9943,30 @@ void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_INDEX, name, NULL); - MODIFY IDX - IDX.RDB$INDEX_INACTIVE.NULL = FALSE; - IDX.RDB$INDEX_INACTIVE = active ? FALSE : TRUE; - END_MODIFY + if (op == OP_ACTIVE || op == OP_INACTIVE) + { + MODIFY IDX + IDX.RDB$INDEX_INACTIVE.NULL = FALSE; + IDX.RDB$INDEX_INACTIVE = (op == OP_ACTIVE) ? FALSE : TRUE; + END_MODIFY + } + else + { + fb_assert(op == OP_ALTER_TABLESPACE || op == OP_DROP_TABLESPACE); + MODIFY IDX + if (op == OP_ALTER_TABLESPACE) + { + IDX.RDB$TABLESPACE_NAME.NULL = FALSE; + strcpy(IDX.RDB$TABLESPACE_NAME, tableSpace.c_str()); + } + else + { + fb_assert(op == OP_DROP_TABLESPACE); + IDX.RDB$TABLESPACE_NAME.NULL = TRUE; + IDX.RDB$TABLESPACE_NAME[0] = 0; + } + END_MODIFY + } } END_FOR @@ -11420,6 +11549,18 @@ static bool checkObjectExist(thread_db* tdbb, jrd_tra* transaction, const MetaNa END_FOR break; } + case obj_tablespaces: + { + AutoCacheRequest request(tdbb, drq_tablespace_exist, DYN_REQUESTS); + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + X IN RDB$TABLESPACES + WITH X.RDB$TABLESPACE_NAME EQ name.c_str() + { + rc = true; + } + END_FOR + break; + } } return rc; diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index 1aa5cff212f..2805beddd89 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -1198,7 +1198,8 @@ class RelationNode : public DdlNode fieldSource(p), identitySequence(p), defaultSource(p), - baseField(p) + baseField(p), + tableSpace(p) { } @@ -1218,6 +1219,7 @@ class RelationNode : public DdlNode Firebird::ByteChunk defaultValue; Nullable viewContext; Firebird::MetaName baseField; + Firebird::MetaName tableSpace; }; struct IndexConstraintClause @@ -1310,7 +1312,8 @@ class RelationNode : public DdlNode TYPE_ALTER_COL_TYPE, TYPE_DROP_COLUMN, TYPE_DROP_CONSTRAINT, - TYPE_ALTER_SQL_SECURITY + TYPE_ALTER_SQL_SECURITY, + TYPE_ALTER_TABLESPACE }; explicit Clause(MemoryPool& p, Type aType) @@ -1508,6 +1511,16 @@ class RelationNode : public DdlNode Nullable ssDefiner; }; + struct AlterTableSpaceClause : public Clause + { + explicit AlterTableSpaceClause(MemoryPool& p) + : Clause(p, TYPE_ALTER_TABLESPACE) + { + } + + Firebird::MetaName name; + }; + RelationNode(MemoryPool& p, RelationSourceNode* aDsqlNode); static void deleteLocalField(thread_db* tdbb, jrd_tra* transaction, @@ -1556,6 +1569,7 @@ class RelationNode : public DdlNode Firebird::MetaName name; Firebird::Array > clauses; Nullable ssDefiner; + Firebird::MetaName tableSpace; }; @@ -1733,6 +1747,7 @@ class CreateIndexNode : public DdlNode bid expressionSource; Firebird::MetaName refRelation; Firebird::ObjectsArray refColumns; + Firebird::MetaName tableSpace; }; public: @@ -1769,16 +1784,19 @@ class CreateIndexNode : public DdlNode NestConst relation; NestConst columns; NestConst computed; + Firebird::MetaName tableSpace; }; class AlterIndexNode : public DdlNode { public: - AlterIndexNode(MemoryPool& p, const Firebird::MetaName& aName, bool aActive) + enum OP {OP_ACTIVE, OP_INACTIVE, OP_ALTER_TABLESPACE, OP_DROP_TABLESPACE}; + + AlterIndexNode(MemoryPool& p, const Firebird::MetaName& aName, OP aOp) : DdlNode(p), name(p, aName), - active(aActive) + op(aOp) { } @@ -1795,7 +1813,8 @@ class AlterIndexNode : public DdlNode public: Firebird::MetaName name; - bool active; + OP op; + Firebird::MetaName tableSpace; }; diff --git a/src/dsql/Parser.h b/src/dsql/Parser.h index 5e04d26b1cf..f09c14daaf1 100644 --- a/src/dsql/Parser.h +++ b/src/dsql/Parser.h @@ -30,6 +30,7 @@ #include "../dsql/AggNodes.h" #include "../dsql/WinNodes.h" #include "../dsql/PackageNodes.h" +#include "../dsql/TablespaceNodes.h" #include "../dsql/StmtNodes.h" #include "../jrd/RecordSourceNodes.h" #include "../common/classes/Nullable.h" diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp new file mode 100644 index 00000000000..2332e32f2a1 --- /dev/null +++ b/src/dsql/TablespaceNodes.epp @@ -0,0 +1,290 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. + * + * Software distributed under the License is distributed AS IS, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. + * See the License for the specific language governing rights + * and limitations under the License. + * + * The Original Code was created by Roman Simakov + * for the RedDatabase project. + * + * Copyright (c) 2018 + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + */ + +#include "firebird.h" +#include "../dsql/TablespaceNodes.h" +#include "../jrd/dyn.h" +#include "../jrd/intl.h" +#include "../jrd/jrd.h" +#include "../jrd/tra.h" +#include "../jrd/dfw_proto.h" +#include "../jrd/exe_proto.h" +#include "../jrd/met_proto.h" +#include "../jrd/vio_proto.h" +#include "../dsql/make_proto.h" +#include "../dsql/pass1_proto.h" +#include "../common/StatusArg.h" +#include "../jrd/Attachment.h" +#include "../jrd/scl_proto.h" +#include "../jrd/dyn_ut_proto.h" +#include "../jrd/pag_proto.h" + + +using namespace Firebird; + +namespace Jrd { + +using namespace Firebird; + +DATABASE DB = STATIC "ODS.RDB"; + + +//---------------------- + +string CreateAlterTablespaceNode::internalPrint(NodePrinter& printer) const +{ + DdlNode::internalPrint(printer); + + NODE_PRINT(printer, name); + NODE_PRINT(printer, create); + NODE_PRINT(printer, alter); + NODE_PRINT(printer, offline); + NODE_PRINT(printer, readonly); + + return "CreateAlterTablespaceNode"; +} + + +void CreateAlterTablespaceNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + dscName.makeText(name.length(), ttype_metadata, (UCHAR*) name.c_str()); + if (alter) + SCL_check_tablespace(tdbb, &dscName, SCL_alter); + else + SCL_check_create_access(tdbb, SCL_object_tablespace); +} + + +void CreateAlterTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, + jrd_tra* transaction) +{ + fb_assert(create || alter); + + // run all statements under savepoint control + AutoSavePoint savePoint(tdbb, transaction); + + if (alter) + { + if (!executeAlter(tdbb, dsqlScratch, transaction)) + { + if (create) // create or alter + executeCreate(tdbb, dsqlScratch, transaction); + else + { + status_exception::raise( + Arg::Gds(isc_no_meta_update) << + Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(name)); + } + } + } + else + executeCreate(tdbb, dsqlScratch, transaction); + + savePoint.release(); // everything is ok +} + + +void CreateAlterTablespaceNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, + jrd_tra* transaction) +{ + Attachment* attachment = transaction->getAttachment(); + Database* dbb = tdbb->getDatabase(); + + const MetaName& userName = attachment->att_user->getUserName(); + + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, + DDL_TRIGGER_CREATE_TABLESPACE, name, NULL); + + AutoCacheRequest requestHandle(tdbb, drq_s_tablespace, DYN_REQUESTS); + + int faults = 0; + SINT64 id = INVALID_PAGE_SPACE; + + while (true) + { + try + { + id = DYN_UTIL_gen_unique_id(tdbb, drq_g_nxt_ts_id, "RDB$TABLESPACES") + 1; // +1 to skip DB_PAGE_SPACE + id %= TRANS_PAGE_SPACE; + + if (!id) + continue; + + STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + X IN RDB$TABLESPACES USING + { + X.RDB$TABLESPACE_ID = id; + strcpy(X.RDB$TABLESPACE_NAME, name.c_str()); + X.RDB$SYSTEM_FLAG = 0; + + X.RDB$OWNER_NAME.NULL = FALSE; + strcpy(X.RDB$OWNER_NAME, userName.c_str()); + + X.RDB$FILE_NAME.NULL = FALSE; + strcpy(X.RDB$FILE_NAME, fileName.c_str()); + + X.RDB$OFFLINE.NULL = FALSE; + X.RDB$OFFLINE = offline; + + X.RDB$READ_ONLY.NULL = FALSE; + X.RDB$READ_ONLY = readonly; + } + END_STORE + + break; + } + catch (const status_exception& ex) + { + if (ex.value()[1] != isc_unique_key_violation) + throw; + + if (++faults >= TRANS_PAGE_SPACE) + throw; + + fb_utils::init_status(tdbb->tdbb_status_vector); + } + } + + dbb->dbb_page_manager.allocTableSpace(tdbb, id, true, PathName(fileName.c_str())); + +// RS: Not sure TS should have SECURITY CLASS. It's not DB SCHEMA. Only DDL privileges for managing it. +// storePrivileges(tdbb, transaction, name, obj_tablespaces, EXEC_PRIVILEGES); +// owner = userName; + + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_TABLESPACE, + name, NULL); +} + + +bool CreateAlterTablespaceNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, + jrd_tra* transaction) +{ + Attachment* attachment = transaction->getAttachment(); + AutoCacheRequest requestHandle(tdbb, drq_m_tablespace, DYN_REQUESTS); + bool modified = false; + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + X IN RDB$TABLESPACES + WITH X.RDB$TABLESPACE_NAME EQ name.c_str() + { + modified = true; + + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, + DDL_TRIGGER_ALTER_TABLESPACE, name, NULL); + + MODIFY X + if (fileName.hasData()) + { + fb_assert(X.RDB$FILE_NAME.NULL == FALSE); + strcpy(X.RDB$FILE_NAME, fileName.c_str()); + } + + X.RDB$OFFLINE.NULL = FALSE; + X.RDB$OFFLINE = offline; + + X.RDB$READ_ONLY.NULL = FALSE; + X.RDB$READ_ONLY = readonly; + END_MODIFY + } + END_FOR + + if (modified) + { + executeDdlTrigger(tdbb, dsqlScratch, transaction, + DTW_AFTER, DDL_TRIGGER_ALTER_TABLESPACE, name, NULL); + } + + return modified; +} + + +//---------------------- + + +string DropTablespaceNode::internalPrint(NodePrinter& printer) const +{ + DdlNode::internalPrint(printer); + + NODE_PRINT(printer, name); + NODE_PRINT(printer, silent); + + return "DropTablespaceNode"; +} + + +void DropTablespaceNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + dscName.makeText(name.length(), ttype_metadata, (UCHAR*) name.c_str()); + SCL_check_tablespace(tdbb, &dscName, SCL_drop); +} + +void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, + jrd_tra* transaction) +{ + // run all statements under savepoint control + AutoSavePoint savePoint(tdbb, transaction); + + bool found = false; + USHORT tableSpaceId = 0; + AutoCacheRequest requestHandle(tdbb, drq_e_tablespace, DYN_REQUESTS); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + X IN RDB$TABLESPACES + WITH X.RDB$TABLESPACE_NAME EQ name.c_str() + { + found = true; + tableSpaceId = X.RDB$TABLESPACE_ID; + + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, + DDL_TRIGGER_DROP_TABLESPACE, name, NULL); + + ERASE X; + + if (!X.RDB$SECURITY_CLASS.NULL) + deleteSecurityClass(tdbb, transaction, X.RDB$SECURITY_CLASS); + + DFW_post_work(transaction, dropDependencies ? dfw_drop_tablespace_dependencies + : dfw_check_tablespace_dependencies, + name.c_str(), tableSpaceId); + } + END_FOR + + if (!found && !silent) + { + status_exception::raise( + Arg::Gds(isc_no_meta_update) << + Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(name)); + } + + if (found) + { + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_TABLESPACE, + name, NULL); + } + + savePoint.release(); // everything is ok +} + + +} // namespace Jrd diff --git a/src/dsql/TablespaceNodes.h b/src/dsql/TablespaceNodes.h new file mode 100644 index 00000000000..86182b9fc99 --- /dev/null +++ b/src/dsql/TablespaceNodes.h @@ -0,0 +1,110 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. + * + * Software distributed under the License is distributed AS IS, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. + * See the License for the specific language governing rights + * and limitations under the License. + * + * The Original Code was created by Roman Simakov + * for the RedDatabase project. + * + * Copyright (c) 2018 + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + */ + +#ifndef DSQL_TABLESPACE_NODES_H +#define DSQL_TABLESPACE_NODES_H + +#include "../dsql/DdlNodes.h" +#include "../common/classes/array.h" + +namespace Jrd { + + +class CreateAlterTablespaceNode : public DdlNode +{ +public: + CreateAlterTablespaceNode(MemoryPool& pool, const Firebird::MetaName& aName) + : DdlNode(pool), + name(pool, aName), + fileName(pool), + create(true), + alter(false), + offline(false), + readonly(false) + { + } + +public: + virtual Firebird::string internalPrint(NodePrinter& printer) const; + virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction); + virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + +protected: + virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) + { + statusVector << + Firebird::Arg::Gds(createAlterCode(create, alter, + isc_dsql_create_ts_failed, isc_dsql_alter_ts_failed, + isc_dsql_create_alter_ts_failed)) << + name; + } + +private: + void executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + bool executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + +public: + Firebird::MetaName name; + Firebird::string fileName; + bool create; + bool alter; + bool offline; + bool readonly; +}; + + +class DropTablespaceNode : public DdlNode +{ +public: + DropTablespaceNode(MemoryPool& pool, const Firebird::MetaName& aName) + : DdlNode(pool), + name(pool, aName), + silent(false), + dropDependencies(false) + { + } + +public: + virtual Firebird::string internalPrint(NodePrinter& printer) const; + virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction); + virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + +protected: + virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) + { + statusVector << Firebird::Arg::Gds(isc_dsql_drop_ts_failed) << name; + } + + void handleDependencies(thread_db* tdbb, jrd_tra* transaction, bool drop); + +public: + Firebird::MetaName name; + bool silent; + bool dropDependencies; +}; + +typedef RecreateNode +RecreateTablespaceNode; + +} // namespace + +#endif // DSQL_TABLESPACE_NODES_H diff --git a/src/dsql/btyacc_fb.ske b/src/dsql/btyacc_fb.ske index 74f4debf34f..c7432aa370a 100644 --- a/src/dsql/btyacc_fb.ske +++ b/src/dsql/btyacc_fb.ske @@ -23,6 +23,7 @@ #include "../dsql/BoolNodes.h" #include "../dsql/ExprNodes.h" #include "../dsql/PackageNodes.h" +#include "../dsql/TablespaceNodes.h" #include "../dsql/StmtNodes.h" #include "../dsql/WinNodes.h" #include "../jrd/RecordSourceNodes.h" diff --git a/src/dsql/dsql.h b/src/dsql/dsql.h index cf127793a73..f190b3937d9 100644 --- a/src/dsql/dsql.h +++ b/src/dsql/dsql.h @@ -297,7 +297,8 @@ class dsql_fld : public TypeClause fld_relation(NULL), fld_procedure(NULL), fld_id(0), - fld_name(p) + fld_name(p), + fld_ts_name(p) { } @@ -312,7 +313,8 @@ class dsql_fld : public TypeClause dsql_rel* fld_relation; // Parent relation dsql_prc* fld_procedure; // Parent procedure USHORT fld_id; // Field in in database - Firebird::MetaName fld_name; + Firebird::MetaName fld_name; + Firebird::MetaName fld_ts_name; // Tablespace name for BLOB field }; // values used in fld_flags diff --git a/src/dsql/parse-conflicts.txt b/src/dsql/parse-conflicts.txt index 6172adfda04..73db89ccfcf 100644 --- a/src/dsql/parse-conflicts.txt +++ b/src/dsql/parse-conflicts.txt @@ -1 +1 @@ -60 shift/reduce conflicts, 17 reduce/reduce conflicts. +61 shift/reduce conflicts, 20 reduce/reduce conflicts. diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 7a970d824ce..663a56c9216 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -671,6 +671,12 @@ using namespace Firebird; %token CLEAR %token OLDEST +// tablespaces +%token INCLUDING +%token CONTENTS +%token TABLESPACE +%token OFFLINE +%token ONLINE // precedence declarations for expression evaluation %left OR @@ -821,6 +827,8 @@ using namespace Firebird; Jrd::SetDecFloatTrapsNode* setDecFloatTrapsNode; Jrd::SetBindNode* setBindNode; Jrd::SessionResetNode* sessionResetNode; + Jrd::CreateAlterTablespaceNode* createAlterTablespaceNode; + Jrd::DropTablespaceNode* dropTablespaceNode; } %include types.y @@ -1024,6 +1032,8 @@ object { $$ = newNode(obj_collations, get_object_name(obj_collations)); } | FILTER { $$ = newNode(obj_filters, get_object_name(obj_filters)); } + | TABLESPACE + { $$ = newNode(obj_tablespaces, get_object_name(obj_tablespaces)); } ; table_noise @@ -1485,9 +1495,11 @@ create_clause node->relation = $6; $$ = node; } - index_definition(static_cast($7)) + index_definition(static_cast($7)) tablespace_name_clause { $$ = $7; + if ($9) + static_cast($$)->tableSpace = *$9; } | FUNCTION function_clause { $$ = $2; } | PROCEDURE procedure_clause { $$ = $2; } @@ -1507,6 +1519,7 @@ create_clause | PACKAGE BODY package_body_clause { $$ = $3; } | MAPPING create_map_clause(false) { $$ = $2; } | GLOBAL MAPPING create_map_clause(true) { $$ = $3; } + | TABLESPACE tablespace_clause { $$ = $2; } ; @@ -1539,6 +1552,8 @@ recreate_clause { $$ = newNode($2); } | SEQUENCE generator_clause { $$ = newNode($2); } + | TABLESPACE tablespace_clause + { $$ = newNode($2); } | USER create_user_clause { $$ = newNode($2); } ; @@ -1561,6 +1576,7 @@ replace_clause | USER replace_user_clause { $$ = $2; } | MAPPING replace_map_clause(false) { $$ = $2; } | GLOBAL MAPPING replace_map_clause(true) { $$ = $3; } + | TABLESPACE replace_tablespace_clause { $$ = $2; } ; @@ -2175,10 +2191,12 @@ table_clause { $$ = newNode($1, $2); } - '(' table_elements($3) ')' sql_security_clause + '(' table_elements($3) ')' tablespace_name_clause sql_security_clause { $$ = $3; - $$->ssDefiner = $7; + if ($7) + $$->tableSpace = *$7; + $$->ssDefiner = $8; } ; @@ -3890,6 +3908,9 @@ trigger_ddl_type_items | CREATE MAPPING { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_MAPPING); } | ALTER MAPPING { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_ALTER_MAPPING); } | DROP MAPPING { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_MAPPING); } + | CREATE TABLESPACE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_TABLESPACE); } + | ALTER TABLESPACE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_ALTER_TABLESPACE); } + | DROP TABLESPACE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_TABLESPACE); } | trigger_ddl_type OR trigger_ddl_type { $$ = $1 | $3; } ; @@ -3961,6 +3982,7 @@ alter_clause | MAPPING alter_map_clause(false) { $$ = $2; } | GLOBAL MAPPING alter_map_clause(true) { $$ = $3; } | EXTERNAL CONNECTIONS POOL alter_eds_conn_pool_clause { $$ = $4; } + | TABLESPACE alter_tablespace_clause { $$ = $2; } ; %type alter_domain @@ -4135,6 +4157,19 @@ alter_op($relationNode) newNode(); $relationNode->clauses.add(clause); } + | ALTER TABLESPACE symbol_tablespace_name + { + RelationNode::AlterTableSpaceClause* clause = + newNode(); + clause->name = *$3; + $relationNode->clauses.add(clause); + } + | DROP TABLESPACE + { + RelationNode::AlterTableSpaceClause* clause = + newNode(); + $relationNode->clauses.add(clause); + } ; %type alter_column_name @@ -4297,8 +4332,15 @@ drop_behaviour %type alter_index_clause alter_index_clause - : symbol_index_name ACTIVE { $$ = newNode(*$1, true); } - | symbol_index_name INACTIVE { $$ = newNode(*$1, false); } + : symbol_index_name ACTIVE { $$ = newNode(*$1, AlterIndexNode::OP_ACTIVE); } + | symbol_index_name INACTIVE { $$ = newNode(*$1, AlterIndexNode::OP_INACTIVE); } + | symbol_index_name ALTER TABLESPACE symbol_tablespace_name + { + AlterIndexNode* node = newNode(*$1, AlterIndexNode::OP_ALTER_TABLESPACE); + node->tableSpace = *$4; + $$ = node; + } + | symbol_index_name DROP TABLESPACE { $$ = newNode(*$1, AlterIndexNode::OP_DROP_TABLESPACE); } ; %type alter_udf_clause @@ -4512,6 +4554,8 @@ drop_clause { $$ = $2; } | GLOBAL MAPPING drop_map_clause(true) { $$ = $3; } + | TABLESPACE drop_tablespace_clause + { $$ = $2; } ; %type opt_no_file_delete @@ -4745,7 +4789,7 @@ without_time_zone_opt %type blob_type blob_type - : BLOB { $$ = newNode(); } blob_subtype(NOTRIAL($2)) blob_segsize charset_clause + : BLOB { $$ = newNode(); } blob_subtype(NOTRIAL($2)) blob_segsize charset_clause tablespace_name_clause { $$ = $2; $$->dtype = dtype_blob; @@ -4756,16 +4800,20 @@ blob_type $$->charSet = *$5; $$->flags |= FLD_has_chset; } + if ($6) + $$->fld_ts_name = *$6; } - | BLOB '(' unsigned_short_integer ')' + | BLOB '(' unsigned_short_integer ')' tablespace_name_clause { $$ = newNode(); $$->dtype = dtype_blob; $$->length = sizeof(ISC_QUAD); $$->segLength = (USHORT) $3; $$->subType = 0; + if ($5) + $$->fld_ts_name = *$5; } - | BLOB '(' unsigned_short_integer ',' signed_short_integer ')' + | BLOB '(' unsigned_short_integer ',' signed_short_integer ')' tablespace_name_clause { $$ = newNode(); $$->dtype = dtype_blob; @@ -4773,8 +4821,11 @@ blob_type $$->segLength = (USHORT) $3; $$->subType = (USHORT) $5; $$->flags |= FLD_has_sub; + + if ($7) + $$->fld_ts_name = *$7; } - | BLOB '(' ',' signed_short_integer ')' + | BLOB '(' ',' signed_short_integer ')' tablespace_name_clause { $$ = newNode(); $$->dtype = dtype_blob; @@ -4782,6 +4833,9 @@ blob_type $$->segLength = 80; $$->subType = (USHORT) $4; $$->flags |= FLD_has_sub; + + if ($6) + $$->fld_ts_name = *$6; } ; @@ -7242,6 +7296,93 @@ map_role | USER { $$ = false; } ; +// TABLESPACE +%type tablespace_clause +tablespace_clause + : symbol_tablespace_name FILE utf_string tablespace_offline_clause tablespace_readonly_clause + { + $$ = newNode(*$1); + $$->fileName = *$3; + $$->offline = $4; + $$->readonly = $5; + } + ; + +%type symbol_tablespace_name +symbol_tablespace_name + : valid_symbol_name + ; + +%type tablespace_offline_clause +tablespace_offline_clause + : { $$ = false; } + | OFFLINE { $$ = true; } + | ONLINE { $$ = false; } + ; + +%type tablespace_readonly_clause +tablespace_readonly_clause + : { $$ = false; } + | READ ONLY { $$ = true; } + | READ WRITE { $$ = false; } + ; + +%type alter_tablespace_clause +alter_tablespace_clause + : symbol_tablespace_name FILE utf_string tablespace_offline_clause tablespace_readonly_clause + { + $$ = newNode(*$1); + $$->create = false; + $$->alter = true; + $$->fileName = *$3; + $$->offline = $4; + $$->readonly = $5; + } + | symbol_tablespace_name tablespace_offline_clause tablespace_readonly_clause + { + $$ = newNode(*$1); + $$->create = false; + $$->alter = true; + $$->offline = $2; + $$->readonly = $3; + } + ; + +%type replace_tablespace_clause +replace_tablespace_clause + : tablespace_clause + { + $$ = $1; + $$->alter = true; + } + ; + +%type tablespace_name_clause +tablespace_name_clause + : { + $$ = NULL; + } + | TABLESPACE symbol_tablespace_name + { + $$ = $2; + } + ; + +%type drop_tablespace_clause +drop_tablespace_clause + : symbol_tablespace_name + { + DropTablespaceNode* node = newNode(*$1); + $$ = node; + } + | symbol_tablespace_name INCLUDING CONTENTS + { + + DropTablespaceNode* node = newNode(*$1); + node->dropDependencies = true; + $$ = node; + } + ; // value types @@ -8915,6 +9056,11 @@ non_reserved_word | TOTALORDER | TRAPS | ZONE + | TABLESPACE + | ONLINE + | OFFLINE + | INCLUDING + | CONTENTS ; %% diff --git a/src/include/gen/codetext.h b/src/include/gen/codetext.h index c42c0c0d61a..897f95f946d 100644 --- a/src/include/gen/codetext.h +++ b/src/include/gen/codetext.h @@ -970,6 +970,8 @@ static const struct { {"truncate_warn", 335545266}, {"truncate_monitor", 335545267}, {"truncate_context", 335545268}, + {"ts_file_exists", 335545269}, + {"tablespace_name", 335545270}, {"gfix_db_name", 335740929}, {"gfix_invalid_sw", 335740930}, {"gfix_incmp_sw", 335740932}, @@ -1126,6 +1128,8 @@ static const struct { {"dyn_exc_not_exist", 336068915}, {"dyn_gen_not_exist", 336068916}, {"dyn_fld_not_exist", 336068917}, + {"dyn_ts_not_found", 336068918}, + {"dyn_cant_alter_ts", 336068919}, {"gbak_unknown_switch", 336330753}, {"gbak_page_size_missing", 336330754}, {"gbak_page_size_toobig", 336330755}, @@ -1354,6 +1358,11 @@ static const struct { {"dsql_string_char_length", 336397332}, {"dsql_max_nesting", 336397333}, {"dsql_recreate_user_failed", 336397334}, + {"dsql_create_ts_failed", 336397335}, + {"dsql_alter_ts_failed", 336397336}, + {"dsql_create_alter_ts_failed", 336397337}, + {"dsql_drop_ts_failed", 336397338}, + {"dsql_recreate_ts_failed", 336397339}, {"gsec_cant_open_db", 336723983}, {"gsec_switches_error", 336723984}, {"gsec_no_op_spec", 336723985}, diff --git a/src/include/gen/iberror.h b/src/include/gen/iberror.h index bae6d6be9a7..75dc3ebfe74 100644 --- a/src/include/gen/iberror.h +++ b/src/include/gen/iberror.h @@ -1004,6 +1004,8 @@ const ISC_STATUS isc_suspend_without_returns = 335545265L; const ISC_STATUS isc_truncate_warn = 335545266L; const ISC_STATUS isc_truncate_monitor = 335545267L; const ISC_STATUS isc_truncate_context = 335545268L; +const ISC_STATUS isc_ts_file_exists = 335545269L; +const ISC_STATUS isc_tablespace_name = 335545270L; const ISC_STATUS isc_gfix_db_name = 335740929L; const ISC_STATUS isc_gfix_invalid_sw = 335740930L; const ISC_STATUS isc_gfix_incmp_sw = 335740932L; @@ -1160,6 +1162,8 @@ const ISC_STATUS isc_dyn_rel_not_exist = 336068914L; const ISC_STATUS isc_dyn_exc_not_exist = 336068915L; const ISC_STATUS isc_dyn_gen_not_exist = 336068916L; const ISC_STATUS isc_dyn_fld_not_exist = 336068917L; +const ISC_STATUS isc_dyn_ts_not_found = 336068918L; +const ISC_STATUS isc_dyn_cant_alter_ts = 336068919L; const ISC_STATUS isc_gbak_unknown_switch = 336330753L; const ISC_STATUS isc_gbak_page_size_missing = 336330754L; const ISC_STATUS isc_gbak_page_size_toobig = 336330755L; @@ -1388,6 +1392,11 @@ const ISC_STATUS isc_dsql_string_byte_length = 336397331L; const ISC_STATUS isc_dsql_string_char_length = 336397332L; const ISC_STATUS isc_dsql_max_nesting = 336397333L; const ISC_STATUS isc_dsql_recreate_user_failed = 336397334L; +const ISC_STATUS isc_dsql_create_ts_failed = 336397335L; +const ISC_STATUS isc_dsql_alter_ts_failed = 336397336L; +const ISC_STATUS isc_dsql_create_alter_ts_failed = 336397337L; +const ISC_STATUS isc_dsql_drop_ts_failed = 336397338L; +const ISC_STATUS isc_dsql_recreate_ts_failed = 336397339L; const ISC_STATUS isc_gsec_cant_open_db = 336723983L; const ISC_STATUS isc_gsec_switches_error = 336723984L; const ISC_STATUS isc_gsec_no_op_spec = 336723985L; @@ -1494,7 +1503,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L; const ISC_STATUS isc_trace_switch_param_miss = 337182758L; const ISC_STATUS isc_trace_param_act_notcompat = 337182759L; const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L; -const ISC_STATUS isc_err_max = 1438; +const ISC_STATUS isc_err_max = 1447; #else /* c definitions */ @@ -2468,6 +2477,8 @@ const ISC_STATUS isc_err_max = 1438; #define isc_truncate_warn 335545266L #define isc_truncate_monitor 335545267L #define isc_truncate_context 335545268L +#define isc_ts_file_exists 335545269L +#define isc_tablespace_name 335545270L #define isc_gfix_db_name 335740929L #define isc_gfix_invalid_sw 335740930L #define isc_gfix_incmp_sw 335740932L @@ -2624,6 +2635,8 @@ const ISC_STATUS isc_err_max = 1438; #define isc_dyn_exc_not_exist 336068915L #define isc_dyn_gen_not_exist 336068916L #define isc_dyn_fld_not_exist 336068917L +#define isc_dyn_ts_not_found 336068918L +#define isc_dyn_cant_alter_ts 336068919L #define isc_gbak_unknown_switch 336330753L #define isc_gbak_page_size_missing 336330754L #define isc_gbak_page_size_toobig 336330755L @@ -2852,6 +2865,11 @@ const ISC_STATUS isc_err_max = 1438; #define isc_dsql_string_char_length 336397332L #define isc_dsql_max_nesting 336397333L #define isc_dsql_recreate_user_failed 336397334L +#define isc_dsql_create_ts_failed 336397335L +#define isc_dsql_alter_ts_failed 336397336L +#define isc_dsql_create_alter_ts_failed 336397337L +#define isc_dsql_drop_ts_failed 336397338L +#define isc_dsql_recreate_ts_failed 336397339L #define isc_gsec_cant_open_db 336723983L #define isc_gsec_switches_error 336723984L #define isc_gsec_no_op_spec 336723985L @@ -2958,7 +2976,7 @@ const ISC_STATUS isc_err_max = 1438; #define isc_trace_switch_param_miss 337182758L #define isc_trace_param_act_notcompat 337182759L #define isc_trace_mandatory_switch_miss 337182760L -#define isc_err_max 1438 +#define isc_err_max 1447 #endif diff --git a/src/include/gen/msgs.h b/src/include/gen/msgs.h index 2e85b9708da..0e6a45e946a 100644 --- a/src/include/gen/msgs.h +++ b/src/include/gen/msgs.h @@ -973,6 +973,8 @@ Data source : @4"}, /* eds_statement */ {335545266, "String truncated warning due to the following reason"}, /* truncate_warn */ {335545267, "Monitoring data does not fit into the field"}, /* truncate_monitor */ {335545268, "Engine data does not fit into return value of system function"}, /* truncate_context */ + {335545269, "Tablespace \"@1\" creation error. File \"@2\" exists."}, /* ts_file_exists */ + {335545270, "TABLESPACE @1"}, /* tablespace_name */ {335740929, "data base file name (@1) already given"}, /* gfix_db_name */ {335740930, "invalid switch @1"}, /* gfix_invalid_sw */ {335740932, "incompatible switch combination"}, /* gfix_incmp_sw */ @@ -1129,6 +1131,8 @@ Data source : @4"}, /* eds_statement */ {336068915, "Exception @1 does not exist"}, /* dyn_exc_not_exist */ {336068916, "Generator/Sequence @1 does not exist"}, /* dyn_gen_not_exist */ {336068917, "Field @1 of table @2 does not exist"}, /* dyn_fld_not_exist */ + {336068918, "Tablespace @1 not found"}, /* dyn_ts_not_found */ + {336068919, "Cannot alter tablespace for temporary table @1"}, /* dyn_cant_alter_ts */ {336330753, "found unknown switch"}, /* gbak_unknown_switch */ {336330754, "page size parameter missing"}, /* gbak_page_size_missing */ {336330755, "Page size specified (@1) greater than limit (32768 bytes)"}, /* gbak_page_size_toobig */ @@ -1357,6 +1361,11 @@ Data source : @4"}, /* eds_statement */ {336397332, "String literal with @1 characters exceeds the maximum length of @2 characters for the @3 character set"}, /* dsql_string_char_length */ {336397333, "Too many BEGIN...END nesting. Maximum level is @1"}, /* dsql_max_nesting */ {336397334, "RECREATE USER @1 failed"}, /* dsql_recreate_user_failed */ + {336397335, "CREATE TABLESPACE @1 failed"}, /* dsql_create_ts_failed */ + {336397336, "ALTER TABLESPACE @1 failed"}, /* dsql_alter_ts_failed */ + {336397337, "CREATE OR ALTER TABLESPACE @1 failed"}, /* dsql_create_alter_ts_failed */ + {336397338, "DROP TABLESPACE @1 failed"}, /* dsql_drop_ts_failed */ + {336397339, "RECREATE TABLESPACE @1 failed"}, /* dsql_recreate_ts_failed */ {336723983, "unable to open database"}, /* gsec_cant_open_db */ {336723984, "error in switch specifications"}, /* gsec_switches_error */ {336723985, "no operation specified"}, /* gsec_no_op_spec */ diff --git a/src/include/gen/sql_code.h b/src/include/gen/sql_code.h index edf92ff4f0b..ff068f8823b 100644 --- a/src/include/gen/sql_code.h +++ b/src/include/gen/sql_code.h @@ -969,6 +969,8 @@ static const struct { {335545266, 304}, /* 946 truncate_warn */ {335545267, 304}, /* 947 truncate_monitor */ {335545268, 304}, /* 948 truncate_context */ + {335545269, -902}, /* 949 ts_file_exists */ + {335545270, -901}, /* 950 tablespace_name */ {335740929, -901}, /* 1 gfix_db_name */ {335740930, -901}, /* 2 gfix_invalid_sw */ {335740932, -901}, /* 4 gfix_incmp_sw */ @@ -1125,6 +1127,8 @@ static const struct { {336068915, -901}, /* 307 dyn_exc_not_exist */ {336068916, -901}, /* 308 dyn_gen_not_exist */ {336068917, -901}, /* 309 dyn_fld_not_exist */ + {336068918, -901}, /* 310 dyn_ts_not_found */ + {336068919, -901}, /* 311 dyn_cant_alter_ts */ {336330753, -901}, /* 1 gbak_unknown_switch */ {336330754, -901}, /* 2 gbak_page_size_missing */ {336330755, -901}, /* 3 gbak_page_size_toobig */ @@ -1353,6 +1357,11 @@ static const struct { {336397332, -901}, /* 1044 dsql_string_char_length */ {336397333, -901}, /* 1045 dsql_max_nesting */ {336397334, -901}, /* 1046 dsql_recreate_user_failed */ + {336397335, -901}, /* 1047 dsql_create_ts_failed */ + {336397336, -901}, /* 1048 dsql_alter_ts_failed */ + {336397337, -901}, /* 1049 dsql_create_alter_ts_failed */ + {336397338, -901}, /* 1050 dsql_drop_ts_failed */ + {336397339, -901}, /* 1051 dsql_recreate_ts_failed */ {336723983, -901}, /* 15 gsec_cant_open_db */ {336723984, -901}, /* 16 gsec_switches_error */ {336723985, -901}, /* 17 gsec_no_op_spec */ diff --git a/src/include/gen/sql_state.h b/src/include/gen/sql_state.h index 96bb4dae85c..439f7dcd75f 100644 --- a/src/include/gen/sql_state.h +++ b/src/include/gen/sql_state.h @@ -969,6 +969,8 @@ static const struct { {335545266, "01004"}, // 946 truncate_warn {335545267, "01004"}, // 947 truncate_monitor {335545268, "01004"}, // 948 truncate_context + {335545269, "08001"}, // 949 ts_file_exists + {335545270, "42000"}, // 950 tablespace_name {335740929, "00000"}, // 1 gfix_db_name {335740930, "00000"}, // 2 gfix_invalid_sw {335740932, "00000"}, // 4 gfix_incmp_sw @@ -1125,6 +1127,8 @@ static const struct { {336068915, "42000"}, // 307 dyn_exc_not_exist {336068916, "42000"}, // 308 dyn_gen_not_exist {336068917, "42000"}, // 309 dyn_fld_not_exist + {336068918, "42000"}, // 310 dyn_ts_not_found + {336068919, "42000"}, // 311 dyn_cant_alter_ts {336330753, "00000"}, // 1 gbak_unknown_switch {336330754, "00000"}, // 2 gbak_page_size_missing {336330755, "00000"}, // 3 gbak_page_size_toobig @@ -1353,6 +1357,11 @@ static const struct { {336397332, "42000"}, // 1044 dsql_string_char_length {336397333, "07002"}, // 1045 dsql_max_nesting {336397334, "42000"}, // 1046 dsql_recreate_user_failed + {336397335, "42000"}, // 1047 dsql_create_ts_failed + {336397336, "42000"}, // 1048 dsql_alter_ts_failed + {336397337, "42000"}, // 1049 dsql_create_alter_ts_failed + {336397338, "42000"}, // 1050 dsql_drop_ts_failed + {336397339, "42000"}, // 1051 dsql_recreate_ts_failed {336723983, "00000"}, // 15 gsec_cant_open_db {336723984, "00000"}, // 16 gsec_switches_error {336723985, "00000"}, // 17 gsec_no_op_spec diff --git a/src/isql/extract.epp b/src/isql/extract.epp index 1b720d68224..b77af4e7f77 100644 --- a/src/isql/extract.epp +++ b/src/isql/extract.epp @@ -94,6 +94,7 @@ static void list_package_headers(); static void list_procedure_bodies(); static void list_procedure_headers(); static void list_views(); +static void list_tablespaces(); static const char* const Procterm = "^"; // TXNN: script use only @@ -177,6 +178,7 @@ int EXTRACT_ddl(LegacyTables flag, const SCHAR* tabname) list_collations(); list_generators(); list_domains(default_char_set_id); + list_tablespaces(); list_all_tables(flag, default_char_set_id); list_functions_legacy(); list_functions_ods12_headers(); @@ -303,6 +305,7 @@ int EXTRACT_list_table(const SCHAR* relation_name, SCHAR char_sets[CHARSET_COLLATE_SIZE]; rel_t rel_type = rel_persistent; char ss[28] = ""; + Firebird::string tableSpaceName; // Query to obtain relation detail information @@ -350,6 +353,13 @@ int EXTRACT_list_table(const SCHAR* relation_name, else isqlGlob.printf("%s ", new_name ? new_name : relation_name); + if (!REL.RDB$TABLESPACE_NAME.NULL) + { + fb_utils::exact_name(REL.RDB$TABLESPACE_NAME); + IUTILS_copy_SQL_id (REL.RDB$TABLESPACE_NAME, SQL_identifier, DBL_QUOTE); + tableSpaceName.printf(" TABLESPACE %s", SQL_identifier); + } + if (!REL.RDB$SQL_SECURITY.NULL) { if (REL.RDB$SQL_SECURITY) @@ -594,9 +604,9 @@ int EXTRACT_list_table(const SCHAR* relation_name, const char* opt_delim = *gtt_scope && *ss ? ", " : ""; if (*gtt_scope || *ss) - isqlGlob.printf(")%s%s%s%s", NEWLINE, gtt_scope, opt_delim , ss); + isqlGlob.printf(")%s %s%s%s%s", tableSpaceName.c_str(), NEWLINE, gtt_scope, opt_delim , ss); else - isqlGlob.printf(")"); + isqlGlob.printf(")%s", tableSpaceName.c_str()); isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); return FINI_OK; @@ -1420,7 +1430,8 @@ static processing_state list_all_grants2(bool show_role_list, const SCHAR* termi static void print_proc_prefix(int obj_type, bool headerOnly) { if (obj_type == obj_procedure || obj_type == obj_udf || - obj_type == obj_package_header || obj_type == obj_package_body) + obj_type == obj_package_header || obj_type == obj_package_body || + obj_type == obj_tablespace) { isqlGlob.printf("%sCOMMIT WORK%s%s", NEWLINE, isqlGlob.global_Term, NEWLINE); } @@ -1448,6 +1459,9 @@ static void print_proc_prefix(int obj_type, bool headerOnly) case obj_package_body: legend = "Package bodies"; break; + case obj_tablespace: + legend = "Tablespaces"; + break; } if (legend) isqlGlob.printf("%s/* %s */%s", NEWLINE, legend, NEWLINE); @@ -3352,13 +3366,20 @@ static void list_indexes() isqlGlob.printf(" COMPUTED BY "); if (!IDX.RDB$EXPRESSION_SOURCE.NULL) SHOW_print_metadata_text_blob (isqlGlob.Out, &IDX.RDB$EXPRESSION_SOURCE); - isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); } else if (ISQL_get_index_segments (collist, sizeof(collist), IDX.RDB$INDEX_NAME, true)) { - isqlGlob.printf(" (%s)%s%s", collist, isqlGlob.global_Term, NEWLINE); + isqlGlob.printf(" (%s)", collist); + } + + if (!IDX.RDB$TABLESPACE_NAME.NULL) + { + fb_utils::exact_name(IDX.RDB$TABLESPACE_NAME); + isqlGlob.printf(" TABLESPACE %s", IDX.RDB$TABLESPACE_NAME); } + isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); + END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3574,3 +3595,61 @@ static void list_views() return; END_ERROR; } + +static void list_tablespaces() +{ +/************************************** + * + * l i s t _ t a b l e s p a c e s + * + ************************************** + * + * Functional description + * Show tablespaces + * Use a SQL query to get the info and print it. + * + **************************************/ + + if (isqlGlob.major_ods < ODS_VERSION13) + return; + + bool first = true; + + FOR X IN RDB$TABLESPACES WITH + (X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$SYSTEM_FLAG MISSING) + SORTED BY X.RDB$TABLESPACE_NAME + + if (first) + { + isqlGlob.printf("%s/* Tablespaces */%s", NEWLINE, NEWLINE); + first = false; + } + + fb_utils::exact_name(X.RDB$TABLESPACE_NAME); + fb_utils::exact_name(X.RDB$FILE_NAME); + fb_utils::exact_name(X.RDB$OWNER_NAME); + + if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) + IUTILS_copy_SQL_id (X.RDB$TABLESPACE_NAME, SQL_identifier, DBL_QUOTE); + else + strcpy(SQL_identifier, X.RDB$TABLESPACE_NAME); + + isqlGlob.printf("%s/* Tablespace: %s, Owner: %s */%s", + NEWLINE, + X.RDB$TABLESPACE_NAME, + X.RDB$OWNER_NAME, + NEWLINE); + + const char* offline = X.RDB$OFFLINE.NULL || !X.RDB$OFFLINE ? "ONLINE" : "OFFLINE"; + const char* readonly = X.RDB$READ_ONLY.NULL || !X.RDB$READ_ONLY ? "READ WRITE" : "READ ONLY"; + + isqlGlob.printf("CREATE TABLESPACE %s FILE '%s' %s %s", SQL_identifier, X.RDB$FILE_NAME, offline, readonly); + + isqlGlob.printf("%s%s", Procterm, NEWLINE); + + END_FOR + ON_ERROR + ISQL_errmsg(fbStatus); + return; + END_ERROR; +} diff --git a/src/isql/isql.h b/src/isql/isql.h index 7fdd887e00e..455b4d2cd5d 100644 --- a/src/isql/isql.h +++ b/src/isql/isql.h @@ -277,6 +277,10 @@ const int DATABASE_CRYPT_PROCESS = 194; // crypt thread not complete const int MSG_ROLES = 195; // Roles: const int NO_TIMEOUTS = 196; // Timeouts are not supported by server +//TODO: Fix message numbers here and in messages2.sql +const int NO_TABLESPACE = 1022; // There is no tablespace @1 in this database +const int NO_TABLESPACES = 1023; // There are no tablespaces in this database +const int MSG_TABLESPACES = 1024; // Tablespaces: // Initialize types diff --git a/src/isql/show.epp b/src/isql/show.epp index 0c49d15ec5b..050e5d07d43 100644 --- a/src/isql/show.epp +++ b/src/isql/show.epp @@ -100,12 +100,13 @@ static processing_state show_sys_functions(const char* msg); static processing_state show_func_legacy(const SCHAR*); static processing_state show_func(const SCHAR*); static processing_state show_generators(const SCHAR*); -static void show_index(SCHAR*, SCHAR*, const SSHORT, const SSHORT, const SSHORT); +static void show_index(SCHAR*, SCHAR*, const SSHORT, const SSHORT, const SSHORT, SCHAR*); static processing_state show_indices(const SCHAR* const*); static processing_state show_proc(const SCHAR*); static processing_state show_packages(const SCHAR* package_name); static processing_state show_role(const SCHAR*, bool, const char* msg = NULL); static processing_state show_secclass(const char* object, const char* opt); +static processing_state show_tablespaces(const SCHAR*); static processing_state show_table(const SCHAR*, bool); static processing_state show_trigger(const SCHAR*, bool, bool); static processing_state show_users(); @@ -1744,6 +1745,10 @@ processing_state SHOW_grants2 (const SCHAR* object, case obj_filters: strcpy(obj_string, "FILTER"); break; + + case obj_tablespaces: + strcpy(obj_string, "TABLESPACE"); + break; } if (PRV.RDB$GRANT_OPTION) @@ -1997,7 +2002,7 @@ processing_state SHOW_metadata(const SCHAR* const* cmd, SCHAR** lcmd) role, table, view, system, index, domain, exception, filter, function, generator, grant, procedure, trigger, check, database, comment, dependency, collation, security_class, - users, package, schema, map, wrong + users, package, schema, map, tablespace, wrong }; ShowOptions(const optionsMap* inmap, size_t insize, int wrongval) : OptionsBase(inmap, insize, wrongval) @@ -2054,7 +2059,8 @@ processing_state SHOW_metadata(const SCHAR* const* cmd, SCHAR** lcmd) {ShowOptions::users, "USERS", 0}, {ShowOptions::package, "PACKAGES", 4}, {ShowOptions::schema, "SCHEMAS", 4}, - {ShowOptions::map, "MAPPING", 3} + {ShowOptions::map, "MAPPING", 3}, + {ShowOptions::tablespace, "TABLESPACES", 0 } }; const ShowOptions showoptions(options, FB_NELEM(options), ShowOptions::wrong); @@ -2653,6 +2659,25 @@ processing_state SHOW_metadata(const SCHAR* const* cmd, SCHAR** lcmd) } break; + case ShowOptions::tablespace: + if (*cmd[2] == '"') + { + remove_delimited_double_quotes(lcmd[2]); + ret = show_tablespaces(lcmd[2]); + } + else + ret = show_tablespaces(cmd[2]); + + switch (ret) { + case OBJECT_NOT_FOUND: + if (*cmd[2]) + key = NO_TABLESPACE; + else + key = NO_TABLESPACES; + break; + } + break; + case ShowOptions::map: if (*cmd[2] == '"') { @@ -4683,7 +4708,8 @@ static void show_index(SCHAR* relation_name, SCHAR* index_name, const SSHORT unique_flag, const SSHORT index_type, - const SSHORT inactive) + const SSHORT inactive, + SCHAR* tablespace_name) { /************************************** * @@ -4707,6 +4733,13 @@ static void show_index(SCHAR* relation_name, (unique_flag ? " UNIQUE" : ""), (index_type == 1 ? " DESCENDING" : ""), relation_name); + if (tablespace_name) + { + fb_utils::exact_name(tablespace_name); + if (tablespace_name[0]) + isqlGlob.printf(" TABLESPACE %s", tablespace_name); + } + // Get column names SCHAR collist[BUFFER_LENGTH512]; @@ -4751,7 +4784,8 @@ static processing_state show_indices(const SCHAR* const* cmd) IDX1.RDB$INDEX_INACTIVE = 0; show_index (IDX1.RDB$RELATION_NAME, IDX1.RDB$INDEX_NAME, - IDX1.RDB$UNIQUE_FLAG, IDX1.RDB$INDEX_TYPE, IDX1.RDB$INDEX_INACTIVE); + IDX1.RDB$UNIQUE_FLAG, IDX1.RDB$INDEX_TYPE, IDX1.RDB$INDEX_INACTIVE, + IDX1.RDB$TABLESPACE_NAME); if (!IDX1.RDB$EXPRESSION_BLR.NULL) { @@ -4782,7 +4816,8 @@ static processing_state show_indices(const SCHAR* const* cmd) first = false; show_index (IDX2.RDB$RELATION_NAME, IDX2.RDB$INDEX_NAME, - IDX2.RDB$UNIQUE_FLAG, IDX2.RDB$INDEX_TYPE, IDX2.RDB$INDEX_INACTIVE); + IDX2.RDB$UNIQUE_FLAG, IDX2.RDB$INDEX_TYPE, IDX2.RDB$INDEX_INACTIVE, + IDX2.RDB$TABLESPACE_NAME); if (!IDX2.RDB$EXPRESSION_BLR.NULL) { @@ -4891,6 +4926,80 @@ static processing_state show_packages(const SCHAR* package_name) } +static processing_state show_tablespaces(const SCHAR* tablespace_name) +{ +/************************************* +* +* s h o w _ t a b l e s p a c e s +* +************************************** +* +* Functional description +* Show all tablespaces or the named tablespace +************************************/ + if (isqlGlob.major_ods < ODS_VERSION12) //TODO: fix ODS version + return OBJECT_NOT_FOUND; + + bool first = true; + + if (!*tablespace_name) + { + // List all tablespace names in columns + FOR X IN RDB$TABLESPACES WITH + (X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$SYSTEM_FLAG MISSING) + SORTED BY X.RDB$TABLESPACE_NAME + { + first = false; + isqlGlob.printf("%s%s", fb_utils::exact_name(X.RDB$TABLESPACE_NAME), NEWLINE); + } + END_FOR + ON_ERROR + ISQL_errmsg(fbStatus); + return ps_ERR; + END_ERROR; + if (!first) + isqlGlob.printf(NEWLINE); + } + else + { + // List named tablespace + + FOR X IN RDB$TABLESPACES WITH + X.RDB$TABLESPACE_NAME EQ tablespace_name + + first = false; + // Print the name of the package + fb_utils::exact_name(X.RDB$TABLESPACE_NAME); + isqlGlob.printf("%s", X.RDB$TABLESPACE_NAME); + + if (!X.RDB$FILE_NAME.NULL) + { + fb_utils::exact_name(X.RDB$FILE_NAME); + isqlGlob.printf(" FILE %s", X.RDB$FILE_NAME); + } + + const char* offline = X.RDB$OFFLINE.NULL || !X.RDB$OFFLINE ? "ONLINE" : "OFFLINE"; + isqlGlob.printf(" %s", offline); + + const char* readonly = X.RDB$READ_ONLY.NULL || !X.RDB$READ_ONLY ? "READ WRITE" : "READ ONLY"; + isqlGlob.printf(" %s", readonly); + + isqlGlob.printf(NEWLINE); + + END_FOR + ON_ERROR + ISQL_errmsg(fbStatus); + return ps_ERR; + END_ERROR; + } + + if (first) + return OBJECT_NOT_FOUND; + + return (SKIP); +} + + static void printIdent(bool quote, char* ident, const char* format = NULL) { fb_utils::exact_name(ident); @@ -5727,6 +5836,12 @@ static processing_state show_table(const SCHAR* relation_name, bool isView) if (!REL.RDB$EXTERNAL_FILE.NULL) isqlGlob.printf("External file: %s%s", REL.RDB$EXTERNAL_FILE, NEWLINE); + + if (!REL.RDB$TABLESPACE_NAME.NULL) + { + fb_utils::exact_name(REL.RDB$TABLESPACE_NAME); + isqlGlob.printf("TABLESPACE: %s%s", REL.RDB$TABLESPACE_NAME, NEWLINE); + } } first = false; if ((isView && REL.RDB$VIEW_BLR.NULL) || (!isView && !REL.RDB$VIEW_BLR.NULL)) diff --git a/src/jrd/Attachment.cpp b/src/jrd/Attachment.cpp index 7d017cdc6f4..e247d2df15d 100644 --- a/src/jrd/Attachment.cpp +++ b/src/jrd/Attachment.cpp @@ -31,6 +31,7 @@ #include "../jrd/PreparedStatement.h" #include "../jrd/tra.h" #include "../jrd/intl.h" +#include "../jrd/Tablespace.h" #include "../jrd/blb_proto.h" #include "../jrd/exe_proto.h" @@ -210,6 +211,7 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb) att_ss_user(NULL), att_user_ids(*pool), att_active_snapshots(*pool), + att_tablespaces(*pool), att_requests(*pool), att_lock_owner_id(Database::getLockOwnerId()), att_backup_state_counter(0), @@ -255,6 +257,10 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb) { att_internal.grow(irq_MAX); att_dyn_req.grow(drq_MAX); + + Tablespace* dbTableSpace = FB_NEW_POOL(*pool) Tablespace(*pool); + dbTableSpace->id = DB_PAGE_SPACE; + att_tablespaces.add(dbTableSpace); } @@ -695,6 +701,19 @@ void Jrd::Attachment::releaseLocks(thread_db* tdbb) } } + // Release all tablespace existence locks that might have been taken + + for (Tablespace** iter = att_tablespaces.begin(); iter < att_tablespaces.end(); ++iter) + { + Tablespace* const tablespace = *iter; + + if (tablespace && tablespace->existenceLock) + { + LCK_release(tdbb, tablespace->existenceLock); + tablespace->useCount = 0; + } + } + // Release all procedure existence locks that might have been taken for (jrd_prc** iter = att_procedures.begin(); iter < att_procedures.end(); ++iter) diff --git a/src/jrd/Attachment.h b/src/jrd/Attachment.h index 4c5953816cf..a333ce45f92 100644 --- a/src/jrd/Attachment.h +++ b/src/jrd/Attachment.h @@ -91,6 +91,7 @@ namespace Jrd class Function; class JrdStatement; class Validation; + class Tablespace; class Applier; @@ -412,6 +413,7 @@ class Attachment : public pool_alloc private: jrd_tra* att_sys_transaction; // system transaction StableAttachmentPart* att_stable; + Firebird::Array att_tablespaces; // Tablespaces cache ([0] element is DB_PAGE_SPACE) public: Firebird::SortedArray att_requests; // Requests belonging to attachment @@ -612,6 +614,23 @@ class Attachment : public pool_alloc att_batches.findAndRemove(b); } + Tablespace* getTablespace(USHORT id) + { + return att_tablespaces[id - 1]; + } + + void setTablespace(USHORT id, Tablespace* value) + { + if (id > att_tablespaces.getCount()) + att_tablespaces.grow(id); + att_tablespaces[id - 1] = value; + } + + USHORT getTablespaceCount() const + { + return att_tablespaces.getCount(); + } + UserId* getUserId(const Firebird::MetaName &userName); const UserId* getEffectiveUserId() const diff --git a/src/jrd/JrdStatement.cpp b/src/jrd/JrdStatement.cpp index ed0529ee779..225774e71c3 100644 --- a/src/jrd/JrdStatement.cpp +++ b/src/jrd/JrdStatement.cpp @@ -36,6 +36,7 @@ #include "../jrd/met_proto.h" #include "../jrd/scl_proto.h" #include "../jrd/Collation.h" +#include "../jrd/Tablespace.h" using namespace Firebird; using namespace Jrd; @@ -85,6 +86,8 @@ JrdStatement::JrdStatement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb) // a little complicated since relation locks MUST be taken before // index locks. + USHORT usedTablespaces[TRANS_PAGE_SPACE] = {0}; + for (Resource* resource = resources.begin(); resource != resources.end(); ++resource) { switch (resource->rsc_type) @@ -93,6 +96,7 @@ JrdStatement::JrdStatement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb) { jrd_rel* relation = resource->rsc_rel; MET_post_existence(tdbb, relation); + usedTablespaces[relation->getBasePages()->rel_pg_space_id]++; break; } @@ -107,6 +111,8 @@ JrdStatement::JrdStatement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb) LCK_lock(tdbb, index->idl_lock, LCK_SR, LCK_WAIT); } } + const USHORT pageSpaceId = MET_index_pagespace(tdbb, relation, resource->rsc_id); + usedTablespaces[pageSpaceId]++; break; } @@ -139,6 +145,15 @@ JrdStatement::JrdStatement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb) } } + // Now let's lock all used tablespaces + for (USHORT i = DB_PAGE_SPACE + 1; i < TRANS_PAGE_SPACE; i++) + if (usedTablespaces[i] > 0) + { + // Tablespace is locking after the use in relation and indices. + // Should we check it here again? + tdbb->getAttachment()->getTablespace(i)->addRef(tdbb); + } + // make a vector of all used RSEs fors = csb->csb_fors; @@ -581,6 +596,8 @@ void JrdStatement::release(thread_db* tdbb) // Release existence locks on references. + USHORT usedTablespaces[TRANS_PAGE_SPACE] = {0}; + for (Resource* resource = resources.begin(); resource != resources.end(); ++resource) { switch (resource->rsc_type) @@ -589,6 +606,7 @@ void JrdStatement::release(thread_db* tdbb) { jrd_rel* relation = resource->rsc_rel; MET_release_existence(tdbb, relation); + usedTablespaces[relation->getBasePages()->rel_pg_space_id]++; break; } @@ -602,6 +620,8 @@ void JrdStatement::release(thread_db* tdbb) if (!index->idl_count) LCK_release(tdbb, index->idl_lock); } + const USHORT pageSpaceId = MET_index_pagespace(tdbb, relation, resource->rsc_id); + usedTablespaces[pageSpaceId]++; break; } @@ -623,6 +643,15 @@ void JrdStatement::release(thread_db* tdbb) } } + // Now let's release all used tablespaces + for (USHORT i = DB_PAGE_SPACE + 1; i < TRANS_PAGE_SPACE; i++) + if (usedTablespaces[i] > 0) + { + // Tablespace is locking after the use in relation and indices. + // Should we check it here again? + tdbb->getAttachment()->getTablespace(i)->release(tdbb); + } + for (jrd_req** instance = requests.begin(); instance != requests.end(); ++instance) EXE_release(tdbb, *instance); diff --git a/src/jrd/Relation.cpp b/src/jrd/Relation.cpp index 04df21e1dbf..2171f0030c0 100644 --- a/src/jrd/Relation.cpp +++ b/src/jrd/Relation.cpp @@ -376,6 +376,11 @@ bool jrd_rel::acquireGCLock(thread_db* tdbb, int wait) return ret; } +void jrd_rel::setPageSpace(USHORT pageSpaceId) +{ + rel_pages_base.rel_pg_space_id = pageSpaceId; +} + void jrd_rel::downgradeGCLock(thread_db* tdbb) { if (!rel_sweep_count && (rel_flags & REL_gc_blocking)) diff --git a/src/jrd/Relation.h b/src/jrd/Relation.h index 41ffda7b0cf..eab916ad2b9 100644 --- a/src/jrd/Relation.h +++ b/src/jrd/Relation.h @@ -278,6 +278,16 @@ class jrd_rel : public pool_alloc return &rel_pages_base; } + RelationPages* getReplacedPages() + { + return rel_replaced_pages; + } + + void setReplacedPages(RelationPages* pages) + { + rel_replaced_pages = pages; + } + bool delPages(thread_db* tdbb, TraNumber tran = MAX_TRA_NUMBER, RelationPages* aPages = NULL); void retainPages(thread_db* tdbb, TraNumber oldNumber, TraNumber newNumber); @@ -324,6 +334,7 @@ class jrd_rel : public pool_alloc RelationPagesInstances* rel_pages_inst; RelationPages rel_pages_base; RelationPages* rel_pages_free; + RelationPages* rel_replaced_pages; RelationPages* getPagesInternal(thread_db* tdbb, TraNumber tran, bool allocPages); @@ -338,6 +349,8 @@ class jrd_rel : public pool_alloc void downgradeGCLock(thread_db* tdbb); bool acquireGCLock(thread_db* tdbb, int wait); + void setPageSpace(USHORT pageSpaceId); + // This guard is used by regular code to prevent online validation while // dead- or back- versions is removed from disk. class GCShared diff --git a/src/jrd/Tablespace.cpp b/src/jrd/Tablespace.cpp new file mode 100644 index 00000000000..0935dbaadf0 --- /dev/null +++ b/src/jrd/Tablespace.cpp @@ -0,0 +1,50 @@ +/* + * The contents of this file are subject to the Interbase Public + * License Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy + * of the License at http://www.Inprise.com/IPL.html + * + * Software distributed under the License is distributed on an + * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express + * or implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code was created by Inprise Corporation + * and its predecessors. Portions created by Inprise Corporation are + * Copyright (C) Inprise Corporation. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + * + * Adriano dos Santos Fernandes + */ + +#include "firebird.h" +#include "../jrd/Tablespace.h" +#include "../jrd/lck_proto.h" + +using namespace Firebird; + + +namespace Jrd { + +void Tablespace::addRef(thread_db *tdbb) +{ + useCount++; + if (useCount == 1) + { + LCK_lock(tdbb, existenceLock, LCK_SR, LCK_WAIT); + } +} + +void Tablespace::release(thread_db *tdbb) +{ + if (useCount == 1) + { + LCK_release(tdbb, existenceLock); + } + useCount--; +} + + +} // namespace Jrd diff --git a/src/jrd/Tablespace.h b/src/jrd/Tablespace.h new file mode 100644 index 00000000000..806862c6a89 --- /dev/null +++ b/src/jrd/Tablespace.h @@ -0,0 +1,68 @@ +/* + * The contents of this file are subject to the Interbase Public + * License Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy + * of the License at http://www.Inprise.com/IPL.html + * + * Software distributed under the License is distributed on an + * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express + * or implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code was created by Inprise Corporation + * and its predecessors. Portions created by Inprise Corporation are + * Copyright (C) Inprise Corporation. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + * Roman Simakov + */ + +#ifndef JRD_TABLESPACE_H +#define JRD_TABLESPACE_H + +#include "../common/classes/alloc.h" +#include "../common/classes/MetaName.h" +#include "../jrd/pag.h" + +namespace Jrd +{ + class thread_db; + class CompilerScratch; + class JrdStatement; + class Lock; + class Format; + class Parameter; + + class Tablespace : public Firebird::PermanentStorage + { + friend class Attachment; + public: + explicit Tablespace(MemoryPool& p) + : PermanentStorage(p), + id(INVALID_PAGE_SPACE), + name(p), + existenceLock(NULL), + useCount(0) + { + } + + USHORT id; // tablespace id = pagespace id + Firebird::MetaName name; // tablespace name + Lock* existenceLock; // existence lock, if any + + private: + int useCount; + + public: + void addRef(thread_db* tdbb); + void release(thread_db* tdbb); + bool isUsed() const + { + return useCount > 0; + } + + }; +} + +#endif // JRD_TABLESPACE_H diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index d1313c97578..032986a5029 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -192,11 +192,14 @@ static void compress(thread_db*, const dsc*, temporary_key*, USHORT, bool, bool, static USHORT compress_root(thread_db*, index_root_page*); static void copy_key(const temporary_key*, temporary_key*); static contents delete_node(thread_db*, WIN*, UCHAR*); -static void delete_tree(thread_db*, USHORT, USHORT, PageNumber, PageNumber); static DSC* eval(thread_db*, const ValueExprNode*, DSC*, bool*); -static ULONG fast_load(thread_db*, IndexCreation&, SelectivityList&); -static index_root_page* fetch_root(thread_db*, WIN*, const jrd_rel*, const RelationPages*); +void delete_tree(thread_db* tdbb, USHORT, USHORT, PageNumber, PageNumber); //RS: Should it become a part of BTR_proto.h? + +template +static ULONG fast_load(thread_db*, IndexCreation&, SelectivityList&, RS *scb); + +static index_root_page* fetch_root(thread_db*, WIN*, const jrd_rel*, const RelationPages*, bool = false); static UCHAR* find_node_start_point(btree_page*, temporary_key*, UCHAR*, USHORT*, bool, bool, bool = false, RecordNumber = NO_VALUE); @@ -421,7 +424,7 @@ void BTR_create(thread_db* tdbb, index_desc* const idx = creation.index; // Now that the index id has been checked out, create the index. - idx->idx_root = fast_load(tdbb, creation, selectivity); + idx->idx_root = fast_load(tdbb, creation, selectivity, creation.sort); // Index is created. Go back to the index root page and update it to // point to the index. @@ -429,14 +432,14 @@ void BTR_create(thread_db* tdbb, WIN window(relPages->rel_pg_space_id, relPages->rel_index_root); index_root_page* const root = (index_root_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_root); CCH_MARK(tdbb, &window); - root->irt_rpt[idx->idx_id].setRoot(idx->idx_root); + root->irt_rpt[idx->idx_id].setRoot(idx->idx_pg_space_id, idx->idx_root); update_selectivity(root, idx->idx_id, selectivity); CCH_RELEASE(tdbb, &window); } -bool BTR_delete_index(thread_db* tdbb, WIN* window, USHORT id) +bool BTR_delete_index(thread_db* tdbb, Jrd::jrd_rel* relation, WIN* window, USHORT id) { /************************************** * @@ -463,11 +466,12 @@ bool BTR_delete_index(thread_db* tdbb, WIN* window, USHORT id) { index_root_page::irt_repeat* irt_desc = root->irt_rpt + id; CCH_MARK(tdbb, window); - const PageNumber next(window->win_page.getPageSpaceID(), irt_desc->getRoot()); - tree_exists = (irt_desc->getRoot() != 0); + // next is on index page space!!! + const PageNumber next(irt_desc->getRootPageSpaceId(), irt_desc->getRootPage()); + tree_exists = (irt_desc->getRootPage() != 0); // remove the pointer to the top-level index page before we delete it - irt_desc->setRoot(0); + irt_desc->setRoot(0, 0); irt_desc->irt_flags = 0; const PageNumber prior = window->win_page; const USHORT relation_id = root->irt_relation; @@ -501,11 +505,12 @@ bool BTR_description(thread_db* tdbb, jrd_rel* relation, index_root_page* root, const index_root_page::irt_repeat* irt_desc = &root->irt_rpt[id]; - if (irt_desc->getRoot() == 0) + if (irt_desc->getRootPage() == 0) return false; idx->idx_id = id; - idx->idx_root = irt_desc->getRoot(); + idx->idx_pg_space_id = irt_desc->getRootPageSpaceId(); + idx->idx_root = irt_desc->getRootPage(); idx->idx_count = irt_desc->irt_keys; idx->idx_flags = irt_desc->irt_flags; idx->idx_runtime_flags = 0; @@ -693,6 +698,7 @@ void BTR_evaluate(thread_db* tdbb, const IndexRetrieval* retrieval, RecordBitmap index_desc idx; RelationPages* relPages = retrieval->irb_relation->getPages(tdbb); + // In BTR_find_page pagespace can be changed to index's one WIN window(relPages->rel_pg_space_id, -1); temporary_key lower, upper; lower.key_flags = 0; @@ -918,7 +924,9 @@ btree_page* BTR_find_page(thread_db* tdbb, } RelationPages* relPages = retrieval->irb_relation->getPages(tdbb); - fb_assert(window->win_page.getPageSpaceID() == relPages->rel_pg_space_id); + // Now it's possible that win may have index page space + // and we need to change page space for fetching index root page + window->win_page.setPageSpaceID(relPages->rel_pg_space_id); window->win_page = relPages->rel_index_root; index_root_page* rpage = (index_root_page*) CCH_FETCH(tdbb, window, LCK_read, pag_root); @@ -929,7 +937,7 @@ btree_page* BTR_find_page(thread_db* tdbb, IBERROR(260); // msg 260 index unexpectedly deleted } - btree_page* page = (btree_page*) CCH_HANDOFF(tdbb, window, idx->idx_root, LCK_read, pag_index); + btree_page* page = (btree_page*) CCH_HANDOFF(tdbb, window, PageNumber(idx->idx_pg_space_id, idx->idx_root), LCK_read, pag_index); // If there is a starting descriptor, search down index to starting position. // This may involve sibling buckets if splits are in progress. If there @@ -1005,8 +1013,7 @@ void BTR_insert(thread_db* tdbb, WIN* root_window, index_insertion* insertion) SET_TDBB(tdbb); index_desc* idx = insertion->iib_descriptor; - RelationPages* relPages = insertion->iib_relation->getPages(tdbb); - WIN window(relPages->rel_pg_space_id, idx->idx_root); + WIN window(idx->idx_pg_space_id, idx->idx_root); btree_page* bucket = (btree_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_index); UCHAR root_level = bucket->btr_level; @@ -1033,7 +1040,7 @@ void BTR_insert(thread_db* tdbb, WIN* root_window, index_insertion* insertion) // update the index root page. Oh boy. index_root_page* root = (index_root_page*) CCH_FETCH(tdbb, root_window, LCK_write, pag_root); - window.win_page = root->irt_rpt[idx->idx_id].getRoot(); + window.win_page = root->irt_rpt[idx->idx_id].getRootPage(); bucket = (btree_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_index); if (window.win_page.getPageNum() != idx->idx_root) @@ -1083,7 +1090,7 @@ void BTR_insert(thread_db* tdbb, WIN* root_window, index_insertion* insertion) BUGCHECK(204); // msg 204 index inconsistent } - window.win_page = root->irt_rpt[idx->idx_id].getRoot(); + window.win_page = root->irt_rpt[idx->idx_id].getRootPage(); bucket = (btree_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_index); key = ret_key; } @@ -1093,7 +1100,7 @@ void BTR_insert(thread_db* tdbb, WIN* root_window, index_insertion* insertion) // so go ahead and mark it as garbage-collectable now. lock.enablePageGC(tdbb); - WIN new_window(relPages->rel_pg_space_id, split_page); + WIN new_window(idx->idx_pg_space_id, split_page); btree_page* new_bucket = (btree_page*) CCH_FETCH(tdbb, &new_window, LCK_read, pag_index); if (bucket->btr_level != new_bucket->btr_level) @@ -1166,7 +1173,7 @@ void BTR_insert(thread_db* tdbb, WIN* root_window, index_insertion* insertion) CCH_RELEASE(tdbb, &new_window); CCH_precedence(tdbb, root_window, new_window.win_page); CCH_MARK(tdbb, root_window); - root->irt_rpt[idx->idx_id].setRoot(new_window.win_page.getPageNum()); + root->irt_rpt[idx->idx_id].setRoot(new_window.win_page.getPageSpaceID(), new_window.win_page.getPageNum()); CCH_RELEASE(tdbb, root_window); } @@ -1792,7 +1799,7 @@ bool BTR_next_index(thread_db* tdbb, jrd_rel* relation, jrd_tra* transaction, in irt_desc = root->irt_rpt + id; if (irt_desc->getTransaction() == trans) - BTR_delete_index(tdbb, window, id); + BTR_delete_index(tdbb, relation, window, id); else CCH_RELEASE(tdbb, window); @@ -1829,8 +1836,7 @@ void BTR_remove(thread_db* tdbb, WIN* root_window, index_insertion* insertion) //const Database* dbb = tdbb->getDatabase(); index_desc* idx = insertion->iib_descriptor; - RelationPages* relPages = insertion->iib_relation->getPages(tdbb); - WIN window(relPages->rel_pg_space_id, idx->idx_root); + WIN window(idx->idx_pg_space_id, idx->idx_root); btree_page* page = (btree_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_index); // If the page is level 0, re-fetch it for write @@ -1876,7 +1882,7 @@ void BTR_remove(thread_db* tdbb, WIN* root_window, index_insertion* insertion) } CCH_MARK(tdbb, root_window); - root->irt_rpt[idx->idx_id].setRoot(number); + root->irt_rpt[idx->idx_id].setRoot(idx->idx_pg_space_id, number); // release the pages, and place the page formerly at the top level // on the free list, making sure the root page is written out first @@ -2050,18 +2056,26 @@ void BTR_selectivity(thread_db* tdbb, jrd_rel* relation, USHORT id, SelectivityL return; ULONG page; - if (id >= root->irt_count || !(page = root->irt_rpt[id].getRoot())) + if (id >= root->irt_count || !(page = root->irt_rpt[id].getRootPage())) { CCH_RELEASE(tdbb, &window); return; } + index_desc idx; + if (!BTR_description(tdbb, relation, root, &idx, id)) + { + CCH_RELEASE(tdbb, &window); + return; + } + + const bool descending = (root->irt_rpt[id].irt_flags & irt_descending); const ULONG segments = root->irt_rpt[id].irt_keys; window.win_flags = WIN_large_scan; window.win_scans = 1; - btree_page* bucket = (btree_page*) CCH_HANDOFF(tdbb, &window, page, LCK_read, pag_index); + btree_page* bucket = (btree_page*) CCH_HANDOFF(tdbb, &window, PageNumber(idx.idx_pg_space_id, page), LCK_read, pag_index); // go down the left side of the index to leaf level UCHAR* pointer = bucket->btr_nodes + bucket->btr_jump_size; @@ -2274,6 +2288,143 @@ bool BTR_types_comparable(const dsc& target, const dsc& source) return false; } +class IndexNodes +{ +public: + IndexNodes(Jrd::thread_db* tdbb, const IndexCreation& creation, WIN* window): + window(window), key_length(creation.key_length) + { + recordData.resize(key_length + sizeof(index_sort_record)); + isr = reinterpret_cast(&recordData[key_length]); + btree_page* bucket = (btree_page*)window->win_buffer; + pointer = bucket->btr_nodes + bucket->btr_jump_size; + end = (UCHAR*) bucket + bucket->btr_length; + nullIndLen = !(creation.index->idx_flags & idx_descending) && (creation.index->idx_count == 1) ? 1 : 0; + } + + void get(Jrd::thread_db* tdbb, ULONG** record) + { + pointer = node.readNode(pointer, true); + // Check if pointer is still valid + if (pointer > end) + BUGCHECK(204); // msg 204 index inconsistent + + if (node.isEndBucket) + { + btree_page* bucket = (btree_page*)window->win_buffer; + if (!bucket->btr_sibling) + { + *record = 0; + return; + } + bucket = (btree_page*)CCH_HANDOFF(tdbb, window, bucket->btr_sibling, LCK_read, pag_index); + pointer = bucket->btr_nodes + bucket->btr_jump_size; + end = (UCHAR*) bucket + bucket->btr_length; + pointer = node.readNode(pointer, true); + // Check if pointer is still valid + if (pointer > end) + BUGCHECK(204); // msg 204 index inconsistent + } + + if (!node.isEndLevel) + { + memcpy(&recordData[node.prefix] + nullIndLen, node.data, node.length); + isr->isr_record_number = node.recordNumber.getValue(); + isr->isr_key_length = node.length + node.prefix; + *record = reinterpret_cast(&recordData[0]); + } + else + *record = 0; + } + +private: + WIN* window; + UCHAR* pointer; + UCHAR* end; + USHORT key_length; + IndexNode node; + Array recordData; + index_sort_record* isr; + int nullIndLen; +}; + +bool BTR_move_index(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, SLONG indexId, USHORT pageSpaceId, PageNumber& oldRootPage) +{ +/************************************** + * + * B T R _ m o v e _ i n d e x + * + ************************************** + * + * Functional description + * Move index pages from its tablespace to new one. + * + **************************************/ + + SET_TDBB(tdbb); + Database* dbb = tdbb->getDatabase(); + + bool result = false; + + // Lets start copy index pages + WIN rootWindow(INVALID_PAGE_SPACE, -1); + index_root_page* root = fetch_root(tdbb, &rootWindow, relation, relation->getPages(tdbb), true); + + index_desc idx; + if (BTR_description(tdbb, relation, root, &idx, indexId)) + { + oldRootPage = PageNumber(idx.idx_pg_space_id, idx.idx_root); + + // Set page space id of the new tablespace + idx.idx_pg_space_id = pageSpaceId; + + IndexCreation creation; + creation.index = &idx; + creation.relation = relation; + //creation.sort is unused in this fast_load call + //creation.transaction is unused in this fast_load call + + const int nullIndLen = !(idx.idx_flags & idx_descending) && (idx.idx_count == 1) ? 1 : 0; + creation.key_length = ROUNDUP(BTR_key_length(tdbb, relation, &idx) + nullIndLen, sizeof(SINT64));; + + // Fall down to level 0 + WIN window(oldRootPage); + btree_page* page = (btree_page*)CCH_FETCH(tdbb, &window, LCK_read, pag_index); + IndexNode node; + while (page->btr_level > 0) + { + UCHAR* pointer; + const UCHAR* const endPointer = (UCHAR*) page + page->btr_length; + pointer = page->btr_nodes + page->btr_jump_size; + pointer = node.readNode(pointer, false); + + // Check if pointer is still valid + if (pointer > endPointer) + BUGCHECK(204); // msg 204 index inconsistent + + page = (btree_page*) CCH_HANDOFF(tdbb, &window, node.pageNumber, LCK_read, pag_index); + } + + IndexNodes indexNodes(tdbb, creation, &window); + + SelectivityList selectivity; + + const ULONG newRootPage = fast_load(tdbb, creation, selectivity, &indexNodes); + + CCH_RELEASE(tdbb, &window); + + CCH_MARK(tdbb, &rootWindow); + root->irt_rpt[indexId].setRoot(pageSpaceId, newRootPage); + CCH_RELEASE(tdbb, &rootWindow); + + result = true; + } + else + CCH_RELEASE(tdbb, &rootWindow); + + return result; +} + static ULONG add_node(thread_db* tdbb, WIN* window, @@ -2875,7 +3026,7 @@ static USHORT compress_root(thread_db* tdbb, index_root_page* page) for (const index_root_page::irt_repeat* const end = root_idx + page->irt_count; root_idx < end; root_idx++) { - if (root_idx->getRoot()) + if (root_idx->getRootPage()) { const USHORT len = root_idx->irt_keys * sizeof(irtd); p -= len; @@ -3200,7 +3351,7 @@ static contents delete_node(thread_db* tdbb, WIN* window, UCHAR* pointer) } -static void delete_tree(thread_db* tdbb, +void delete_tree(thread_db* tdbb, USHORT rel_id, USHORT idx_id, PageNumber next, PageNumber prior) { /************************************** @@ -3303,10 +3454,10 @@ static DSC* eval(thread_db* tdbb, const ValueExprNode* node, DSC* temp, bool* is return temp; } - +template static ULONG fast_load(thread_db* tdbb, IndexCreation& creation, - SelectivityList& selectivity) + SelectivityList& selectivity, RS* scb) { /************************************** * @@ -3331,9 +3482,8 @@ static ULONG fast_load(thread_db* tdbb, jrd_rel* const relation = creation.relation; index_desc* const idx = creation.index; const USHORT key_length = creation.key_length; - Sort* const scb = creation.sort; - const USHORT pageSpaceID = relation->getPages(tdbb)->rel_pg_space_id; + const USHORT pageSpaceID = idx->idx_pg_space_id; // leaf-page and pointer-page size limits, we always need to // leave room for the END_LEVEL node. @@ -4087,7 +4237,7 @@ static ULONG fast_load(thread_db* tdbb, static index_root_page* fetch_root(thread_db* tdbb, WIN* window, const jrd_rel* relation, - const RelationPages* relPages) + const RelationPages* relPages, bool writeLock) { /************************************** * @@ -4103,20 +4253,21 @@ static index_root_page* fetch_root(thread_db* tdbb, WIN* window, const jrd_rel* **************************************/ SET_TDBB(tdbb); - if ((window->win_page = relPages->rel_index_root) == 0) + if (!relPages->rel_index_root) { - if (relation->rel_id == 0) - return NULL; +// if (relation->rel_id == 0) +// return NULL; - DPM_scan_pages(tdbb); + DPM_scan_pages(tdbb, pag_root, relation->rel_id); if (!relPages->rel_index_root) return NULL; - window->win_page = relPages->rel_index_root; } - return (index_root_page*) CCH_FETCH(tdbb, window, LCK_read, pag_root); + window->win_page = PageNumber(relPages->rel_pg_space_id, relPages->rel_index_root); + + return (index_root_page*) CCH_FETCH(tdbb, window, writeLock ? LCK_write : LCK_read, pag_root); } diff --git a/src/jrd/btr.h b/src/jrd/btr.h index baaeb37a71d..5ab241533dc 100644 --- a/src/jrd/btr.h +++ b/src/jrd/btr.h @@ -67,6 +67,7 @@ struct index_desc ValueExprNode* idx_expression; // node tree for indexed expresssion dsc idx_expression_desc; // descriptor for expression result JrdStatement* idx_expression_statement; // stored statement for expression evaluation + USHORT idx_pg_space_id; // PageSpace of index pages // This structure should exactly match IRTD structure for current ODS struct idx_repeat { @@ -290,7 +291,7 @@ class IndexErrorContext bool isLocationDefined; }; - } //namespace Jrd + #endif // JRD_BTR_H diff --git a/src/jrd/btr_proto.h b/src/jrd/btr_proto.h index 71a38586fa5..f6b34d49de7 100644 --- a/src/jrd/btr_proto.h +++ b/src/jrd/btr_proto.h @@ -32,7 +32,7 @@ USHORT BTR_all(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::IndexDescAlloc**, Jrd::RelationPages*); void BTR_complement_key(Jrd::temporary_key*); void BTR_create(Jrd::thread_db*, Jrd::IndexCreation&, Jrd::SelectivityList&); -bool BTR_delete_index(Jrd::thread_db*, Jrd::win*, USHORT); +bool BTR_delete_index(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::win*, USHORT); bool BTR_description(Jrd::thread_db*, Jrd::jrd_rel*, Ods::index_root_page*, Jrd::index_desc*, USHORT); DSC* BTR_eval_expression(Jrd::thread_db*, Jrd::index_desc*, Jrd::Record*, bool&); void BTR_evaluate(Jrd::thread_db*, const Jrd::IndexRetrieval*, Jrd::RecordBitmap**, Jrd::RecordBitmap*); @@ -53,5 +53,7 @@ void BTR_remove(Jrd::thread_db*, Jrd::win*, Jrd::index_insertion*); void BTR_reserve_slot(Jrd::thread_db*, Jrd::IndexCreation&); void BTR_selectivity(Jrd::thread_db*, Jrd::jrd_rel*, USHORT, Jrd::SelectivityList&); bool BTR_types_comparable(const dsc& target, const dsc& source); +bool BTR_move_index(Jrd::thread_db*, Jrd::jrd_rel*, SLONG, USHORT, Jrd::PageNumber&); + #endif // JRD_BTR_PROTO_H diff --git a/src/jrd/cch.cpp b/src/jrd/cch.cpp index b168a61d4da..04aff20ff9a 100644 --- a/src/jrd/cch.cpp +++ b/src/jrd/cch.cpp @@ -1314,7 +1314,7 @@ void CCH_get_related(thread_db* tdbb, PageNumber page, PagesArray &lowPages) } -pag* CCH_handoff(thread_db* tdbb, WIN* window, ULONG page, int lock, SCHAR page_type, +pag* CCH_handoff(thread_db* tdbb, WIN* window, PageNumber pageNumber, int lock, SCHAR page_type, int wait, const bool release_tail) { /************************************** @@ -1348,8 +1348,9 @@ pag* CCH_handoff(thread_db* tdbb, WIN* window, ULONG page, int lock, SCHAR page_ SET_TDBB(tdbb); - CCH_TRACE(("HANDOFF %d:%06d->%06d, %s", - window->win_page.getPageSpaceID(), window->win_page.getPageNum(), page, (lock >= LCK_write) ? "EX" : "SH")); + CCH_TRACE(("HANDOFF %d:%06d->%d:%06d, %s", + window->win_page.getPageSpaceID(), window->win_page.getPageNum(), + pageNumber.getPageSpaceID(), pageNumber.getPageNum(), (lock >= LCK_write) ? "EX" : "SH")); BufferDesc *bdb = window->win_bdb; @@ -1363,7 +1364,7 @@ pag* CCH_handoff(thread_db* tdbb, WIN* window, ULONG page, int lock, SCHAR page_ // If the 'from-page' and 'to-page' of the handoff are the // same and the latch requested is shared then downgrade it. - if ((window->win_page.getPageNum() == page) && (lock == LCK_read)) + if ((window->win_page == pageNumber) && (lock == LCK_read)) { if (bdb->ourExclusiveLock()) bdb->downgrade(SYNC_SHARED); @@ -1372,7 +1373,7 @@ pag* CCH_handoff(thread_db* tdbb, WIN* window, ULONG page, int lock, SCHAR page_ } WIN temp = *window; - window->win_page = PageNumber(window->win_page.getPageSpaceID(), page); + window->win_page = pageNumber; // This prevents a deadlock with the precedence queue, as shown by // mwrite mwrite1 2 mwrite2 2 test.fdb @@ -3114,7 +3115,9 @@ static void check_precedence(thread_db* tdbb, WIN* window, PageNumber page) // If this is really a transaction id, sort things out - switch(page.getPageSpaceID()) + const USHORT pageSpaceId = page.getPageSpaceID(); + + switch(pageSpaceId) { case DB_PAGE_SPACE: break; @@ -3126,6 +3129,8 @@ static void check_precedence(thread_db* tdbb, WIN* window, PageNumber page) break; default: + if ((pageSpaceId > DB_PAGE_SPACE) && (pageSpaceId < TRANS_PAGE_SPACE)) + break; // tablespace fb_assert(false); return; } diff --git a/src/jrd/cch_proto.h b/src/jrd/cch_proto.h index c04f204b42b..eec794bb6b2 100644 --- a/src/jrd/cch_proto.h +++ b/src/jrd/cch_proto.h @@ -55,7 +55,7 @@ void CCH_flush(Jrd::thread_db* tdbb, USHORT flush_flag, TraNumber tra_number); bool CCH_free_page(Jrd::thread_db*); SLONG CCH_get_incarnation(Jrd::win*); void CCH_get_related(Jrd::thread_db*, Jrd::PageNumber, Jrd::PagesArray&); -Ods::pag* CCH_handoff(Jrd::thread_db*, Jrd::win*, ULONG, int, SCHAR, int, const bool); +Ods::pag* CCH_handoff(Jrd::thread_db*, Jrd::win*, Jrd::PageNumber, int, SCHAR, int, const bool); void CCH_init(Jrd::thread_db*, ULONG); void CCH_init2(Jrd::thread_db*); void CCH_mark(Jrd::thread_db*, Jrd::win*, bool, bool); @@ -116,17 +116,22 @@ inline void CCH_MARK_SYSTEM(Jrd::thread_db* tdbb, Jrd::win* window) inline Ods::pag* CCH_HANDOFF(Jrd::thread_db* tdbb, Jrd::win* window, ULONG page, SSHORT lock, SCHAR page_type) { - return CCH_handoff (tdbb, window, page, lock, page_type, 1, false); + return CCH_handoff (tdbb, window, Jrd::PageNumber(window->win_page.getPageSpaceID(), page), lock, page_type, 1, false); } inline Ods::pag* CCH_HANDOFF_TIMEOUT(Jrd::thread_db* tdbb, Jrd::win* window, ULONG page, SSHORT lock, SCHAR page_type, SSHORT latch_wait) { - return CCH_handoff (tdbb, window, page, lock, page_type, latch_wait, false); + return CCH_handoff (tdbb, window, Jrd::PageNumber(window->win_page.getPageSpaceID(), page), lock, page_type, latch_wait, false); } inline Ods::pag* CCH_HANDOFF_TAIL(Jrd::thread_db* tdbb, Jrd::win* window, ULONG page, SSHORT lock, SCHAR page_type) { - return CCH_handoff (tdbb, window, page, lock, page_type, 1, true); + return CCH_handoff (tdbb, window, Jrd::PageNumber(window->win_page.getPageSpaceID(), page), lock, page_type, 1, true); +} + +inline Ods::pag* CCH_HANDOFF(Jrd::thread_db* tdbb, Jrd::win* window, Jrd::PageNumber pageNumber, SSHORT lock, SCHAR page_type) +{ + return CCH_handoff (tdbb, window, pageNumber, lock, page_type, 1, false); } inline void CCH_MARK_MUST_WRITE(Jrd::thread_db* tdbb, Jrd::win* window) diff --git a/src/jrd/constants.h b/src/jrd/constants.h index 72b463455fd..6539daca986 100644 --- a/src/jrd/constants.h +++ b/src/jrd/constants.h @@ -388,7 +388,10 @@ static const char* const DDL_TRIGGER_ACTION_NAMES[][2] = {"DROP", "PACKAGE BODY"}, {"CREATE", "MAPPING"}, {"ALTER", "MAPPING"}, - {"DROP", "MAPPING"} + {"DROP", "MAPPING"}, + {"CREATE", "TABLESPACE"}, + {"ALTER", "TABLESPACE"}, + {"DROP", "TABLESPACE"} }; const int DDL_TRIGGER_BEFORE = 0; @@ -441,6 +444,9 @@ const int DDL_TRIGGER_DROP_PACKAGE_BODY = 44; const int DDL_TRIGGER_CREATE_MAPPING = 45; const int DDL_TRIGGER_ALTER_MAPPING = 46; const int DDL_TRIGGER_DROP_MAPPING = 47; +const int DDL_TRIGGER_CREATE_TABLESPACE = 48; +const int DDL_TRIGGER_ALTER_TABLESPACE = 49; +const int DDL_TRIGGER_DROP_TABLESPACE = 50; // that's how database trigger action types are encoded // (TRIGGER_TYPE_DB | type) diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 1911d8ee0ae..cb9e9d89472 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -126,6 +126,8 @@ #include "../jrd/CryptoManager.h" #include "../jrd/Mapping.h" #include "../jrd/shut_proto.h" +#include "../jrd/Tablespace.h" +#include "../jrd/vio_proto.h" #ifdef HAVE_UNISTD_H #include @@ -485,6 +487,12 @@ static bool grant_privileges(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool db_crypt(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool set_linger(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool clear_cache(thread_db*, SSHORT, DeferredWork*, jrd_tra*); +static bool create_tablespace(thread_db*, SSHORT, DeferredWork*, jrd_tra*); +static bool check_tablespace_dependencies(thread_db*, SSHORT, DeferredWork*, jrd_tra*); +static bool drop_tablespace_dependencies(thread_db*, SSHORT, DeferredWork*, jrd_tra*); +static bool move_relation(thread_db*, SSHORT, DeferredWork*, jrd_tra*); +static bool move_index(thread_db*, SSHORT, DeferredWork*, jrd_tra*); + // ---------------------------------------------------------------- @@ -1233,6 +1241,11 @@ static const deferred_task task_table[] = { dfw_db_crypt, db_crypt }, { dfw_set_linger, set_linger }, { dfw_clear_cache, clear_cache }, + { dfw_create_tablespace, create_tablespace }, + { dfw_check_tablespace_dependencies, check_tablespace_dependencies }, + { dfw_drop_tablespace_dependencies, drop_tablespace_dependencies }, + { dfw_move_relation, move_relation }, + { dfw_move_index, move_index }, { dfw_null, NULL } }; @@ -1556,6 +1569,8 @@ void DFW_perform_work(thread_db* tdbb, jrd_tra* transaction) { case dfw_post_event: case dfw_delete_shadow: + case dfw_clear_datapages: + case dfw_clear_indexpages: break; default: @@ -1571,8 +1586,9 @@ void DFW_perform_work(thread_db* tdbb, jrd_tra* transaction) } } +void delete_tree(thread_db* tdbb, USHORT, USHORT, PageNumber, PageNumber); -void DFW_perform_post_commit_work(jrd_tra* transaction) +void DFW_perform_post_commit_work(thread_db* tdbb, jrd_tra* transaction) { /************************************** * @@ -1594,7 +1610,8 @@ void DFW_perform_post_commit_work(jrd_tra* transaction) bool pending_events = false; - Database* dbb = GET_DBB(); + SET_TDBB(tdbb); + Database* dbb = tdbb->getDatabase(); for (DeferredWork* itr = transaction->tra_deferred_job->work; itr;) { @@ -1610,17 +1627,51 @@ void DFW_perform_post_commit_work(jrd_tra* transaction) work->dfw_name.c_str(), work->dfw_count); - delete work; pending_events = true; break; case dfw_delete_shadow: if (work->dfw_name.hasData()) unlink(work->dfw_name.c_str()); - delete work; break; + case dfw_clear_datapages: + { + jrd_rel* relation = MET_lookup_relation_id(tdbb, work->dfw_id, false); + RelationPages* relationPages = relation->getPages(tdbb); + DPM_delete_relation_pages(tdbb, relation, relationPages); + + RelationPages* newRelationPages = relation->getReplacedPages(); + // Regenerate RDB$PAGES for the new relation + { + AutoRequest handle; + + DPM_pages(tdbb, relation->rel_id, pag_root, 0, newRelationPages->rel_index_root); + ULONG* page = &(*newRelationPages->rel_pages)[0]; + const FB_SIZE_T n = newRelationPages->rel_pages->count(); + for (FB_SIZE_T seq = 0; seq < n; seq++, page++) + DPM_pages(tdbb, relation->rel_id, pag_pointer, seq, *page); + } + + CCH_flush(tdbb, FLUSH_SYSTEM, 0); + + *relationPages = *newRelationPages; + } + break; + case dfw_clear_indexpages: + { + SortedArray& ids = DFW_get_ids(work); + fb_assert(ids.getCount() == 3); + const SLONG indexId = ids[0]; + const PageNumber oldRootPage(ids[1], ids[2]); + delete_tree(tdbb, work->dfw_id, indexId, oldRootPage, PageNumber()); + } + + break; + default: break; } + + delete work; } if (pending_events) @@ -2689,6 +2740,7 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* jrd_rel* relation = NULL; index_desc idx; MemoryPool* new_pool = NULL; + MetaName tableSpace; SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); @@ -2744,6 +2796,9 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* if (IDX.RDB$INDEX_TYPE == 1) idx.idx_flags |= idx_descending; + if (!IDX.RDB$TABLESPACE_NAME.NULL) + tableSpace = IDX.RDB$TABLESPACE_NAME; + CompilerScratch* csb = NULL; // allocate a new pool to contain the expression tree for the expression index new_pool = attachment->createPool(); @@ -2800,6 +2855,7 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* { fb_assert(work->dfw_id <= dbb->dbb_max_idx); idx.idx_id = work->dfw_id; + idx.idx_pg_space_id = MET_tablespace(tdbb, tableSpace)->id; IDX_create_index(tdbb, relation, &idx, work->dfw_name.c_str(), &work->dfw_id, transaction, selectivity); @@ -3049,7 +3105,7 @@ static void cleanup_index_creation(thread_db* tdbb, DeferredWork* work, jrd_tra* WIN window(relPages->rel_pg_space_id, relPages->rel_index_root); CCH_FETCH(tdbb, &window, LCK_write, pag_root); CCH_MARK_MUST_WRITE(tdbb, &window); - const bool tree_exists = BTR_delete_index(tdbb, &window, work->dfw_id); + const bool tree_exists = BTR_delete_index(tdbb, relation, &window, work->dfw_id); if (!isTempIndex) { work->dfw_id = dbb->dbb_max_idx; @@ -3327,6 +3383,8 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ relation = NULL; idx.idx_flags = 0; + MetaName tableSpace; + // Fetch the information necessary to create the index. On the first // time thru, check to see if the index already exists. If so, delete // it. If the index inactive flag is set, don't create the index @@ -3346,6 +3404,12 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ // Msg308: can't create index %s } + if (!IDX.RDB$TABLESPACE_NAME.NULL) + tableSpace = IDX.RDB$TABLESPACE_NAME; + else // By default index data is in tablespace of relation + if (!REL.RDB$TABLESPACE_NAME.NULL) + tableSpace = REL.RDB$TABLESPACE_NAME; + if (IDX.RDB$INDEX_ID && IDX.RDB$STATISTICS < 0.0) { // we need to know if this relation is temporary or not @@ -3583,6 +3647,7 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ fb_assert(work->dfw_id <= dbb->dbb_max_idx); idx.idx_id = work->dfw_id; + idx.idx_pg_space_id = MET_tablespace(tdbb, tableSpace)->id; SelectivityList selectivity(*tdbb->getDefaultPool()); IDX_create_index(tdbb, relation, &idx, work->dfw_name.c_str(), &work->dfw_id, transaction, selectivity); @@ -6348,6 +6413,421 @@ static bool scan_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd return false; } + +static bool create_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction) +{ +/************************************** + * + * c r e a t e _ t a b l e s p a c e + * + ************************************** + * + * Functional description + * Create tablespace file and format it when restoring + * + **************************************/ + + SET_TDBB(tdbb); + Database* dbb = tdbb->getDatabase(); + + switch (phase) + { + case 0: + { + fb_assert(work->dfw_id > DB_PAGE_SPACE); + + AutoCacheRequest request(tdbb, irq_find_ts_dfw0, IRQ_REQUESTS); + + bool found = false; + PathName file; + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + TS IN RDB$TABLESPACES + WITH TS.RDB$TABLESPACE_ID EQ work->dfw_id + { + found = true; + file = TS.RDB$FILE_NAME; + } + END_FOR + + if (!found) + return false; + + unlink(file.c_str()); + } + return false; + + case 1: + return true; + + case 2: + { + fb_assert(work->dfw_id > DB_PAGE_SPACE); + + AutoCacheRequest request(tdbb, irq_find_ts_dfw, IRQ_REQUESTS); + + bool found = false; + PathName file; + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + TS IN RDB$TABLESPACES + WITH TS.RDB$TABLESPACE_ID EQ work->dfw_id + { + found = true; + file = TS.RDB$FILE_NAME; + } + END_FOR + + if (!found) + status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(work->dfw_name)); + + dbb->dbb_page_manager.allocTableSpace(tdbb, work->dfw_id, true, file); + } + return true; + + case 3: + case 4: + break; + } + + return false; +} + + +static bool check_tablespace_dependencies(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction) +{ +/************************************** + * + * c h e c k _ t a b l e s p a c e _ d e p e n d e n c i e s + * + ************************************** + * + * Functional description + * Check tablespace dependencies before drop + * + **************************************/ + + SET_TDBB(tdbb); + Database* dbb = tdbb->getDatabase(); + Attachment* attachment = tdbb->getAttachment(); + + switch (phase) + { + case 1: + { + SLONG total = 0; + + { // Find all indices + AutoCacheRequest requestHandle(tdbb, irq_ts_find_idx_dfw, DYN_REQUESTS); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + X IN RDB$INDICES + WITH X.RDB$TABLESPACE_NAME EQ work->dfw_name.c_str() + { + total++; + } + END_FOR + } + + { // Find all tables + AutoCacheRequest requestHandle(tdbb, irq_ts_find_rel_dfw, DYN_REQUESTS); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + X IN RDB$RELATIONS + WITH X.RDB$TABLESPACE_NAME EQ work->dfw_name.c_str() + { + total++; + } + END_FOR + } + + if (total) + { + status_exception::raise(Arg::Gds(isc_no_meta_update) << + Arg::Gds(isc_no_delete) << // Msg353: can not delete + Arg::Gds(isc_tablespace_name) << Arg::Str(work->dfw_name) << + Arg::Gds(isc_dependency) << Arg::Num(total)); // Msg310: there are %ld dependencies + } + } + return true; + + case 2: + case 3: + case 4: + break; + } + + return false; +} + + +static bool drop_tablespace_dependencies(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction) +{ +/************************************** + * + * d r o p _ t a b l e s p a c e _ d e p e n d e n c i e s + * + ************************************** + * + * Functional description + * Drop tablespace dependencies + * + **************************************/ + + SET_TDBB(tdbb); + Database* dbb = tdbb->getDatabase(); + Attachment* attachment = tdbb->getAttachment(); + + switch (phase) + { + case 0: + if (work->dfw_id <= attachment->getTablespaceCount()) + { + Tablespace* tablespace = attachment->getTablespace(work->dfw_id); + if ( tablespace->existenceLock && tablespace->isUsed() ) + LCK_convert(tdbb, tablespace->existenceLock, LCK_SR, transaction->getLockWait()); + } + return false; + + case 1: + { + // Make sure nobady uses tablespace + if (work->dfw_id <= attachment->getTablespaceCount()) + { + Tablespace* tablespace = attachment->getTablespace(work->dfw_id); + if ( (tablespace && tablespace->isUsed()) || // RS: if isUsed maybe I must try to convert SR to EX? + (tablespace->existenceLock && + !LCK_lock(tdbb, tablespace->existenceLock, LCK_EX, transaction->getLockWait()) ) + ) + { + raiseObjectInUseError("TABLESPACE", work->dfw_name); + } + } + + { // Find all indices + AutoCacheRequest requestHandle(tdbb, irq_ts_drop_idx_dfw, DYN_REQUESTS); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + X IN RDB$INDICES + WITH X.RDB$TABLESPACE_NAME EQ work->dfw_name.c_str() + { + ERASE X; + } + END_FOR + } + + { // Find all tables + AutoCacheRequest requestHandle(tdbb, irq_ts_drop_rel_dfw, DYN_REQUESTS); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + X IN RDB$RELATIONS + WITH X.RDB$TABLESPACE_NAME EQ work->dfw_name.c_str() + { + ERASE X; + } + END_FOR + } + } + return true; + + case 2: + case 3: + return true; + case 4: + if (work->dfw_id <= attachment->getTablespaceCount()) + { + Tablespace* tablespace = attachment->getTablespace(work->dfw_id); + if (tablespace->existenceLock) + LCK_release(tdbb, tablespace->existenceLock); + } + + break; + } + + return false; +} + +static bool move_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction) +{ +/************************************** + * + * move_relation + * + ************************************** + * + * Functional description + * Move relation from its tablespace to new one. + * + **************************************/ + + SET_TDBB(tdbb); + Database* dbb = tdbb->getDatabase(); + Attachment* attachment = tdbb->getAttachment(); + + switch (phase) + { + case 0: + // Probably it's good to check here that we have reverted both the first + // pointer page and index root or force it. + CCH_release_exclusive(tdbb); + break; + + case 1: + // We ask EX lock on DB to prevent relation changing and keep data consistent. + // This is a temporary solution. It's better to migrate data of a tablespace + // without locking the whole DB but with locking only relation. + if (!CCH_exclusive(tdbb, LCK_EX, WAIT_PERIOD, NULL)) + raiseDatabaseInUseError(true); + return true; + + case 2: + { + jrd_rel* relation = MET_lookup_relation_id(tdbb, work->dfw_id, false); + RelationPages* newRelationPages = FB_NEW_POOL(*relation->rel_pool) RelationPages(*relation->rel_pool); + + // Metadata was changed at Ddl stage and now contains new pagespace id + newRelationPages->rel_pg_space_id = MET_rel_pagespace(tdbb, relation->rel_id); + + // Scan pages before cleanup relation. Maybe redundant? + // Or maybe to scan starting from the last known sequence? + DPM_scan_pages(tdbb, pag_pointer, relation->rel_id); + DPM_scan_pages(tdbb, pag_root, relation->rel_id); + + RelationPages* relationPages = relation->getPages(tdbb); + + // Copy index root page to a new relation tablespace + // And free previos one + WIN oldWindow(relationPages->rel_pg_space_id, relationPages->rel_index_root); + Ods::pag* oldPage = CCH_FETCH(tdbb, &oldWindow, LCK_read, pag_root); + + WIN newWindow(newRelationPages->rel_pg_space_id, -1); + Ods::pag* newPage = DPM_allocate(tdbb, &newWindow); + CCH_MARK_MUST_WRITE(tdbb, &newWindow); + memcpy(newPage, oldPage, dbb->dbb_page_size); + newPage->pag_pageno = newWindow.win_page.getPageNum(); + newRelationPages->rel_index_root = newWindow.win_page.getPageNum(); + + CCH_RELEASE(tdbb, &newWindow); + CCH_RELEASE(tdbb, &oldWindow); + + DPM_move_data_pages(tdbb, relation, newRelationPages); + + relation->setReplacedPages(newRelationPages); + + { // We delete all from RDB$PAGES about the relation to have an ability to understand that + // we need to restore pages if transaction won't be able to finish succeccfully. + AutoRequest handle; + + FOR(REQUEST_HANDLE handle) X IN RDB$PAGES + WITH (X.RDB$RELATION_ID EQ relation->rel_id) + SORTED BY DESCENDING X.RDB$PAGE_SEQUENCE + { + ERASE X; + } + END_FOR + } + + // Post commit work will clean up old pages. It must be done exactly after commit + // If crash is happend the metadata will point to the old page space and new ones + // will be garbage. Right after commit old pages will be garbage. + DFW_post_work(transaction, dfw_clear_datapages, NULL, relation->rel_id); + } + break; + + case 3: + case 4: + break; + } + + return false; +} + + +static bool move_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction) +{ +/************************************** + * + * move_index + * + ************************************** + * + * Functional description + * Move index pages from its tablespace to new one. + * + **************************************/ + + SET_TDBB(tdbb); + Database* dbb = tdbb->getDatabase(); + Attachment* attachment = tdbb->getAttachment(); + + switch (phase) + { + case 0: + CCH_release_exclusive(tdbb); + break; + + case 1: + // We ask EX lock on DB to prevent relation changing and keep data consistent. + // This is a temporary solution. It's better to migrate data of a tablespace + // without locking the whole DB but with locking only relation. + if (!CCH_exclusive(tdbb, LCK_EX, WAIT_PERIOD, NULL)) + raiseDatabaseInUseError(true); + return true; + + case 2: + { + // Fetch relation and index id by index name + PreparedStatement::Builder sql; + jrd_rel* relation = NULL; + SLONG relationId; + SLONG indexId; + MetaName tableSpace; + sql << "select" + << sql("rel.rdb$relation_id,", relationId) + << sql("idx.rdb$index_id,", indexId) + << sql("idx.rdb$tablespace_name", tableSpace) + << "from rdb$indices idx join rdb$relations rel using (rdb$relation_name)" + << "where idx.rdb$index_name = " << work->dfw_name + << " and rel.rdb$relation_id is not null"; + AutoPreparedStatement ps(attachment->prepareStatement(tdbb, + attachment->getSysTransaction(), sql)); + AutoResultSet rs(ps->executeQuery(tdbb, attachment->getSysTransaction())); + + while (rs->fetch(tdbb)) + { + relation = MET_lookup_relation_id(tdbb, relationId, false); + indexId--; // ID of a index starts from 1 in metadata and from 0 in code :) + break; + } + + fb_assert(relation); + + const USHORT newPageSpaceId = MET_tablespace(tdbb, tableSpace)->id; + + PageNumber oldRootPage; + if (BTR_move_index(tdbb, relation, indexId, newPageSpaceId, oldRootPage)) + { + // Futher transaction must finish and flush its pages to the disk. + // It actually switched pointer. If server crash before it the database file will have the old data. + DeferredWork* work = DFW_post_work(transaction, dfw_clear_indexpages, NULL, relation->rel_id); + SortedArray& ids = DFW_get_ids(work); + ids.resize(3); + ids[0] = indexId; + ids[1] = oldRootPage.getPageSpaceID(); + ids[2] = oldRootPage.getPageNum(); + } + } + break; + + case 3: + case 4: + break; + } + + return false; +} + + #ifdef NOT_USED_OR_REPLACED static bool shadow_defined(thread_db* tdbb) { diff --git a/src/jrd/dfw_proto.h b/src/jrd/dfw_proto.h index e7794e03fdd..bec7b32fe9a 100644 --- a/src/jrd/dfw_proto.h +++ b/src/jrd/dfw_proto.h @@ -37,7 +37,7 @@ 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*); +void DFW_perform_post_commit_work(Jrd::thread_db*, 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 Firebird::MetaName& package = NULL); diff --git a/src/jrd/dpm.epp b/src/jrd/dpm.epp index 13778e11416..d3034347c79 100644 --- a/src/jrd/dpm.epp +++ b/src/jrd/dpm.epp @@ -63,6 +63,7 @@ #include "../jrd/pag_proto.h" #include "../jrd/replication/Publisher.h" #include "../common/StatusArg.h" +#include "../jrd/ini.h" DATABASE DB = FILENAME "ODS.RDB"; @@ -538,7 +539,24 @@ bool DPM_chain( thread_db* tdbb, record_param* org_rpb, record_param* new_rpb) } -void DPM_create_relation( thread_db* tdbb, jrd_rel* relation) +static void update_first_pointer_page(thread_db* tdbb, USHORT rel_id, ULONG page, ULONG root) +{ + // Update the first pointer page transactionally. + AutoCacheRequest request(tdbb, irq_s_first_pp, IRQ_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE tdbb->getTransaction()) + R IN RDB$RELATIONS + WITH R.RDB$RELATION_ID EQ rel_id + { + MODIFY R USING + R.RDB$POINTER_PAGE = page; + R.RDB$ROOT_PAGE = root; + END_MODIFY; + } + END_FOR +} + +void DPM_create_relation(thread_db* tdbb, jrd_rel* relation) { /************************************** * @@ -567,6 +585,13 @@ void DPM_create_relation( thread_db* tdbb, jrd_rel* relation) (*relPages->rel_pages)[0] /*window.win_page*/); DPM_pages(tdbb, relation->rel_id, pag_root, (ULONG) 0, relPages->rel_index_root /*root_window.win_page*/); + + // RDB$PAGE_NUMBER is used only for non system tables + if (relation->rel_id < rel_MAX) + return; + + // Update the first pointer page transactionally. + update_first_pointer_page(tdbb, relation->rel_id, (*relPages->rel_pages)[0], relPages->rel_index_root); } @@ -641,10 +666,21 @@ ULONG DPM_data_pages(thread_db* tdbb, jrd_rel* relation) RelationPages* relPages = relation->getPages(tdbb); ULONG pages = relPages->rel_data_pages; + ULONG step = 1; + if (!pages) { + const size_t ppCount = relPages->rel_pages ? relPages->rel_pages->count() : 0; + const ULONG PAGES_LIMIT = 100; + + if (ppCount > PAGES_LIMIT) + { + step = ppCount / PAGES_LIMIT + 1; + DPM_scan_pages(tdbb, pag_pointer); + } + WIN window(relPages->rel_pg_space_id, -1); - for (ULONG sequence = 0; true; sequence++) + for (ULONG sequence = 0; (step == 1) || (sequence < ppCount); sequence += step) { const pointer_page* ppage = get_pointer_page(tdbb, relation, relPages, &window, sequence, LCK_read); @@ -663,14 +699,16 @@ ULONG DPM_data_pages(thread_db* tdbb, jrd_rel* relation) } if (ppage->ppg_header.pag_flags & ppg_eof) + { + CCH_RELEASE(tdbb, &window); break; + } CCH_RELEASE(tdbb, &window); tdbb->checkCancelState(true); } - CCH_RELEASE(tdbb, &window); relPages->rel_data_pages = pages; } @@ -679,7 +717,7 @@ ULONG DPM_data_pages(thread_db* tdbb, jrd_rel* relation) " returned pages: %" ULONGFORMAT"\n", pages); #endif - return pages; + return pages * step; } @@ -816,7 +854,7 @@ void DPM_delete( thread_db* tdbb, record_param* rpb, ULONG prior_page) DECOMPOSE(sequence, dbb->dbb_dp_per_pp, pp_sequence, slot); RelationPages* relPages = NULL; - WIN pwindow(DB_PAGE_SPACE, -1); + WIN pwindow(DB_PAGE_SPACE, -1); // Will be initialized by pagespace of relation leter for (;;) { @@ -1114,6 +1152,7 @@ void DPM_delete_relation_pages(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, relPages->rel_index_root = 0; } + bool DPM_fetch(thread_db* tdbb, record_param* rpb, USHORT lock) { /************************************** @@ -1347,7 +1386,7 @@ SINT64 DPM_gen_id(thread_db* tdbb, SLONG generator, bool initialize, SINT64 val) vcl* vector = dbb->dbb_gen_id_pages; if (!vector || (sequence >= vector->count()) || !((*vector)[sequence])) { - DPM_scan_pages(tdbb); + DPM_scan_pages(tdbb, pag_ids); if (!(vector = dbb->dbb_gen_id_pages) || (sequence >= vector->count()) || !((*vector)[sequence])) { @@ -1991,7 +2030,7 @@ SLONG DPM_prefetch_bitmap(thread_db* tdbb, jrd_rel* relation, PageBitmap* bitmap #endif -void DPM_scan_pages( thread_db* tdbb) +void DPM_scan_pages(thread_db* tdbb, SCHAR pagType /*= 0*/, int relId /*= 0*/, ULONG startSequence /*= 0*/) { /************************************** * @@ -2035,40 +2074,101 @@ void DPM_scan_pages( thread_db* tdbb) CCH_RELEASE(tdbb, &window); - AutoCacheRequest request(tdbb, irq_r_pages, IRQ_REQUESTS); + if (!relPages->rel_index_root) + { + // Try to guess IRT number for RDB$PAGES, it should be next page after first PP + window.win_page = (*vector)[0] + 1; + + index_root_page* root = (index_root_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_undefined); + + if (root->irt_header.pag_type == pag_root && root->irt_relation == 0) + relPages->rel_index_root = window.win_page.getPageNum(); - FOR(REQUEST_HANDLE request) X IN RDB$PAGES + CCH_RELEASE(tdbb, &window); + } + + if (pagType == 0 && relId == 0 || !relPages->rel_index_root) { - relation = MET_relation(tdbb, X.RDB$RELATION_ID); - relPages = relation->getBasePages(); - sequence = X.RDB$PAGE_SEQUENCE; - MemoryPool* pool = dbb->dbb_permanent; - switch (X.RDB$PAGE_TYPE) + AutoCacheRequest request(tdbb, irq_r_pages, IRQ_REQUESTS); + + FOR(REQUEST_HANDLE request) X IN RDB$PAGES { - case pag_root: - relPages->rel_index_root = X.RDB$PAGE_NUMBER; - continue; + relation = MET_relation(tdbb, X.RDB$RELATION_ID); + relPages = relation->getBasePages(); + sequence = X.RDB$PAGE_SEQUENCE; + MemoryPool* pool = dbb->dbb_permanent; + switch (X.RDB$PAGE_TYPE) + { + case pag_root: + relPages->rel_index_root = X.RDB$PAGE_NUMBER; + continue; - case pag_pointer: - address = &relPages->rel_pages; - pool = relation->rel_pool; - break; + case pag_pointer: + address = &relPages->rel_pages; + pool = relation->rel_pool; + break; - case pag_transactions: - address = &dbb->dbb_t_pages; - break; + case pag_transactions: + address = &dbb->dbb_t_pages; + break; - case pag_ids: - address = &dbb->dbb_gen_id_pages; - break; + case pag_ids: + address = &dbb->dbb_gen_id_pages; + break; - default: - CORRUPT(257); // msg 257 bad record in RDB$PAGES + default: + CORRUPT(257); // msg 257 bad record in RDB$PAGES + } + vector = *address = vcl::newVector(*pool, *address, sequence + 1); + (*vector)[sequence] = X.RDB$PAGE_NUMBER; } - vector = *address = vcl::newVector(*pool, *address, sequence + 1); - (*vector)[sequence] = X.RDB$PAGE_NUMBER; + END_FOR + } + else + { + AutoCacheRequest request(tdbb, irq_r_pages2, IRQ_REQUESTS); + + FOR(REQUEST_HANDLE request) X IN RDB$PAGES + WITH X.RDB$RELATION_ID = relId + AND X.RDB$PAGE_TYPE = pagType + AND X.RDB$PAGE_SEQUENCE >= startSequence + { + relation = MET_relation(tdbb, X.RDB$RELATION_ID); + relPages = relation->getBasePages(); + sequence = X.RDB$PAGE_SEQUENCE; + switch (X.RDB$PAGE_TYPE) + { + case pag_root: + relPages->rel_index_root = X.RDB$PAGE_NUMBER; + continue; + + case pag_pointer: + address = &relPages->rel_pages; + break; + + case pag_transactions: + address = &dbb->dbb_t_pages; + break; + + case pag_ids: + address = &dbb->dbb_gen_id_pages; + break; + + default: + CORRUPT(257); // msg 257 bad record in RDB$PAGES + } + + if ((sequence == startSequence) && (vector = *address)) + { + fb_assert(vector->count() > sequence); + fb_assert((*vector)[sequence] == X.RDB$PAGE_NUMBER); + } + + vector = *address = vcl::newVector(*dbb->dbb_permanent, *address, sequence + 1); + (*vector)[sequence] = X.RDB$PAGE_NUMBER; + } + END_FOR } - END_FOR } @@ -3196,6 +3296,25 @@ static bool get_header(WIN* window, USHORT line, record_param* rpb) } +static bool restore_pages(thread_db* tdbb, USHORT rel_id) +{ + Attachment* attachment = tdbb->getAttachment(); + + AutoRequest request; + + bool found = false; + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE tdbb->getTransaction()) + X IN RDB$RELATIONS WITH X.RDB$RELATION_ID EQ rel_id + { + DPM_pages(tdbb, rel_id, pag_pointer, 0, X.RDB$POINTER_PAGE); + DPM_pages(tdbb, rel_id, pag_root, 0, X.RDB$ROOT_PAGE); + found = true; + } + END_FOR + return found; +} + + static pointer_page* get_pointer_page(thread_db* tdbb, jrd_rel* relation, RelationPages* relPages, WIN* window, ULONG sequence, USHORT lock) @@ -3215,15 +3334,35 @@ static pointer_page* get_pointer_page(thread_db* tdbb, **************************************/ SET_TDBB(tdbb); + if (!relation) + return NULL; + vcl* vector = relPages->rel_pages; + bool restored = false; if (!vector || sequence >= vector->count()) { for (;;) { - DPM_scan_pages(tdbb); - // If the relation is gone, then we can't do anything anymore. - if (!relation || !(vector = relPages->rel_pages)) - return NULL; + DPM_scan_pages(tdbb, pag_pointer, relation->rel_id); + vector = relPages->rel_pages; + + // If there is no relation in RDB$PAGES we try to restore it from RDB$RELATIONS + // After moving relation and deleting its pages maybe other DFWs + // I rely it may not cause cleaning vector of pages. We hold locks. But I leave this comment + // describing a potential situation. + if (!vector || vector->count() == 0) + { + if (restored || (relPages->rel_instance_id != 0) || (relation->rel_id < rel_MAX)) + return NULL; + + if (restore_pages(tdbb, relation->rel_id)) + { + restored = true; + continue; + } + else + return NULL; + } if (sequence < vector->count()) break; // we are in business again @@ -3787,3 +3926,277 @@ static void store_big_record(thread_db* tdbb, else CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); } + +typedef Firebird::GenericMap > > PagesMap; + +void DPM_move_data_pages(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, RelationPages* newRelationPages) +{ + /************************************** + * + * D P M _ m o v e _ d a t a _ p a g e s + * + ************************************** + * + * Functional description + * Copy data and blob pages from the oldRelation pages to the newRelationPages + * The main steps are: + * - allocate necessary number of pointer pages by extents. + * - allocate the rest of pointer pages by pages. + * - walking through PPs allocate DPs by pages or extents. + * - fix every PP by correcting DP numbers and ppg_next pointer and build a map + * - walking through the map and copy every DP to the new one by fixing + * b_page and f_page numbers. + * We expect that DPM_scan_pages was called. + * In the end of work replace records in RDB$PAGES. + * + **************************************/ + SET_TDBB(tdbb); + Database* dbb = tdbb->getDatabase(); + Attachment* attachment = tdbb->getAttachment(); + + RelationPages* oldRelationPages = relation->getPages(tdbb); + + WIN newWindow(newRelationPages->rel_pg_space_id, -1); + WIN oldWindow(oldRelationPages->rel_pg_space_id, -1); + WIN dpWindow(newRelationPages->rel_pg_space_id, -1); + + PagesMap pagesMap; + + const ULONG ppCount = oldRelationPages->rel_pages->count(); + newRelationPages->rel_pages = vcl::newVector(*relation->rel_pool, newRelationPages->rel_pages, ppCount); + + ULONG sequence = 0; + // Allocate PPs by extents + if (ppCount > PAGES_IN_EXTENT) + { + for (; sequence < ppCount - PAGES_IN_EXTENT; sequence += PAGES_IN_EXTENT) + { + PAG_allocate_pages(tdbb, &newWindow, PAGES_IN_EXTENT, true); + const ULONG firstPage = newWindow.win_page.getPageNum(); + CCH_RELEASE(tdbb, &newWindow); + for (int i = 0; i < PAGES_IN_EXTENT; i++) + (*newRelationPages->rel_pages)[sequence + i] = firstPage + i; + } + } + // Allocate the rest of PPs by pages + for (; sequence < ppCount; sequence++) + { + PAG_allocate_pages(tdbb, &newWindow, 1, false); + const ULONG page = newWindow.win_page.getPageNum(); + CCH_RELEASE(tdbb, &newWindow); + (*newRelationPages->rel_pages)[sequence] = page; + } + + // Copy and fix every pointer page and allocate and map its datapages + for (sequence = 0; sequence < ppCount; sequence++) + { + ULONG oldPage = oldWindow.win_page = (*oldRelationPages->rel_pages)[sequence]; + const pointer_page* oldPP = (pointer_page*) CCH_FETCH(tdbb, &oldWindow, LCK_read, pag_pointer); + + ULONG newPage = newWindow.win_page = (*newRelationPages->rel_pages)[sequence]; + pointer_page* newPP = (pointer_page*) CCH_FETCH(tdbb, &newWindow, LCK_write, pag_undefined); + + // Copy and relpace useful markers from oldRelationPages + if (oldRelationPages->rel_slot_space == oldPage) + newRelationPages->rel_slot_space == newPage; + + if (oldRelationPages->rel_pri_data_space == oldPage) + newRelationPages->rel_pri_data_space == newPage; + + if (oldRelationPages->rel_sec_data_space == oldPage) + newRelationPages->rel_sec_data_space == newPage; + + // Now copy the page data + CCH_MARK(tdbb, &newWindow); + memcpy(newPP, oldPP, dbb->dbb_page_size); + + if (sequence < (ppCount - 1)) + { + // Fix the pointer to the next PP + newPP->ppg_next = (*newRelationPages->rel_pages)[sequence + 1]; + } + else + { + // We rely that rel_pages vector is correct and nobody extend relation when we copy its data!!! + fb_assert(oldPP->ppg_header.pag_flags & ppg_eof); + } + + CCH_RELEASE(tdbb, &oldWindow); + + // Allocate DPs + if (!sequence && newPP->ppg_count < PAGES_IN_EXTENT) + { + // Allocate by pages + for (USHORT slot = 0; slot < newPP->ppg_count; slot++) + { + if (newPP->ppg_page[slot]) + { + PAG_allocate(tdbb, &dpWindow); + // Replace slots by the new data page numbers + const ULONG newPageNumber = dpWindow.win_page.getPageNum(); + CCH_RELEASE(tdbb, &dpWindow); + pagesMap.put(newPP->ppg_page[slot], newPageNumber); + newPP->ppg_page[slot] = newPageNumber; + } + } + } + else + { + // Allocated by extents + UCHAR* bits = (UCHAR*) (newPP->ppg_page + dbb->dbb_dp_per_pp); + for (USHORT slot = 0; slot < newPP->ppg_count; slot += PAGES_IN_EXTENT) + { + // We are on the new extent. Check it for empty. + int count = 0; + for (int i = 0; i < PAGES_IN_EXTENT; i++) + { + fb_assert(slot + i < newPP->ppg_count); + + if (newPP->ppg_page[slot + i]) + count++; + else + newPP->ppg_min_space = MIN(newPP->ppg_min_space, slot + i); + } + // If new extent is empty go to the next + if (!count) + continue; + + PAG_allocate_pages(tdbb, &dpWindow, PAGES_IN_EXTENT, true); + // Replace slots by the new data page numbers + const ULONG newPageNumber = dpWindow.win_page.getPageNum(); + CCH_RELEASE(tdbb, &dpWindow); + + // All non empty slots we replace by new data page numbers in the allocated extent. + // Check if there are empty slots. In general case all slots in extent must be used. + // If such slot is we remove it and replace by empty data page. + for (int i = 0; i < PAGES_IN_EXTENT; i++) + { + if (!newPP->ppg_page[slot + i]) + { + // Original PP has empty slot here. We replace it by empty data page + PPG_DP_BIT_SET(bits, slot + i, ppg_dp_empty); + dpWindow.win_page = newPageNumber + i; + data_page* dpage = (data_page*) CCH_fake(tdbb, &dpWindow, 1); + dpage->dpg_sequence = sequence * dbb->dbb_dp_per_pp + slot + i; + dpage->dpg_relation = relation->rel_id; + dpage->dpg_header.pag_type = pag_data; + CCH_RELEASE(tdbb, &dpWindow); + newPP->ppg_count = MAX(newPP->ppg_count, slot + i); + } + else + pagesMap.put(newPP->ppg_page[slot + i], newPageNumber + i); + + newPP->ppg_page[slot + i] = newPageNumber + i; + } + } + } + + CCH_RELEASE(tdbb, &newWindow); + } + + // Now we have copied all PPs, allocated all DPs and got an allocation map + // We can copy and fix every DP. We will use sorted order in the map to optimize reads. + PagesMap::Accessor dPage(&pagesMap); + + for (bool found = dPage.getFirst(); found; found = dPage.getNext()) + { + const ULONG oldPage = dPage.current()->first; + const ULONG newPage = dPage.current()->second; + + if (oldRelationPages->rel_last_free_pri_dp == oldPage) + newRelationPages->rel_last_free_pri_dp == newPage; + + // Copy data page + oldWindow.win_page = oldPage; + Ods::data_page* oldDP = (Ods::data_page*) CCH_FETCH(tdbb, &oldWindow, LCK_read, pag_data); + + newWindow.win_page = newPage; + Ods::data_page* newDP = (Ods::data_page*) CCH_FETCH(tdbb, &newWindow, LCK_write, pag_undefined); + + CCH_MARK(tdbb, &newWindow); + memcpy(newDP, oldDP, dbb->dbb_page_size); + + CCH_RELEASE(tdbb, &oldWindow); // We don't need old datapage anymore + + // Now we need to fix every b_page and f_page pointers in record versions + const Ods::data_page::dpg_repeat* index = newDP->dpg_rpt; + const Ods::data_page::dpg_repeat* const end = index + newDP->dpg_count; + for (; index < end; index++) + { + if (index->dpg_offset) + { + Ods::rhd* header = (rhd*) ((SCHAR*) newDP + index->dpg_offset); + // If the record is blob we need to copy all its pages + if (header->rhd_flags & rhd_blob) + { + blh* blob = (blh*) header; + if (blob->blh_level == 0) + continue; + + ULONG* page1 = blob->blh_page; + const ULONG* const end1 = page1 + (index->dpg_length - BLH_SIZE) / sizeof(ULONG); + + for (; page1 < end1; page1++) + { + // Copy blob page with blob page numbers + WIN oldWindow1(oldRelationPages->rel_pg_space_id, *page1); + WIN newWindow1(newRelationPages->rel_pg_space_id, -1); + blob_page* oldBlobPage1 = (blob_page*) CCH_FETCH(tdbb, &oldWindow1, LCK_read, pag_blob); + blob_page* newBlobPage1 = (blob_page*) PAG_allocate(tdbb, &newWindow1); + memcpy(newBlobPage1, oldBlobPage1, dbb->dbb_page_size); + *page1 = newWindow1.win_page.getPageNum(); + CCH_RELEASE_TAIL(tdbb, &oldWindow1); + + if (blob->blh_level == 2) + { + // Fix blob page numbers and copy other pages + ULONG* page2 = newBlobPage1->blp_page; + const ULONG* const end2 = page2 + ((newBlobPage1->blp_length) / sizeof(ULONG)); + + for (; page2 < end2; page2++) + { + WIN oldWindow2(oldRelationPages->rel_pg_space_id, *page2); + WIN newWindow2(newRelationPages->rel_pg_space_id, -1); + blob_page* oldBlobPage2 = (blob_page*) CCH_FETCH(tdbb, &oldWindow2, LCK_read, pag_blob); + blob_page* newBlobPage2 = (blob_page*) PAG_allocate(tdbb, &newWindow2); + memcpy(newBlobPage2, oldBlobPage2, dbb->dbb_page_size); + *page2 = newWindow2.win_page.getPageNum(); + CCH_RELEASE_TAIL(tdbb, &oldWindow2); + CCH_RELEASE_TAIL(tdbb, &newWindow2); + } + } + + CCH_RELEASE_TAIL(tdbb, &newWindow1); + } + } + else + { + if (header->rhd_b_page) + { + // If backversion page number is the same as primary we don't need mapping + if (header->rhd_b_page == oldPage) + header->rhd_b_page = newPage; + else + { + const bool r = pagesMap.get(header->rhd_b_page, header->rhd_b_page); + fb_assert(r); // Maybe to drop bugcheck? + } + } + if (header->rhd_flags & rhd_incomplete) + { + Ods::rhdf* fheader = (rhdf*) header; + if (fheader->rhdf_f_page) + { + const bool r = pagesMap.get(fheader->rhdf_f_page, header->rhd_b_page); + fb_assert(r); // Maybe to drop bugcheck? + } + } + } + } + } + + CCH_RELEASE(tdbb, &newWindow); + } + + update_first_pointer_page(tdbb, relation->rel_id, (*newRelationPages->rel_pages)[0], newRelationPages->rel_index_root); +} diff --git a/src/jrd/dpm_proto.h b/src/jrd/dpm_proto.h index 327f4bfcaea..2094c8d3e0e 100644 --- a/src/jrd/dpm_proto.h +++ b/src/jrd/dpm_proto.h @@ -73,7 +73,7 @@ void DPM_pages(Jrd::thread_db*, SSHORT, int, ULONG, ULONG); #ifdef SUPERSERVER_V2 SLONG DPM_prefetch_bitmap(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::PageBitmap*, SLONG); #endif -void DPM_scan_pages(Jrd::thread_db*); +void DPM_scan_pages(Jrd::thread_db*, SCHAR pagType = 0, int relId = 0, ULONG startSequence = 0); void DPM_store(Jrd::thread_db*, Jrd::record_param*, Jrd::PageStack&, const Jrd::RecordStorageType type); RecordNumber DPM_store_blob(Jrd::thread_db*, Jrd::blb*, Jrd::Record*); void DPM_rewrite_header(Jrd::thread_db*, Jrd::record_param*); @@ -82,4 +82,6 @@ void DPM_update(Jrd::thread_db*, Jrd::record_param*, Jrd::PageStack*, const Jrd: void DPM_create_relation_pages(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::RelationPages*); void DPM_delete_relation_pages(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::RelationPages*); +void DPM_move_data_pages(Jrd::thread_db* tdbb, Jrd::jrd_rel *relation, Jrd::RelationPages *newRelationPages); + #endif // JRD_DPM_PROTO_H diff --git a/src/jrd/drq.h b/src/jrd/drq.h index 929c3945abb..555d418773e 100644 --- a/src/jrd/drq.h +++ b/src/jrd/drq.h @@ -243,6 +243,11 @@ enum drq_type_t drq_exception_exist, // check if exception exists drq_generator_exist, // check if generator exists drq_rel_field_exist, // check if a field of relation or view exists + drq_s_tablespace, // store tablespace + drq_m_tablespace, // modify tablespace + drq_e_tablespace, // erase tablespace + drq_g_nxt_ts_id, // generate next tablespace id + drq_tablespace_exist, // check if tablespace exists drq_m_coll_attrs, // modify collation attributes drq_MAX diff --git a/src/jrd/fields.h b/src/jrd/fields.h index ebba07eb967..9318d4122be 100644 --- a/src/jrd/fields.h +++ b/src/jrd/fields.h @@ -210,3 +210,9 @@ 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_ts_id , nam_ts_id , dtype_short , sizeof(SSHORT) , 0 , NULL , false) + FIELD(fld_ts_name , nam_ts_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) + + FIELD(fld_pp_number , nam_pp_number , dtype_long , sizeof(SLONG) , 0 , NULL , true) + FIELD(fld_idx_number , nam_idx_number , dtype_long , sizeof(SLONG) , 0 , NULL , true) diff --git a/src/jrd/idx.cpp b/src/jrd/idx.cpp index b0698c9a2c2..2d0516df99b 100644 --- a/src/jrd/idx.cpp +++ b/src/jrd/idx.cpp @@ -64,6 +64,7 @@ #include "../jrd/vio_proto.h" #include "../jrd/tra_proto.h" #include "../jrd/Collation.h" +#include "../jrd/pag_proto.h" using namespace Jrd; using namespace Ods; @@ -611,7 +612,7 @@ void IDX_delete_index(thread_db* tdbb, jrd_rel* relation, USHORT id) WIN window(get_root_page(tdbb, relation)); CCH_FETCH(tdbb, &window, LCK_write, pag_root); - const bool tree_exists = BTR_delete_index(tdbb, &window, id); + const bool tree_exists = BTR_delete_index(tdbb, relation, &window, id); if ((relation->rel_flags & REL_temp_conn) && (relation->getPages(tdbb)->rel_instance_id != 0) && tree_exists) @@ -651,7 +652,7 @@ void IDX_delete_indices(thread_db* tdbb, jrd_rel* relation, RelationPages* relPa for (USHORT i = 0; i < root->irt_count; i++) { - const bool tree_exists = BTR_delete_index(tdbb, &window, i); + const bool tree_exists = BTR_delete_index(tdbb, relation, &window, i); root = (index_root_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_root); if (is_temp && tree_exists) @@ -1533,7 +1534,7 @@ static PageNumber get_root_page(thread_db* tdbb, jrd_rel* relation) SLONG page = relPages->rel_index_root; if (!page) { - DPM_scan_pages(tdbb); + DPM_scan_pages(tdbb, pag_root, relation->rel_id); page = relPages->rel_index_root; } diff --git a/src/jrd/idx.h b/src/jrd/idx.h index 25987e5afa9..4eeee897f4c 100644 --- a/src/jrd/idx.h +++ b/src/jrd/idx.h @@ -295,6 +295,16 @@ static const struct ini_idx_t indices[] = INDEX(54, rel_backup_history, idx_unique, 1) SEGMENT(f_backup_guid, idx_string) // backup guid }}, + // define index RDB$INDEX_55 for RDB$TABLESPACES unique RDB$TABALESPACE_NAME; + INDEX(55, rel_tablespaces, idx_unique, 1) + SEGMENT(f_ts_name, idx_metadata) // tablespace name + }}, + // define index RDB$INDEX_52 for RDB$PAGES RDB$PAGE_TYPE, RDB$RELATION_ID, RDB$PAGE_SEQUENCE; + INDEX(56, rel_pages, 0, 3) + SEGMENT(f_pag_type, idx_numeric), // page type + SEGMENT(f_pag_id, idx_numeric), // relation id + SEGMENT(f_pag_seq, idx_numeric) // page sequence + }} }; #define SYSTEM_INDEX_COUNT FB_NELEM(indices) diff --git a/src/jrd/ini.epp b/src/jrd/ini.epp index fb8cf5b87c4..54052e3ac90 100644 --- a/src/jrd/ini.epp +++ b/src/jrd/ini.epp @@ -979,6 +979,7 @@ static void add_index_set(thread_db* tdbb) idx.idx_count = index->ini_idx_segment_count; idx.idx_flags = index->ini_idx_flags; + idx.idx_pg_space_id = DB_PAGE_SPACE; SelectivityList selectivity(*tdbb->getDefaultPool()); IDX_create_index(tdbb, relation, &idx, indexName.c_str(), NULL, diff --git a/src/jrd/irq.h b/src/jrd/irq.h index 1cb2ecd94b3..c8eb16605d6 100644 --- a/src/jrd/irq.h +++ b/src/jrd/irq.h @@ -178,7 +178,21 @@ enum irq_type_t irq_c_relation3, // lookup relation in phase 0 to cleanup irq_linger, // get database linger value irq_dbb_ss_definer, // get database sql security value + irq_find_rel_ts, // find tablespace options for relation + irq_find_idx_ts, // find tablespace options for index + irq_find_ts, // find tablespace options by name irq_out_proc_param_dep, // check output procedure parameter dependency + irq_list_ts_files, // list tablespace files + irq_find_ts_dfw, // find tablespace options by name in dfw + irq_find_ts_dfw0, // find tablespace options by name in dfw for cleanup + irq_ts_find_rel_dfw, // find relation of tablespace in dfw for check + irq_ts_drop_rel_dfw, // find relation of tablespace in dfw for drop + irq_ts_find_idx_dfw, // find index of tablespace in dfw for check + irq_ts_drop_idx_dfw, // find index of tablespace in dfw for drop + irq_scan_ts, // scn tablespaces + irq_ts_security, // verify security for tablespace + irq_r_pages2, + irq_s_first_pp, irq_MAX }; diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 5ad0f45d906..3ade44b1345 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -1277,6 +1277,7 @@ class TraceFailedConnection : static void check_database(thread_db* tdbb, bool async = false); static void commit(thread_db*, jrd_tra*, const bool); static bool drop_files(const jrd_file*); +static bool drop_files(ObjectsArray &tsFiles); static void find_intl_charset(thread_db*, Jrd::Attachment*, const DatabaseOptions*); static jrd_tra* find_transaction(thread_db*); static void init_database_lock(thread_db*); @@ -3315,6 +3316,7 @@ void JAttachment::dropDatabase(CheckStatusWrapper* user_status) // Prepare to set ODS to 0 WIN window(HEADER_PAGE_NUMBER); Ods::header_page* header = NULL; + ObjectsArray tsFiles; try { @@ -3359,6 +3361,9 @@ void JAttachment::dropDatabase(CheckStatusWrapper* user_status) // dbb->dbb_extManager.closeAttachment(tdbb, attachment); // To be reviewed by Adriano - it will be anyway called in release_attachment + // Now under exclusive lock we can get a list of tablespace files to delete them later + MET_ts_files(tdbb, tsFiles); + // Forced release of all transactions purge_transactions(tdbb, attachment, true); @@ -3410,6 +3415,7 @@ void JAttachment::dropDatabase(CheckStatusWrapper* user_status) { err = drop_files(shadow->sdw_file) || err; } + err = drop_files(tsFiles) || err; tdbb->setDatabase(NULL); Database::destroy(dbb); @@ -6598,6 +6604,36 @@ static bool drop_files(const jrd_file* file) return status->getState() & IStatus::STATE_ERRORS ? true : false; } +static bool drop_files(ObjectsArray& tsFiles) +{ +/************************************** + * + * d r o p _ f i l e s + * + ************************************** + * + * Functional description + * drop files in list + * + **************************************/ + FbLocalStatus status; + + while (tsFiles.getCount()) + { + const PathName file(tsFiles.pop()); + if (unlink(file.c_str())) + { + ERR_build_status(&status, Arg::Gds(isc_io_error) << Arg::Str("unlink") << + Arg::Str(file) << + Arg::Gds(isc_io_delete_err) << SYS_ERR(errno)); + Database* dbb = GET_DBB(); + PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); + iscDbLogStatus(pageSpace->file->fil_string, &status); + } + } + + return status->getState() & IStatus::STATE_ERRORS ? true : false; +} static jrd_tra* find_transaction(thread_db* tdbb) { diff --git a/src/jrd/lck.cpp b/src/jrd/lck.cpp index 66e510abe84..033a81f2678 100644 --- a/src/jrd/lck.cpp +++ b/src/jrd/lck.cpp @@ -580,6 +580,7 @@ static lck_owner_t get_owner_type(enum lck_t lock_type) case LCK_rel_gc: case LCK_record_gc: case LCK_alter_database: + case LCK_tablespace_exist: owner_type = LCK_OWNER_attachment; break; diff --git a/src/jrd/lck.h b/src/jrd/lck.h index 7d75974de1a..e5eaaed0a41 100644 --- a/src/jrd/lck.h +++ b/src/jrd/lck.h @@ -73,7 +73,8 @@ enum lck_t { LCK_crypt, // Crypt lock for single crypt thread LCK_crypt_status, // Notifies about changed database encryption status LCK_record_gc, // Record-level GC lock - LCK_alter_database // ALTER DATABASE lock + LCK_alter_database, // ALTER DATABASE lock + LCK_tablespace_exist // Tablespace existance lock }; // Lock owner types diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 8d3fbe8dad7..662bce1897d 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -93,6 +93,7 @@ #include "../common/classes/Hash.h" #include "../common/classes/MsgPrint.h" #include "../jrd/Function.h" +#include "../jrd/Tablespace.h" #ifdef HAVE_CTYPE_H @@ -3656,6 +3657,10 @@ jrd_rel* MET_relation(thread_db* tdbb, USHORT id) } relation->rel_flags |= (REL_check_existence | REL_check_partners); + + const USHORT pageSpaceId = MET_rel_pagespace(tdbb, id); + relation->setPageSpace(pageSpaceId); + return relation; } @@ -5449,9 +5454,9 @@ Nullable MET_get_ss_definer(Jrd::thread_db* tdbb) * **************************************/ SET_TDBB(tdbb); - Attachment* attachment = tdbb->getAttachment(); - Nullable r; + Nullable r; + Attachment* attachment = tdbb->getAttachment(); AutoCacheRequest request(tdbb, irq_dbb_ss_definer, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) @@ -5464,3 +5469,210 @@ Nullable MET_get_ss_definer(Jrd::thread_db* tdbb) return r; } + +USHORT MET_rel_pagespace(Jrd::thread_db* tdbb, USHORT rel_id) +{ +/************************************** + * + * M E T _ r e l _ p a g e s p a c e + * + ************************************** + * + * Functional description + * Find id and filename of tablespace by ID of relation and allocate page space + * Returns page space id for relation of default DB_PAGE_SPACE if table space + * for relation is not specified + * RS: Probably later it would be useful to implement cache of tablespaces + * + **************************************/ + SET_TDBB(tdbb); + Database* dbb = tdbb->getDatabase(); + CHECK_DBB(dbb); + + USHORT pageSpaceId = DB_PAGE_SPACE; + Attachment* attachment = tdbb->getAttachment(); + AutoCacheRequest request(tdbb, irq_find_rel_ts, IRQ_REQUESTS); + + FOR(REQUEST_HANDLE request) + REL IN RDB$RELATIONS + WITH REL.RDB$RELATION_ID EQ rel_id AND + REL.RDB$TABLESPACE_NAME NOT MISSING + { + pageSpaceId = MET_tablespace(tdbb, REL.RDB$TABLESPACE_NAME)->id; + } + END_FOR + + return pageSpaceId; +} + +USHORT MET_index_pagespace(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, USHORT idx_id) +{ +/************************************** + * + * M E T _ i n d e x _ t a b l e s p a c e + * + ************************************** + * + * Functional description + * Find tablespace name for index and lookup page space for it. + * If there is no tablespace for the index or relation is system + * returns relation pagespace. + * + **************************************/ + SET_TDBB(tdbb); + Database* dbb = tdbb->getDatabase(); + CHECK_DBB(dbb); + + RelationPages* const relPages = relation->getPages(tdbb); + if (relation->isSystem()) + return relPages->rel_pg_space_id; + + // Relation tablespace name must be in system table after index creation + // If it's not so we shoud use the main DB page space. + USHORT pageSpaceId = DB_PAGE_SPACE; + Attachment* attachment = tdbb->getAttachment(); + AutoCacheRequest request(tdbb, irq_find_idx_ts, IRQ_REQUESTS); + + FOR(REQUEST_HANDLE request) + IDX IN RDB$INDICES + WITH IDX.RDB$RELATION_NAME EQ relation->rel_name.c_str() AND + IDX.RDB$INDEX_ID EQ idx_id + 1 AND + IDX.RDB$TABLESPACE_NAME NOT MISSING + { + pageSpaceId = MET_tablespace(tdbb, IDX.RDB$TABLESPACE_NAME)->id; + } + END_FOR + + return pageSpaceId; +} + +Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const MetaName& tableSpaceName) +{ +/************************************** + * + * M E T _ t a b l e s p a c e + * + ************************************** + * + * Functional description + * Find tablespace by its name in attach cache first of all. + * If not found alloc pagespace, get exist tablespace lock and + * add it in attachment cache. + * + * Return a pointer to the tablespace. + * + **************************************/ + SET_TDBB(tdbb); + Database* dbb = tdbb->getDatabase(); + CHECK_DBB(dbb); + + Attachment* attachment = tdbb->getAttachment(); + if (tableSpaceName.isEmpty()) + return attachment->getTablespace(DB_PAGE_SPACE); + + const USHORT tsCount = attachment->getTablespaceCount(); + + for (USHORT i = 2; i <= tsCount; i++) + { + Tablespace* ts = attachment->getTablespace(i); + if (ts && (ts->name == tableSpaceName) ) + return ts; + } + + // Now we need to find tablespace in system table + AutoCacheRequest request(tdbb, irq_find_ts, IRQ_REQUESTS); + + USHORT pageSpaceId; + PathName file; + bool found = false; + + FOR(REQUEST_HANDLE request) + TS IN RDB$TABLESPACES + WITH TS.RDB$TABLESPACE_NAME EQ tableSpaceName.c_str() + { + found = true; + pageSpaceId = TS.RDB$TABLESPACE_ID; + file = TS.RDB$FILE_NAME; + } + END_FOR + + if (!found) + status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(tableSpaceName)); + + // Check that pageSpaceId has reasonable value + fb_assert( (pageSpaceId > DB_PAGE_SPACE) && (pageSpaceId < TRANS_PAGE_SPACE) ); + + // Check that pageSpaceId is either new or is not set (else it should be found in att_tablespaces above) + fb_assert( (pageSpaceId >= tsCount + 1) || !attachment->getTablespace(pageSpaceId)); + + dbb->dbb_page_manager.allocTableSpace(tdbb, pageSpaceId, false, file); + + Tablespace* tableSpace = FB_NEW_POOL(*attachment->att_pool) Tablespace(*attachment->att_pool); + tableSpace->id = pageSpaceId; + tableSpace->name = tableSpaceName; + + Lock* lock = FB_NEW_RPT(*attachment->att_pool, 0) + Lock(tdbb, sizeof(SLONG), LCK_tablespace_exist, tableSpace); + tableSpace->existenceLock = lock; + lock->setKey(tableSpace->id); + attachment->setTablespace(pageSpaceId, tableSpace); + + return tableSpace; +} + +void MET_ts_files(Jrd::thread_db* tdbb, ObjectsArray& files) +{ +/************************************** + * + * M E T _ t s _ f i l e s + * + ************************************** + * + * Functional description + * List all tablespace file names + * + **************************************/ + SET_TDBB(tdbb); + + Attachment* attachment = tdbb->getAttachment(); + AutoCacheRequest request(tdbb, irq_list_ts_files, IRQ_REQUESTS); + + FOR(REQUEST_HANDLE request) + TS IN RDB$TABLESPACES + { + files.push(TS.RDB$FILE_NAME); + } + END_FOR +} + +void MET_scan_tablespaces(Jrd::thread_db* tdbb) +{ +/************************************** + * + * M E T _ s c a n _ t a b l e s p a c e s + * + ************************************** + * + * Functional description + * Scan every tablespace to cache it. + * The main usage is to scan every tablespace PIP + * in walk_pip + * + **************************************/ + SET_TDBB(tdbb); + Database* dbb = tdbb->getDatabase(); + CHECK_DBB(dbb); + + Attachment* attachment = tdbb->getAttachment(); + + // Now we need to find tablespace in system table + AutoCacheRequest request(tdbb, irq_scan_ts, IRQ_REQUESTS); + + FOR(REQUEST_HANDLE request) + TS IN RDB$TABLESPACES + { + const Tablespace* ts = MET_tablespace(tdbb, TS.RDB$TABLESPACE_NAME); + fb_assert(ts); + } + END_FOR +} diff --git a/src/jrd/met_proto.h b/src/jrd/met_proto.h index 38716837c37..d89d3412965 100644 --- a/src/jrd/met_proto.h +++ b/src/jrd/met_proto.h @@ -143,4 +143,10 @@ void MET_update_partners(Jrd::thread_db*); int MET_get_linger(Jrd::thread_db*); Nullable MET_get_ss_definer(Jrd::thread_db*); +USHORT MET_rel_pagespace(Jrd::thread_db* tdbb, USHORT rel_id); +USHORT MET_index_pagespace(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, USHORT idx_id); +Jrd::Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const Firebird::MetaName& tableSpaceName); +void MET_ts_files(Jrd::thread_db* tdbb, Firebird::ObjectsArray &files); +void MET_scan_tablespaces(Jrd::thread_db*); + #endif // JRD_MET_PROTO_H diff --git a/src/jrd/names.h b/src/jrd/names.h index 6ebe4528c04..65d972c6ae7 100644 --- a/src/jrd/names.h +++ b/src/jrd/names.h @@ -269,6 +269,9 @@ NAME("RDB$ARGUMENT_NAME", nam_arg_name) NAME("RDB$IDENTITY_TYPE", nam_identity_type) NAME("RDB$AUTH_METHOD", nam_auth_method) +NAME("RDB$POINTER_PAGE", nam_pp_number) +NAME("RDB$ROOT_PAGE", nam_idx_number) + NAME("SEC$USER_NAME", nam_user_name) NAME("SEC$FIRST_NAME", nam_first_name) NAME("SEC$MIDDLE_NAME", nam_middle_name) @@ -428,3 +431,9 @@ NAME("RDB$TIME_ZONE_NAME", nam_tz_name) NAME("RDB$TIME_ZONE_OFFSET", nam_tz_offset) NAME("RDB$TIMESTAMP_TZ", nam_timestamp_tz) NAME("RDB$DBTZ_VERSION", nam_tz_db_version) + +NAME("RDB$TABLESPACES", nam_tablespaces) +NAME("RDB$TABLESPACE_ID", nam_ts_id) +NAME("RDB$TABLESPACE_NAME", nam_ts_name) +NAME("RDB$OFFLINE", nam_ts_offline) +NAME("RDB$READ_ONLY", nam_ts_readonly) diff --git a/src/jrd/obj.h b/src/jrd/obj.h index 1bb0bf9b7e3..77c0a129a13 100644 --- a/src/jrd/obj.h +++ b/src/jrd/obj.h @@ -48,8 +48,9 @@ const int obj_collation = 17; const int obj_package_header = 18; const int obj_package_body = 19; const int obj_privilege = 20; +const int obj_tablespace = 21; -const int obj_last_non_ddl = 20; // keep in sync!!! +const int obj_last_non_ddl = 21; // keep in sync!!! // objects types for ddl operations const int obj_database = obj_last_non_ddl + 1; @@ -65,8 +66,9 @@ const int obj_roles = obj_last_non_ddl + 10; const int obj_charsets = obj_last_non_ddl + 11; const int obj_collations = obj_last_non_ddl + 12; const int obj_filters = obj_last_non_ddl + 13; +const int obj_tablespaces = obj_last_non_ddl + 14; -const int obj_type_MAX = obj_last_non_ddl + 14; // keep this last! +const int obj_type_MAX = obj_last_non_ddl + 15; // keep this last! // used in the parser only / no relation with obj_type_MAX (should be greater) const int obj_user_or_role = 100; @@ -103,6 +105,8 @@ inline const char* get_object_name(int object_type) return "SQL$CHARSETS"; case obj_collations: return "SQL$COLLATIONS"; + case obj_tablespaces: + return "SQL$TABLESPACES"; default: return ""; } diff --git a/src/jrd/ods.h b/src/jrd/ods.h index 73fd2ae28b6..7149783ef09 100644 --- a/src/jrd/ods.h +++ b/src/jrd/ods.h @@ -182,16 +182,17 @@ const USHORT USER_DEF_REL_INIT_ID = 128; // ODS >= 9 // Page types const SCHAR pag_undefined = 0; -const SCHAR pag_header = 1; // Database header page -const SCHAR pag_pages = 2; // Page inventory page -const SCHAR pag_transactions = 3; // Transaction inventory page -const SCHAR pag_pointer = 4; // Pointer page -const SCHAR pag_data = 5; // Data page -const SCHAR pag_root = 6; // Index root page -const SCHAR pag_index = 7; // Index (B-tree) page -const SCHAR pag_blob = 8; // Blob data page -const SCHAR pag_ids = 9; // Gen-ids -const SCHAR pag_scns = 10; // SCN's inventory page +const SCHAR pag_header = 1; // Database header page (only in DB_PAGE_SPACE) +const SCHAR pag_pages = 2; // Page inventory page (per tablespace) +const SCHAR pag_transactions = 3; // Transaction inventory page (only in DB_PAGE_SPACE) +const SCHAR pag_pointer = 4; // Pointer page (in tablespace of relation) +const SCHAR pag_data = 5; // Data page (in tablespace of relation) +const SCHAR pag_root = 6; // Index root page (in tablespace of relation) +const SCHAR pag_index = 7; // Index (B-tree) page (in tablespace of relation by default + // or in its own one) +const SCHAR pag_blob = 8; // Blob data page (in relation tablespace or temp pagespace) +const SCHAR pag_ids = 9; // Gen-ids (only in DB_PAGE_SPACE) +const SCHAR pag_scns = 10; // SCN's inventory page (per tablespace) const SCHAR pag_max = 10; // Max page type // Pre-defined page numbers @@ -359,6 +360,7 @@ struct index_root_page { private: friend struct index_root_page; // to allow offset check for private members + USHORT irt_page_space_id; // page space of index root ULONG irt_root; // page number of index root if irt_in_progress is NOT set, or // highest 32 bit of transaction if irt_in_progress is set ULONG irt_transaction; // transaction in progress (lowest 32 bits) @@ -367,8 +369,9 @@ struct index_root_page UCHAR irt_keys; // number of keys in index UCHAR irt_flags; - ULONG getRoot() const; - void setRoot(ULONG root_page); + USHORT getRootPageSpaceId() const; + ULONG getRootPage() const; + void setRoot(USHORT pageSpaceId, ULONG page); TraNumber getTransaction() const; void setTransaction(TraNumber traNumber); @@ -377,15 +380,16 @@ struct index_root_page } irt_rpt[1]; - static_assert(sizeof(struct irt_repeat) == 12, "struct irt_repeat size mismatch"); - static_assert(offsetof(struct irt_repeat, irt_root) == 0, "irt_root offset mismatch"); - static_assert(offsetof(struct irt_repeat, irt_transaction) == 4, "irt_transaction offset mismatch"); - static_assert(offsetof(struct irt_repeat, irt_desc) == 8, "irt_desc offset mismatch"); - static_assert(offsetof(struct irt_repeat, irt_keys) == 10, "irt_keys offset mismatch"); - static_assert(offsetof(struct irt_repeat, irt_flags) == 11, "irt_flags offset mismatch"); + static_assert(sizeof(struct irt_repeat) == 16, "struct irt_repeat size mismatch"); + static_assert(offsetof(struct irt_repeat, irt_page_space_id) == 0, "irt_page_space_id offset mismatch"); + static_assert(offsetof(struct irt_repeat, irt_root) == 4, "irt_root offset mismatch"); + static_assert(offsetof(struct irt_repeat, irt_transaction) == 8, "irt_transaction offset mismatch"); + static_assert(offsetof(struct irt_repeat, irt_desc) == 12, "irt_desc offset mismatch"); + static_assert(offsetof(struct irt_repeat, irt_keys) == 14, "irt_keys offset mismatch"); + static_assert(offsetof(struct irt_repeat, irt_flags) == 15, "irt_flags offset mismatch"); }; -static_assert(sizeof(struct index_root_page) == 32, "struct index_root_page size mismatch"); +static_assert(sizeof(struct index_root_page) == 36, "struct index_root_page size mismatch"); static_assert(offsetof(struct index_root_page, irt_header) == 0, "irt_header offset mismatch"); static_assert(offsetof(struct index_root_page, irt_relation) == 16, "irt_relation offset mismatch"); static_assert(offsetof(struct index_root_page, irt_count) == 18, "irt_count offset mismatch"); @@ -413,14 +417,20 @@ const USHORT irt_foreign = 8; const USHORT irt_primary = 16; const USHORT irt_expression = 32; -inline ULONG index_root_page::irt_repeat::getRoot() const +inline USHORT index_root_page::irt_repeat::getRootPageSpaceId() const +{ + return irt_page_space_id; +} + +inline ULONG index_root_page::irt_repeat::getRootPage() const { return (irt_flags & irt_in_progress) ? 0 : irt_root; } -inline void index_root_page::irt_repeat::setRoot(ULONG root_page) +inline void index_root_page::irt_repeat::setRoot(USHORT pageSpaceId, ULONG page) { - irt_root = root_page; + irt_page_space_id = pageSpaceId; + irt_root = page; irt_flags &= ~irt_in_progress; } diff --git a/src/jrd/os/pio_proto.h b/src/jrd/os/pio_proto.h index 58ae49e885f..ad6e582e44b 100644 --- a/src/jrd/os/pio_proto.h +++ b/src/jrd/os/pio_proto.h @@ -67,6 +67,7 @@ inline bool PIO_on_raw_device(const Firebird::PathName&) } #endif bool PIO_write(Jrd::thread_db*, Jrd::jrd_file*, Jrd::BufferDesc*, Ods::pag*, Jrd::FbStatusVector*); +bool PIO_file_exists(const Firebird::PathName&); #endif // JRD_PIO_PROTO_H diff --git a/src/jrd/os/posix/unix.cpp b/src/jrd/os/posix/unix.cpp index 0f64e9a6bb5..3556b7032ad 100644 --- a/src/jrd/os/posix/unix.cpp +++ b/src/jrd/os/posix/unix.cpp @@ -1173,6 +1173,17 @@ bool PIO_on_raw_device(const PathName& file_name) } +bool PIO_file_exists(const Firebird::PathName& fileName) +{ + const int fd = openFile(fileName.c_str(), false, false, true); + if (fd == -1) + return false; + + close(fd); + return true; +} + + static bool raw_devices_validate_database(int desc, const PathName& file_name) { /************************************** diff --git a/src/jrd/os/win32/winnt.cpp b/src/jrd/os/win32/winnt.cpp index 5bc55c6fa22..e1f2b5f2bbd 100644 --- a/src/jrd/os/win32/winnt.cpp +++ b/src/jrd/os/win32/winnt.cpp @@ -790,6 +790,18 @@ ULONG PIO_get_number_of_pages(const jrd_file* file, const USHORT pagesize) } +bool PIO_file_exists(const Firebird::PathName& fileName) +{ + const FILE_DESC fd = CreateFile(fileName.c_str(), GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (fd == INVALID_HANDLE_VALUE) + return false; + + CloseHandle(fd); + return true; +} + + static jrd_file* seek_file(jrd_file* file, BufferDesc* bdb, OVERLAPPED* overlapped) diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index c61ea091e44..b0ef8bc75d1 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -1531,8 +1531,9 @@ void PAG_release_page(thread_db* tdbb, const PageNumber& number, const PageNumbe * **************************************/ - fb_assert(number.getPageSpaceID() == prior_page.getPageSpaceID() || - prior_page == ZERO_PAGE_NUMBER); + // RS: When index is on another tablespace this maybe wrong assert if prior is IRP +// fb_assert(number.getPageSpaceID() == prior_page.getPageSpaceID() || +// prior_page == ZERO_PAGE_NUMBER); const ULONG pgNum = number.getPageNum(); PAG_release_pages(tdbb, number.getPageSpaceID(), 1, &pgNum, prior_page.getPageNum()); @@ -2442,7 +2443,7 @@ bool PageSpace::extend(thread_db* tdbb, const ULONG pageNum, const bool forceSiz return true; } -ULONG PageSpace::getSCNPageNum(ULONG sequence) +ULONG PageSpace::getSCNPageNum(ULONG sequence) const { /************************************** * @@ -2460,12 +2461,6 @@ ULONG PageSpace::getSCNPageNum(ULONG sequence) return sequence * dbb->dbb_page_manager.pagesPerSCN; } -ULONG PageSpace::getSCNPageNum(const Database* dbb, ULONG sequence) -{ - PageSpace* pgSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); - return pgSpace->getSCNPageNum(sequence); -} - PageSpace* PageManager::addPageSpace(const USHORT pageSpaceID) { PageSpace* newPageSpace = findPageSpace(pageSpaceID); @@ -2567,6 +2562,40 @@ USHORT PageManager::getTempPageSpaceID(thread_db* tdbb) return tempPageSpaceID; } + +void PageManager::allocTableSpace(thread_db* tdbb, USHORT tableSpaceID, bool create, const PathName& fileName) +{ + /*** + * NOTE: PageSpaceId of Tablespaces is equal to tablespace id + */ + fb_assert((tableSpaceID > DB_PAGE_SPACE) && (tableSpaceID < TRANS_PAGE_SPACE)); + + PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(tableSpaceID); + if (!pageSpace) + { + Firebird::MutexLockGuard guard(initTmpMtx, FB_FUNCTION); + // Double check if someone concurrently have added the tablespaceid + if (pageSpace = dbb->dbb_page_manager.findPageSpace(tableSpaceID)) + return; + pageSpace = dbb->dbb_page_manager.addPageSpace(tableSpaceID); + if (create) + { + pageSpace->file = PIO_create(tdbb, fileName, false, false); + PAG_format_pip(tdbb, *pageSpace); + } + else + { + pageSpace->file = PIO_open(tdbb, fileName, fileName); + pageSpace->pipFirst = FIRST_PIP_PAGE; + pageSpace->scnFirst = FIRST_SCN_PAGE; + } + if (dbb->dbb_flags & (DBB_force_write | DBB_no_fs_cache)) + PIO_force_write(pageSpace->file, dbb->dbb_flags & DBB_force_write, dbb->dbb_flags & DBB_no_fs_cache); + + } +} + + ULONG PAG_page_count(thread_db* tdbb) { /********************************************* diff --git a/src/jrd/pag.h b/src/jrd/pag.h index dc786782fad..ebce378777c 100644 --- a/src/jrd/pag.h +++ b/src/jrd/pag.h @@ -62,7 +62,8 @@ class PageControl : public pool_alloc // INVALID_PAGE_SPACE is to ??? const USHORT INVALID_PAGE_SPACE = 0; const USHORT DB_PAGE_SPACE = 1; -const USHORT TRANS_PAGE_SPACE = 255; +// .. here all tablespace IDs. Keep TRANS_PAGE_SPACE right after DB_PAGE_SPACE +const USHORT TRANS_PAGE_SPACE = 255; // is not used for tablespace id const USHORT TEMP_PAGE_SPACE = 256; const USHORT PAGES_IN_EXTENT = 8; @@ -133,8 +134,7 @@ class PageSpace : public pool_alloc bool extend(thread_db*, const ULONG, const bool); // get SCN's page number - ULONG getSCNPageNum(ULONG sequence); - static ULONG getSCNPageNum(const Database* dbb, ULONG sequence); + ULONG getSCNPageNum(ULONG sequence) const; // is pagespace on raw device bool onRawDevice() const; @@ -175,6 +175,8 @@ class PageManager : public pool_alloc void initTempPageSpace(thread_db* tdbb); USHORT getTempPageSpaceID(thread_db* tdbb); + void allocTableSpace(thread_db* tdbb, USHORT tableSpaceID, bool create, const Firebird::PathName& fileName); + void closeAll(); ULONG pagesPerPIP; // Pages per pip diff --git a/src/jrd/recsrc/IndexTableScan.cpp b/src/jrd/recsrc/IndexTableScan.cpp index 00c3a4719bd..5377f4b0d00 100644 --- a/src/jrd/recsrc/IndexTableScan.cpp +++ b/src/jrd/recsrc/IndexTableScan.cpp @@ -133,7 +133,7 @@ bool IndexTableScan::getRecord(thread_db* tdbb) const index_desc* const idx = (index_desc*) ((SCHAR*) impure + m_offset); // find the last fetched position from the index - const USHORT pageSpaceID = m_relation->getPages(tdbb)->rel_pg_space_id; + const USHORT pageSpaceID = idx->idx_pg_space_id; win window(pageSpaceID, impure->irsb_nav_page); UCHAR* nextPointer = getPosition(tdbb, impure, &window); diff --git a/src/jrd/relations.h b/src/jrd/relations.h index ceb93f0c6c3..3695d92590f 100644 --- a/src/jrd/relations.h +++ b/src/jrd/relations.h @@ -99,6 +99,7 @@ RELATION(nam_indices, rel_indices, ODS_8_0, rel_persistent) FIELD(f_idx_exp_blr, nam_exp_blr, fld_value, 1, ODS_8_0) FIELD(f_idx_exp_source, nam_exp_source, fld_source, 1, ODS_8_0) FIELD(f_idx_statistics, nam_statistics, fld_statistics, 1, ODS_8_0) + FIELD(f_idx_ts_name, nam_ts_name, fld_ts_name, 1, ODS_13_0) // TODO: fix ODS version END_RELATION // Relation 5 (RDB$RELATION_FIELDS) @@ -124,6 +125,7 @@ RELATION(nam_r_fields, rel_rfr, ODS_8_0, rel_persistent) FIELD(f_rfr_coll_id, nam_collate_id, fld_collate_id, 1, ODS_8_0) FIELD(f_rfr_gen_name, nam_gen_name, fld_gen_name, 1, ODS_12_0) FIELD(f_rfr_identity_type, nam_identity_type, fld_identity_type, 1, ODS_12_0) + FIELD(f_rfr_ts_name, nam_ts_name, fld_ts_name, 1, ODS_13_0) // TODO: fix ODS version END_RELATION // Relation 6 (RDB$RELATIONS) @@ -146,6 +148,9 @@ RELATION(nam_relations, rel_relations, ODS_8_0, rel_persistent) FIELD(f_rel_flags, nam_flags, fld_flag_nullable, 0, ODS_8_0) FIELD(f_rel_type, nam_r_type, fld_r_type, 0, ODS_11_1) FIELD(f_rel_sql_security, nam_sql_security, fld_b_sql_security, 1, ODS_13_0) + FIELD(f_rel_ts_name, nam_ts_name, fld_ts_name, 1, ODS_13_0) //TODO: fix ODS version + FIELD(f_rel_first_pp, nam_pp_number, fld_pp_number, 0, ODS_13_0) //TODO: fix ODS version + FIELD(f_rel_idx_root, nam_idx_number, fld_idx_number, 0, ODS_13_0) //TODO: fix ODS version END_RELATION // Relation 7 (RDB$VIEW_RELATIONS) @@ -704,3 +709,17 @@ RELATION(nam_time_zones, rel_time_zones, ODS_13_0, rel_virtual) FIELD(f_tz_id, nam_tz_id, fld_tz_id, 0, ODS_13_0) FIELD(f_tz_name, nam_tz_name, fld_tz_name, 0, ODS_13_0) END_RELATION + +// Relation 51 (RDB$TABLESPACES) +// TODO: fix ODS version +RELATION(nam_tablespaces, rel_tablespaces, ODS_13_0, rel_persistent) + FIELD(f_ts_id, nam_ts_id, fld_ts_id, 0, ODS_13_0) + FIELD(f_ts_name, nam_ts_name, fld_ts_name, 1, ODS_13_0) + FIELD(f_ts_class, nam_class, fld_class, 1, ODS_13_0) + FIELD(f_ts_sys_flag, nam_sys_flag, fld_flag, 1, ODS_13_0) + FIELD(f_ts_desc, nam_description, fld_description, 1, ODS_13_0) + FIELD(f_ts_owner, nam_owner, fld_user, 1, ODS_13_0) + FIELD(f_ts_file, nam_file_name, fld_file_name, 1, ODS_13_0) + FIELD(f_ts_offline, nam_ts_offline, fld_flag, 1, ODS_13_0) + FIELD(f_ts_readonly, nam_ts_readonly, fld_flag, 1, ODS_13_0) +END_RELATION diff --git a/src/jrd/replication/Applier.cpp b/src/jrd/replication/Applier.cpp index f3d0790307e..f08bbcffa31 100644 --- a/src/jrd/replication/Applier.cpp +++ b/src/jrd/replication/Applier.cpp @@ -798,7 +798,7 @@ bool Applier::lookupKey(thread_db* tdbb, jrd_rel* relation, index_desc& key) auto page = relPages->rel_index_root; if (!page) { - DPM_scan_pages(tdbb); + DPM_scan_pages(tdbb, pag_root, relation->rel_id); page = relPages->rel_index_root; } diff --git a/src/jrd/scl.epp b/src/jrd/scl.epp index 17301b13dfa..3b9d96a53e6 100644 --- a/src/jrd/scl.epp +++ b/src/jrd/scl.epp @@ -890,6 +890,44 @@ void SCL_check_role(thread_db* tdbb, const Firebird::MetaName& name, SecurityCla SCL_check_access(tdbb, s_class, 0, NULL, mask, SCL_object_role, false, name); } + +void SCL_check_tablespace(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flags_t mask) +{ +/************************************** + * + * S C L _ c h e c k _ t a b l e s p a c e + * + ************************************** + * + * Functional description + * Given a tablespace name, check for a set of privileges. + * + **************************************/ + SET_TDBB(tdbb); + + // Get the name in CSTRING format, ending on NULL or SPACE + fb_assert(dsc_name->dsc_dtype == dtype_text); + const Firebird::MetaName name(reinterpret_cast(dsc_name->dsc_address), + dsc_name->dsc_length); + + Jrd::Attachment* const attachment = tdbb->getAttachment(); + + const SecurityClass* s_class = NULL; + AutoCacheRequest request(tdbb, irq_ts_security, IRQ_REQUESTS); + + FOR (REQUEST_HANDLE request) + X IN RDB$TABLESPACES + WITH X.RDB$TABLESPACE_NAME EQ name.c_str() + { + if (!X.RDB$SECURITY_CLASS.NULL) + s_class = SCL_get_class(tdbb, X.RDB$SECURITY_CLASS); + } + END_FOR + + SCL_check_access(tdbb, s_class, 0, name, mask, SCL_object_tablespace, false, name); +} + + SecurityClass* SCL_get_class(thread_db* tdbb, const TEXT* par_string) { /************************************** diff --git a/src/jrd/scl.h b/src/jrd/scl.h index 2e1c39e1c91..2f5f2d3d1a3 100644 --- a/src/jrd/scl.h +++ b/src/jrd/scl.h @@ -404,6 +404,7 @@ const SLONG SCL_object_domain = obj_domains; const SLONG SCL_object_view = obj_views; const SLONG SCL_object_role = obj_roles; const SLONG SCL_object_filter = obj_filters; +const SLONG SCL_object_tablespace = obj_tablespaces; // Please keep it with code more than other objects // - relations and procedures should be sorted before columns. const SLONG SCL_object_column = obj_type_MAX + 1; diff --git a/src/jrd/scl_proto.h b/src/jrd/scl_proto.h index 1cf35982ff7..63fcd4494a6 100644 --- a/src/jrd/scl_proto.h +++ b/src/jrd/scl_proto.h @@ -52,6 +52,7 @@ void SCL_check_filter(Jrd::thread_db* tdbb, const Firebird::MetaName &name, Jrd: void SCL_check_relation(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t, bool protectSys = true); bool SCL_check_view(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t); void SCL_check_role(Jrd::thread_db* tdbb, const Firebird::MetaName&, Jrd::SecurityClass::flags_t); +void SCL_check_tablespace(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t); Jrd::SecurityClass* SCL_get_class(Jrd::thread_db*, const TEXT*); Jrd::SecurityClass::flags_t SCL_get_mask(Jrd::thread_db* tdbb, const TEXT*, const TEXT*); void SCL_clear_classes(Jrd::thread_db*, const TEXT*); diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index 8c2e39070c0..4eea5fe5174 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -78,6 +78,7 @@ #include "../jrd/Mapping.h" #include "../jrd/DbCreators.h" #include "../common/os/fbsyslog.h" +#include "../jrd/Tablespace.h" const int DYN_MSG_FAC = 8; @@ -527,7 +528,7 @@ void TRA_commit(thread_db* tdbb, jrd_tra* transaction, const bool retaining_flag // Perform any post commit work - DFW_perform_post_commit_work(transaction); + DFW_perform_post_commit_work(tdbb, transaction); // notify any waiting locks that this transaction is committing; // there could be no lock if this transaction is being reconnected @@ -951,6 +952,8 @@ void TRA_post_resources(thread_db* tdbb, jrd_tra* transaction, ResourceList& res Jrd::ContextPoolHolder context(tdbb, transaction->tra_pool); + USHORT usedTablespaces[TRANS_PAGE_SPACE] = {0}; + for (Resource* rsc = resources.begin(); rsc < resources.end(); rsc++) { if (rsc->rsc_type == Resource::rsc_relation || @@ -969,6 +972,7 @@ void TRA_post_resources(thread_db* tdbb, jrd_tra* transaction, ResourceList& res if (rsc->rsc_rel->rel_file) { EXT_tra_attach(rsc->rsc_rel->rel_file, transaction); } + usedTablespaces[rsc->rsc_rel->getBasePages()->rel_pg_space_id]++; break; case Resource::rsc_procedure: case Resource::rsc_function: @@ -992,6 +996,15 @@ void TRA_post_resources(thread_db* tdbb, jrd_tra* transaction, ResourceList& res } } } + + // Now let's lock all used tablespaces + for (USHORT i = DB_PAGE_SPACE + 1; i < TRANS_PAGE_SPACE; i++) + if (usedTablespaces[i] > 0) + { + // Tablespace is locking after the use in relation and indices. + // Should we check it here again? + tdbb->getAttachment()->getTablespace(i)->addRef(tdbb); + } } @@ -1233,6 +1246,7 @@ void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction, Jrd::TraceTr } // Release interest in relation/procedure existence for transaction + USHORT usedTablespaces[TRANS_PAGE_SPACE] = {0}; for (Resource* rsc = transaction->tra_resources.begin(); rsc < transaction->tra_resources.end(); rsc++) @@ -1244,6 +1258,7 @@ void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction, Jrd::TraceTr if (rsc->rsc_rel->rel_file) { EXT_tra_detach(rsc->rsc_rel->rel_file, transaction); } + usedTablespaces[rsc->rsc_rel->getBasePages()->rel_pg_space_id]++; break; case Resource::rsc_procedure: case Resource::rsc_function: @@ -1259,6 +1274,28 @@ void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction, Jrd::TraceTr release_temp_tables(tdbb, transaction); + // Now let's release all used tablespaces + for (USHORT i = DB_PAGE_SPACE + 1; i < TRANS_PAGE_SPACE; i++) + if (usedTablespaces[i] > 0) + { + // Tablespace is locking after the use in relation and indices. + // Should we check it here again? + tdbb->getAttachment()->getTablespace(i)->release(tdbb); + } + + { // scope + vec& rels = *attachment->att_relations; + + for (FB_SIZE_T i = 0; i < rels.count(); i++) + { + jrd_rel* relation = rels[i]; + + if (relation && (relation->rel_flags & REL_temp_tran)) + relation->delPages(tdbb, transaction->tra_number); + } + + } // end scope + // Release the locks associated with the transaction if (transaction->tra_alter_db_lock) @@ -2320,7 +2357,7 @@ static ULONG inventory_page(thread_db* tdbb, ULONG sequence) vcl* vector = dbb->dbb_t_pages; while (!vector || sequence >= vector->count()) { - DPM_scan_pages(tdbb); + DPM_scan_pages(tdbb, pag_transactions); if ((vector = dbb->dbb_t_pages) && sequence < vector->count()) break; @@ -2625,7 +2662,7 @@ static void retain_context(thread_db* tdbb, jrd_tra* transaction, bool commit, i // Perform any post commit work OR delete entries from deferred list if (commit) - DFW_perform_post_commit_work(transaction); + DFW_perform_post_commit_work(tdbb, transaction); else DFW_delete_deferred(transaction, -1); diff --git a/src/jrd/tra.h b/src/jrd/tra.h index b14a04d8105..1487367fd44 100644 --- a/src/jrd/tra.h +++ b/src/jrd/tra.h @@ -512,6 +512,13 @@ enum dfw_t { dfw_check_not_null, dfw_store_view_context_type, dfw_set_generator, + dfw_create_tablespace, + dfw_check_tablespace_dependencies, + dfw_drop_tablespace_dependencies, + dfw_move_relation, + dfw_move_index, + dfw_clear_datapages, + dfw_clear_indexpages, // deferred works argument types dfw_arg_index_name, // index name for dfw_delete_expression_index, mandatory diff --git a/src/jrd/trig.h b/src/jrd/trig.h index 569a0e51c0a..9a1924010d8 100644 --- a/src/jrd/trig.h +++ b/src/jrd/trig.h @@ -81,6 +81,7 @@ static const Jrd::gen generators[] = { "RDB$BACKUP_HISTORY", 9, "Nbackup technology" }, { FUNCTIONS_GENERATOR, 10, "Function ID" }, { "RDB$GENERATOR_NAME", 11, "Implicit generator name" }, + { "RDB$TABLESPACES", 12, "Tablespace ID" }, { nullptr, 0, nullptr } }; diff --git a/src/jrd/validation.cpp b/src/jrd/validation.cpp index 129eab53d8a..1aa841f33aa 100644 --- a/src/jrd/validation.cpp +++ b/src/jrd/validation.cpp @@ -570,6 +570,8 @@ VI. ADDITIONAL NOTES #include "../common/db_alias.h" #include "../jrd/intl_proto.h" #include "../jrd/lck_proto.h" +#include "../jrd/PreparedStatement.h" +#include "../jrd/ResultSet.h" #ifdef DEBUG_VAL_VERBOSE #include "../jrd/dmp_proto.h" @@ -811,20 +813,20 @@ namespace Jrd const Validation::MSG_ENTRY Validation::vdr_msg_table[VAL_MAX_ERROR] = { - {true, isc_info_page_errors, "Page %" ULONGFORMAT" wrong type (expected %s encountered %s)"}, // 0 - {true, isc_info_page_errors, "Checksum error on page %" ULONGFORMAT}, - {true, isc_info_page_errors, "Page %" ULONGFORMAT" doubly allocated"}, - {true, isc_info_page_errors, "Page %" ULONGFORMAT" is used but marked free"}, - {false, fb_info_page_warns, "Page %" ULONGFORMAT" is an orphan"}, + {true, isc_info_page_errors, "Page (%d, %" ULONGFORMAT") wrong type (expected %s encountered %s)"}, // 0 + {true, isc_info_page_errors, "Checksum error on page (%d, %" ULONGFORMAT")"}, + {true, isc_info_page_errors, "Page (%d, %" ULONGFORMAT") doubly allocated"}, + {true, isc_info_page_errors, "Page (%d, %" ULONGFORMAT") is used but marked free"}, + {false, fb_info_page_warns, "Page (%d, %" ULONGFORMAT") is an orphan"}, {false, fb_info_bpage_warns, "Blob %" SQUADFORMAT" appears inconsistent"}, // 5 {true, isc_info_bpage_errors, "Blob %" SQUADFORMAT" is corrupt"}, {true, isc_info_bpage_errors, "Blob %" SQUADFORMAT" is truncated"}, {true, isc_info_record_errors, "Chain for record %" SQUADFORMAT" is broken"}, - {true, isc_info_dpage_errors, "Data page %" ULONGFORMAT" {sequence %" ULONGFORMAT"} is confused"}, - {true, isc_info_dpage_errors, "Data page %" ULONGFORMAT" {sequence %" ULONGFORMAT"}, line %" ULONGFORMAT" is bad"}, // 10 - {true, isc_info_ipage_errors, "Index %d is corrupt on page %" ULONGFORMAT" level %d at offset %" ULONGFORMAT". File: %s, line: %d\n\t"}, + {true, isc_info_dpage_errors, "Data page (%d, %" ULONGFORMAT") {sequence %" ULONGFORMAT"} is confused"}, + {true, isc_info_dpage_errors, "Data page (%d, %" ULONGFORMAT") {sequence %" ULONGFORMAT"}, line %" ULONGFORMAT" is bad"}, // 10 + {true, isc_info_ipage_errors, "Index %d is corrupt on page (%d, %" ULONGFORMAT") level %d at offset %" ULONGFORMAT". File: %s, line: %d\n\t"}, {true, isc_info_ppage_errors, "Pointer page {sequence %" ULONGFORMAT"} lost"}, - {true, isc_info_ppage_errors, "Pointer page %" ULONGFORMAT" {sequence %" ULONGFORMAT"} inconsistent"}, + {true, isc_info_ppage_errors, "Pointer page (%d, %" ULONGFORMAT") {sequence %" ULONGFORMAT"} inconsistent"}, {true, isc_info_record_errors, "Record %" SQUADFORMAT" is marked as damaged"}, {true, isc_info_record_errors, "Record %" SQUADFORMAT" has bad transaction %" SQUADFORMAT}, // 15 {true, isc_info_record_errors, "Fragmented record %" SQUADFORMAT" is corrupt"}, @@ -835,29 +837,29 @@ const Validation::MSG_ENTRY Validation::vdr_msg_table[VAL_MAX_ERROR] = {true, isc_info_tpage_errors, "Transaction inventory pages confused, sequence %" ULONGFORMAT}, {false, fb_info_record_warns, "Relation has %" UQUADFORMAT" orphan backversions {%" UQUADFORMAT" in use}"}, {true, isc_info_ipage_errors, "Index %d is corrupt {missing entries for record %" SQUADFORMAT"}"}, - {false, fb_info_ipage_warns, "Index %d has orphan child page at page %" ULONGFORMAT}, - {true, isc_info_ipage_errors, "Index %d has a circular reference at page %" ULONGFORMAT}, // 25 - {true, isc_info_page_errors, "SCN's page %" ULONGFORMAT" {sequence %" ULONGFORMAT"} inconsistent"}, - {false, fb_info_page_warns, "Page %" ULONGFORMAT" has SCN %" ULONGFORMAT" while at SCN's page it is %" ULONGFORMAT}, + {false, fb_info_ipage_warns, "Index %d has orphan child page at page (%d, %" ULONGFORMAT")"}, + {true, isc_info_ipage_errors, "Index %d has a circular reference at page (%d, %" ULONGFORMAT")"}, // 25 + {true, isc_info_page_errors, "SCN's page (%d, %" ULONGFORMAT") {sequence %" ULONGFORMAT"} inconsistent"}, + {false, fb_info_page_warns, "Page (%d, %" ULONGFORMAT") has SCN %" ULONGFORMAT" while at SCN's page it is %" ULONGFORMAT}, {true, isc_info_bpage_errors, "Blob %" SQUADFORMAT" has unknown level %d instead of {0, 1, 2}"}, - {false, fb_info_ipage_warns, "Index %d has inconsistent left sibling pointer, page %" ULONGFORMAT" level %d at offset %" ULONGFORMAT}, - {false, fb_info_ipage_warns, "Index %d misses node on page %" ULONGFORMAT" level %d at offset %" ULONGFORMAT}, // 30 - {false, fb_info_pip_warns, "PIP %" ULONGFORMAT" (seq %d) have wrong pip_min (%" ULONGFORMAT"). Correct is %" ULONGFORMAT}, - {false, fb_info_pip_warns, "PIP %" ULONGFORMAT" (seq %d) have wrong pip_extent (%" ULONGFORMAT"). Correct is %" ULONGFORMAT}, - {false, fb_info_pip_warns, "PIP %" ULONGFORMAT" (seq %d) have wrong pip_used (%" ULONGFORMAT"). Correct is %" ULONGFORMAT}, - {false, fb_info_ppage_warns, "Pointer page %" ULONGFORMAT" {sequence %" ULONGFORMAT"} bits {0x%02X %s} are not consistent with data page %" ULONGFORMAT" {sequence %" ULONGFORMAT"} state {0x%02X %s}"}, - {true, fb_info_pip_errors, "Data page %" ULONGFORMAT" marked as free in PIP (%" ULONGFORMAT":%" ULONGFORMAT")"}, - {true, isc_info_ppage_errors, "Data page %" ULONGFORMAT" is not in PP (%" ULONGFORMAT"). Slot (%d) is not found"}, - {true, isc_info_ppage_errors, "Data page %" ULONGFORMAT" is not in PP (%" ULONGFORMAT"). Slot (%d) has value %" ULONGFORMAT}, - {true, isc_info_ppage_errors, "Pointer page is not found for data page %" ULONGFORMAT". dpg_sequence (%" ULONGFORMAT") is invalid"}, - {true, isc_info_dpage_errors, "Data page %" ULONGFORMAT" {sequence %" ULONGFORMAT"} marked as secondary but contains primary record versions"} + {false, fb_info_ipage_warns, "Index %d has inconsistent left sibling pointer, page (%d, %" ULONGFORMAT") level %d at offset %" ULONGFORMAT}, + {false, fb_info_ipage_warns, "Index %d misses node on page (%d, %" ULONGFORMAT") level %d at offset %" ULONGFORMAT}, // 30 + {false, fb_info_pip_warns, "PIP (%d, %" ULONGFORMAT") (seq %d) have wrong pip_min (%" ULONGFORMAT"). Correct is %" ULONGFORMAT}, + {false, fb_info_pip_warns, "PIP (%d, %" ULONGFORMAT") (seq %d) have wrong pip_extent (%" ULONGFORMAT"). Correct is %" ULONGFORMAT}, + {false, fb_info_pip_warns, "PIP (%d, %" ULONGFORMAT") (seq %d) have wrong pip_used (%" ULONGFORMAT"). Correct is %" ULONGFORMAT}, + {false, fb_info_ppage_warns, "Pointer page (%d, %" ULONGFORMAT") {sequence %" ULONGFORMAT"} bits {0x%02X %s} are not consistent with data page (%d, %" ULONGFORMAT") {sequence %" ULONGFORMAT"} state {0x%02X %s}"}, + {true, fb_info_pip_errors, "Data page (%d, %" ULONGFORMAT") marked as free in PIP (%" ULONGFORMAT":%" ULONGFORMAT")"}, // 35 + {true, isc_info_ppage_errors, "Data page (%d, %" ULONGFORMAT") is not in PP (%" ULONGFORMAT"). Slot (%d) is not found"}, + {true, isc_info_ppage_errors, "Data page (%d, %" ULONGFORMAT") is not in PP (%" ULONGFORMAT"). Slot (%d) has value %" ULONGFORMAT}, + {true, isc_info_ppage_errors, "Pointer page is not found for data page (%d, %" ULONGFORMAT"). dpg_sequence (%" ULONGFORMAT") is invalid"}, + {true, isc_info_dpage_errors, "Data page (%d, %" ULONGFORMAT") {sequence %" ULONGFORMAT"} marked as secondary but contains primary record versions"} }; Validation::Validation(thread_db* tdbb, UtilSvc* uSvc) : vdr_used_bdbs(*tdbb->getDefaultPool()) { vdr_tdbb = tdbb; - vdr_max_page = 0; + memset(vdr_max_page, 0, sizeof(vdr_max_page)); vdr_flags = 0; vdr_errors = 0; vdr_warns = 0; @@ -869,7 +871,7 @@ Validation::Validation(thread_db* tdbb, UtilSvc* uSvc) : vdr_chain_pages = NULL; vdr_rel_records = NULL; vdr_idx_records = NULL; - vdr_page_bitmap = NULL; + memset(vdr_page_bitmap, 0, sizeof(vdr_page_bitmap)); vdr_service = uSvc; vdr_lock_tout = -10; @@ -1074,8 +1076,13 @@ bool Validation::run(thread_db* tdbb, USHORT flags) void Validation::cleanup() { - delete vdr_page_bitmap; - vdr_page_bitmap = NULL; + for (USHORT i = DB_PAGE_SPACE; i < TRANS_PAGE_SPACE; i++) + { + if (!vdr_page_bitmap[i]) + continue; + delete vdr_page_bitmap[i]; + vdr_page_bitmap[i] = NULL; + } delete vdr_rel_records; vdr_rel_records = NULL; @@ -1162,7 +1169,7 @@ Validation::RTN Validation::corrupt(int err_code, const jrd_rel* relation, ...) return rtn_corrupt; } -Validation::FETCH_CODE Validation::fetch_page(bool mark, ULONG page_number, +Validation::FETCH_CODE Validation::fetch_page(bool mark, PageNumber page_number, USHORT type, WIN* window, void* aPage_pointer) { /************************************** @@ -1199,7 +1206,7 @@ Validation::FETCH_CODE Validation::fetch_page(bool mark, ULONG page_number, vdr_used_bdbs[pos].count++; BufferDesc* bdb = vdr_used_bdbs[pos].bdb; - fb_assert(bdb->bdb_page == PageNumber(DB_PAGE_SPACE, page_number)); + fb_assert(bdb->bdb_page == page_number); window->win_bdb = bdb; *page_pointer = window->win_buffer = bdb->bdb_buffer; @@ -1215,7 +1222,7 @@ Validation::FETCH_CODE Validation::fetch_page(bool mark, ULONG page_number, if ((*page_pointer)->pag_type != type && type != pag_undefined) { - corrupt(VAL_PAG_WRONG_TYPE, 0, page_number, + corrupt(VAL_PAG_WRONG_TYPE, 0, page_number.getPageSpaceID(), page_number.getPageNum(), pagtype(type).c_str(), pagtype((*page_pointer)->pag_type).c_str()); return fetch_type; } @@ -1227,12 +1234,16 @@ Validation::FETCH_CODE Validation::fetch_page(bool mark, ULONG page_number, if ((dbb->dbb_flags & DBB_damaged) && !CCH_validate(window)) { - corrupt(VAL_PAG_CHECKSUM_ERR, 0, page_number); + corrupt(VAL_PAG_CHECKSUM_ERR, 0, page_number.getPageSpaceID(), page_number.getPageNum()); if (vdr_flags & VDR_repair) CCH_MARK(vdr_tdbb, window); } - vdr_max_page = MAX(vdr_max_page, page_number); + const int pageSpaceId = page_number.getPageSpaceID(); + const PageManager& pageMgr = dbb->dbb_page_manager; + const PageSpace* pageSpace = pageMgr.findPageSpace(pageSpaceId); + + vdr_max_page[pageSpaceId] = MAX(vdr_max_page[pageSpaceId], page_number.getPageNum()); // For walking back versions & record fragments on data pages we // sometimes will fetch the same page more than once. In that @@ -1244,22 +1255,21 @@ Validation::FETCH_CODE Validation::fetch_page(bool mark, ULONG page_number, // non pag_scns type. if (type != pag_data && type != pag_scns && - PageBitmap::test(vdr_page_bitmap, page_number)) + PageBitmap::test(vdr_page_bitmap[pageSpaceId], page_number.getPageNum())) { - corrupt(VAL_PAG_DOUBLE_ALLOC, 0, page_number); + corrupt(VAL_PAG_DOUBLE_ALLOC, 0, page_number.getPageSpaceID(), page_number.getPageNum()); return fetch_duplicate; } // Check SCN's page - if (page_number) + if (page_number.getPageNum()) { - const PageManager& pageMgr = dbb->dbb_page_manager; - const ULONG scn_seq = page_number / pageMgr.pagesPerSCN; - const ULONG scn_slot = page_number % pageMgr.pagesPerSCN; - const ULONG scn_page_num = PageSpace::getSCNPageNum(dbb, scn_seq); + const ULONG scn_seq = page_number.getPageNum() / pageMgr.pagesPerSCN; + const ULONG scn_slot = page_number.getPageNum() % pageMgr.pagesPerSCN; + const PageNumber scn_page_num(pageSpaceId, pageSpace->getSCNPageNum(scn_seq)); const ULONG page_scn = (*page_pointer)->pag_scn; - WIN scns_window(DB_PAGE_SPACE, scn_page_num); + WIN scns_window(scn_page_num); scns_page* scns = (scns_page*) *page_pointer; if (scn_page_num != page_number) { @@ -1268,7 +1278,7 @@ Validation::FETCH_CODE Validation::fetch_page(bool mark, ULONG page_number, if (scns->scn_pages[scn_slot] != page_scn) { - corrupt(VAL_PAG_WRONG_SCN, 0, page_number, page_scn, scns->scn_pages[scn_slot]); + corrupt(VAL_PAG_WRONG_SCN, 0, page_number.getPageSpaceID(), page_number.getPageNum(), page_scn, scns->scn_pages[scn_slot]); if (vdr_flags & VDR_update) { @@ -1285,7 +1295,7 @@ Validation::FETCH_CODE Validation::fetch_page(bool mark, ULONG page_number, } } - PBM_SET(vdr_tdbb->getDefaultPool(), &vdr_page_bitmap, page_number); + PBM_SET(vdr_tdbb->getDefaultPool(), &vdr_page_bitmap[page_number.getPageSpaceID()], page_number.getPageNum()); return fetch_ok; } @@ -1293,7 +1303,7 @@ Validation::FETCH_CODE Validation::fetch_page(bool mark, ULONG page_number, void Validation::release_page(WIN* window) { FB_SIZE_T pos; - if (!vdr_used_bdbs.find(window->win_page.getPageNum(), pos)) + if (!vdr_used_bdbs.find(window->win_page, pos)) { fb_assert(false); return; // BUG @@ -1323,64 +1333,72 @@ void Validation::garbage_collect() Database* dbb = vdr_tdbb->getDatabase(); PageManager& pageSpaceMgr = dbb->dbb_page_manager; - PageSpace* pageSpace = pageSpaceMgr.findPageSpace(DB_PAGE_SPACE); - fb_assert(pageSpace); - WIN window(DB_PAGE_SPACE, -1); - - for (ULONG sequence = 0, number = 0; number < vdr_max_page; sequence++) + for (USHORT pageSpaceId = DB_PAGE_SPACE; pageSpaceId < TRANS_PAGE_SPACE; pageSpaceId++) { - const ULONG page_number = sequence ? sequence * pageSpaceMgr.pagesPerPIP - 1 : pageSpace->pipFirst; - page_inv_page* page = 0; - fetch_page(false, page_number, pag_pages, &window, &page); - UCHAR* p = page->pip_bits; - const UCHAR* const end = p + pageSpaceMgr.bytesBitPIP; - while (p < end && number < vdr_max_page) + if (!vdr_max_page[pageSpaceId]) + continue; + + PageSpace* pageSpace = pageSpaceMgr.findPageSpace(pageSpaceId); + fb_assert(pageSpace); // probably here we need to continue if NULL + WIN window(pageSpaceId, -1); + + for (ULONG sequence = 0, number = 0; number < vdr_max_page[pageSpaceId]; sequence++) { - UCHAR byte = *p++; - for (int i = 8; i; --i, byte >>= 1, number++) + const ULONG page_number = sequence ? sequence * pageSpaceMgr.pagesPerPIP - 1 : pageSpace->pipFirst; + page_inv_page* page = 0; + fetch_page(false, PageNumber(pageSpaceId, page_number), pag_pages, &window, &page); + UCHAR* p = page->pip_bits; + const UCHAR* const end = p + pageSpaceMgr.bytesBitPIP; + while (p < end && number < vdr_max_page[pageSpaceId]) { - if (PageBitmap::test(vdr_page_bitmap, number)) + UCHAR byte = *p++; + for (int i = 8; i; --i, byte >>= 1, number++) { - if (byte & 1) + if (PageBitmap::test(vdr_page_bitmap[pageSpaceId], number)) // This page was fetched { - corrupt(VAL_PAG_IN_USE, 0, number); - if (vdr_flags & VDR_update) + if (byte & 1) // The page mark as free in PIP { - CCH_MARK(vdr_tdbb, &window); - p[-1] &= ~(1 << (number & 7)); - vdr_fixed++; + corrupt(VAL_PAG_IN_USE, 0, pageSpaceId, page_number); + if (vdr_flags & VDR_update) + { + CCH_MARK(vdr_tdbb, &window); + p[-1] &= ~(1 << (number & 7)); + vdr_fixed++; + } + DEBUG; } - DEBUG; } - } - else if (!(byte & 1) && (vdr_flags & VDR_records)) - { - // Page is potentially an orphan - but don't declare it as such - // unless we think we walked all pages - - corrupt(VAL_PAG_ORPHAN, 0, number); - if (vdr_flags & VDR_update) + else if (!(byte & 1) && (vdr_flags & VDR_records) && + (pageSpaceId == DB_PAGE_SPACE || number > HEADER_PAGE)) { - CCH_MARK(vdr_tdbb, &window); - p[-1] |= 1 << (number & 7); - vdr_fixed++; + // Page is potentially an orphan - but don't declare it as such + // unless we think we walked all pages (with full validation - VDR_records) + // For non main tablespace we skip header page. It's reserved for now + + corrupt(VAL_PAG_ORPHAN, 0, pageSpaceId, number); + if (vdr_flags & VDR_update) + { + CCH_MARK(vdr_tdbb, &window); + p[-1] |= 1 << (number & 7); + vdr_fixed++; - const ULONG bit = number - sequence * pageSpaceMgr.pagesPerPIP; - if (page->pip_min > bit) - page->pip_min = bit; + const ULONG bit = number - sequence * pageSpaceMgr.pagesPerPIP; + if (page->pip_min > bit) + page->pip_min = bit; - if (p[-1] == 0xFF && page->pip_extent > bit) - page->pip_extent = bit & ((ULONG) ~7); + if (p[-1] == 0xFF && page->pip_extent > bit) + page->pip_extent = bit & ((ULONG) ~7); + } + DEBUG; } - DEBUG; } } + const UCHAR test_byte = p[-1]; + release_page(&window); + if (test_byte & 0x80) + break; } - const UCHAR test_byte = p[-1]; - release_page(&window); - if (test_byte & 0x80) - break; } #ifdef DEBUG_VAL_VERBOSE @@ -1475,8 +1493,9 @@ Validation::RTN Validation::walk_blob(jrd_rel* relation, const blh* header, USHO corrupt(VAL_BLOB_UNKNOWN_LEVEL, relation, number.getValue(), header->blh_level); } + const USHORT pageSpaceId = relation->getBasePages()->rel_pg_space_id; // Level 1 blobs are a little more complicated - WIN window1(DB_PAGE_SPACE, -1), window2(DB_PAGE_SPACE, -1); + WIN window1(pageSpaceId, -1), window2(pageSpaceId, -1); window1.win_flags = window2.win_flags = WIN_garbage_collector; const ULONG* pages1 = header->blh_page; @@ -1486,7 +1505,7 @@ Validation::RTN Validation::walk_blob(jrd_rel* relation, const blh* header, USHO for (; pages1 < end1; pages1++) { blob_page* page1 = 0; - fetch_page(true, *pages1, pag_blob, &window1, &page1); + fetch_page(true, PageNumber(pageSpaceId, *pages1), pag_blob, &window1, &page1); if (page1->blp_lead_page != header->blh_lead_page) { corrupt(VAL_BLOB_INCONSISTENT, relation, number.getValue()); } @@ -1505,7 +1524,7 @@ Validation::RTN Validation::walk_blob(jrd_rel* relation, const blh* header, USHO for (; pages2 < end2; pages2++, sequence++) { blob_page* page2 = 0; - fetch_page(true, *pages2, pag_blob, &window2, &page2); + fetch_page(true, PageNumber(pageSpaceId, *pages2), pag_blob, &window2, &page2); if (page2->blp_lead_page != header->blh_lead_page || page2->blp_sequence != sequence) { corrupt(VAL_BLOB_CORRUPT, relation, number.getValue()); @@ -1542,9 +1561,11 @@ Validation::RTN Validation::walk_chain(jrd_rel* relation, const rhd* header, USHORT counter = 0; #endif + const USHORT pageSpaceId = relation->getBasePages()->rel_pg_space_id; + ULONG page_number = header->rhd_b_page; USHORT line_number = header->rhd_b_line; - WIN window(DB_PAGE_SPACE, -1); + WIN window(pageSpaceId, -1); window.win_flags = WIN_garbage_collector; while (page_number) @@ -1556,12 +1577,12 @@ Validation::RTN Validation::walk_chain(jrd_rel* relation, const rhd* header, #endif vdr_rel_chain_counter++; data_page* page = 0; - fetch_page(true, page_number, pag_data, &window, &page); + fetch_page(true, PageNumber(pageSpaceId, page_number), pag_data, &window, &page); if (page->dpg_relation != relation->rel_id) { release_page(&window); - return corrupt(VAL_DATA_PAGE_CONFUSED, relation, page_number, page->dpg_sequence); + return corrupt(VAL_DATA_PAGE_CONFUSED, relation, pageSpaceId, page_number, page->dpg_sequence); } vdr_rel_chain_counter++; @@ -1612,7 +1633,7 @@ void Validation::walk_database() DPM_scan_pages(vdr_tdbb); WIN window(DB_PAGE_SPACE, -1); header_page* page = 0; - fetch_page(true, HEADER_PAGE, pag_header, &window, &page); + fetch_page(true, PageNumber(DB_PAGE_SPACE, HEADER_PAGE), pag_header, &window, &page); TraNumber next = vdr_max_transaction = Ods::getNT(page); if (vdr_flags & VDR_online) { @@ -1628,6 +1649,19 @@ void Validation::walk_database() walk_generators(); } + // Fill the relations cache with all known relations + // Without this we cant report about lost pointer pages + PreparedStatement::Builder sql; + SLONG rdbRelationID; + sql << "select" + << sql("rdb$relation_id", rdbRelationID) + << "from rdb$relations where (rdb$relation_type = 0) and (rdb$relation_id is not null)"; + AutoPreparedStatement ps(attachment->prepareStatement(vdr_tdbb, attachment->getSysTransaction(), sql)); + AutoResultSet rs(ps->executeQuery(vdr_tdbb, attachment->getSysTransaction())); + + while (rs->fetch(vdr_tdbb)) + MET_relation(vdr_tdbb, rdbRelationID); + vec* vector; for (USHORT i = 0; (vector = attachment->att_relations) && i < vector->count(); i++) { @@ -1662,7 +1696,7 @@ void Validation::walk_database() // We can't realiable track double allocated page's when validating online. // All we can check is that page is not double allocated at the same relation. if (vdr_flags & VDR_online) - vdr_page_bitmap->clear(); + vdr_page_bitmap[relation->getBasePages()->rel_pg_space_id]->clear(); // Should all array be cleared? string relName; relName.printf("Relation %d (%s)", relation->rel_id, relation->rel_name.c_str()); @@ -1699,11 +1733,12 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number, **************************************/ Database* dbb = vdr_tdbb->getDatabase(); - WIN window(DB_PAGE_SPACE, -1); + const USHORT pageSpaceId = relation->getBasePages()->rel_pg_space_id; + WIN window(pageSpaceId, -1); window.win_flags = WIN_garbage_collector; data_page* page = 0; - fetch_page(true, page_number, pag_data, &window, &page); + fetch_page(true, PageNumber(pageSpaceId, page_number), pag_data, &window, &page); #ifdef DEBUG_VAL_VERBOSE if (VAL_debug_level) @@ -1718,7 +1753,7 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number, if (page->dpg_relation != relation->rel_id || page->dpg_sequence != sequence) { release_page(&window); - return corrupt(VAL_DATA_PAGE_CONFUSED, relation, page_number, sequence); + return corrupt(VAL_DATA_PAGE_CONFUSED, relation, pageSpaceId, page_number, sequence); } pp_bits = 0; @@ -1764,7 +1799,7 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number, if ((UCHAR*) header < (UCHAR*) end || (UCHAR*) header + line->dpg_length > end_page) { release_page(&window); - return corrupt(VAL_DATA_PAGE_LINE_ERR, relation, page_number, + return corrupt(VAL_DATA_PAGE_LINE_ERR, relation, pageSpaceId, page_number, sequence, (ULONG) (line - page->dpg_rpt)); } if (header->rhd_flags & rhd_chain) @@ -1838,7 +1873,7 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number, if (primary_versions && (dp_flags & dpg_secondary)) { - corrupt(VAL_DATA_PAGE_SEC_PRI, relation, page_number, sequence); + corrupt(VAL_DATA_PAGE_SEC_PRI, relation, pageSpaceId, page_number, sequence); if (vdr_flags & VDR_update) { @@ -1894,7 +1929,7 @@ void Validation::walk_generators() #endif // It doesn't make a difference generator_page or pointer_page because it's not used. generator_page* page = NULL; - fetch_page(true, *ptr, pag_ids, &window, &page); + fetch_page(true, PageNumber(DB_PAGE_SPACE, *ptr), pag_ids, &window, &page); release_page(&window); } } @@ -1922,7 +1957,7 @@ void Validation::walk_header(ULONG page_num) #endif WIN window(DB_PAGE_SPACE, -1); header_page* page = 0; - fetch_page(true, page_num, pag_header, &window, &page); + fetch_page(true, PageNumber(DB_PAGE_SPACE, page_num), pag_header, &window, &page); page_num = page->hdr_next_page; release_page(&window); } @@ -1948,7 +1983,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ **************************************/ Database* dbb = vdr_tdbb->getDatabase(); - const ULONG page_number = root_page.irt_rpt[id].getRoot(); + const ULONG page_number = root_page.irt_rpt[id].getRootPage(); if (!page_number) { return rtn_ok; } @@ -1957,17 +1992,19 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ const bool descending = (root_page.irt_rpt[id].irt_flags & irt_descending); temporary_key nullKey, *null_key = 0; - if (unique) - { - const bool isExpression = root_page.irt_rpt[id].irt_flags & irt_expression; - if (isExpression) - root_page.irt_rpt[id].irt_flags &= ~irt_expression; - index_desc idx; - BTR_description(vdr_tdbb, relation, &root_page, &idx, id); - if (isExpression) - root_page.irt_rpt[id].irt_flags |= irt_expression; + // We need to have index description to get index page space + const bool isExpression = root_page.irt_rpt[id].irt_flags & irt_expression; + if (isExpression) + root_page.irt_rpt[id].irt_flags &= ~irt_expression; + + index_desc idx; + BTR_description(vdr_tdbb, relation, &root_page, &idx, id); + if (isExpression) + root_page.irt_rpt[id].irt_flags |= irt_expression; + if (unique) + { null_key = &nullKey; BTR_make_null_key(vdr_tdbb, &idx, null_key); } @@ -1990,11 +2027,11 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ while (next) { - WIN window(DB_PAGE_SPACE, -1); + WIN window(idx.idx_pg_space_id, -1); window.win_flags = WIN_garbage_collector; btree_page* page = 0; - fetch_page(true, next, pag_index, &window, &page); + fetch_page(true, PageNumber(idx.idx_pg_space_id, next), pag_index, &window, &page); // remember each page for circular reference detection visited_pages.set(next); @@ -2003,7 +2040,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ // (page->btr_header.pag_flags & BTR_FLAG_COPY_MASK) != (flags & BTR_FLAG_COPY_MASK)) //{ // corrupt(VAL_INDEX_PAGE_CORRUPT, relation, - // id + 1, next, page->btr_level, 0, __FILE__, __LINE__); + // id + 1, idx.idx_pg_space_id, next, page->btr_level, 0, __FILE__, __LINE__); //} if (level == 255) { @@ -2012,14 +2049,14 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ else if (level != page->btr_level) { corrupt(VAL_INDEX_PAGE_CORRUPT, relation, - id + 1, next, page->btr_level, 0, __FILE__, __LINE__); + id + 1, idx.idx_pg_space_id, next, page->btr_level, 0, __FILE__, __LINE__); } const bool leafPage = (page->btr_level == 0); if (page->btr_relation != relation->rel_id || page->btr_id != (UCHAR) (id % 256)) { - corrupt(VAL_INDEX_PAGE_CORRUPT, relation, id + 1, + corrupt(VAL_INDEX_PAGE_CORRUPT, relation, id + 1, idx.idx_pg_space_id, next, page->btr_level, 0, __FILE__, __LINE__); release_page(&window); return rtn_corrupt; @@ -2030,7 +2067,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ if (BTR_SIZE + page->btr_jump_size > page->btr_length) { corrupt(VAL_INDEX_PAGE_CORRUPT, relation, - id + 1, next, page->btr_level, (ULONG) (pointer - (UCHAR*) page), + id + 1, idx.idx_pg_space_id, next, page->btr_level, (ULONG) (pointer - (UCHAR*) page), __FILE__, __LINE__); } @@ -2047,7 +2084,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ (jumpNode.offset > page->btr_length)) { corrupt(VAL_INDEX_PAGE_CORRUPT, relation, - id + 1, next, page->btr_level, (ULONG) (pointer - (UCHAR*) page), + id + 1, idx.idx_pg_space_id, next, page->btr_level, (ULONG) (pointer - (UCHAR*) page), __FILE__, __LINE__); } else @@ -2057,7 +2094,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ if ((jumpNode.prefix + jumpNode.length) != checknode.prefix) { corrupt(VAL_INDEX_PAGE_CORRUPT, relation, - id + 1, next, page->btr_level, (ULONG) jumpNode.offset, + id + 1, idx.idx_pg_space_id, next, page->btr_level, (ULONG) jumpNode.offset, __FILE__, __LINE__); } @@ -2065,7 +2102,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ if (n == page->btr_jump_count && jumpNode.prefix) { corrupt(VAL_INDEX_PAGE_CORRUPT, relation, - id + 1, next, page->btr_level, (ULONG) jumpNode.offset, + id + 1, idx.idx_pg_space_id, next, page->btr_level, (ULONG) jumpNode.offset, __FILE__, __LINE__); } @@ -2073,7 +2110,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ if (n != page->btr_jump_count && jumpNode.prefix > jumpDataLen) { corrupt(VAL_INDEX_PAGE_CORRUPT, relation, - id + 1, next, page->btr_level, (ULONG) jumpNode.offset, + id + 1, idx.idx_pg_space_id, next, page->btr_level, (ULONG) jumpNode.offset, __FILE__, __LINE__); } @@ -2085,7 +2122,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ if (jumpersSize > page->btr_jump_size) { corrupt(VAL_INDEX_PAGE_CORRUPT, relation, - id + 1, next, page->btr_level, (ULONG) page->btr_jump_size + BTR_SIZE, + id + 1, idx.idx_pg_space_id, next, page->btr_level, (ULONG) page->btr_jump_size + BTR_SIZE, __FILE__, __LINE__); } @@ -2105,7 +2142,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ if (node.prefix > key.key_length) { corrupt(VAL_INDEX_PAGE_CORRUPT, relation, - id + 1, next, page->btr_level, node.nodePointer - (UCHAR*) page, __FILE__, __LINE__); + id + 1, idx.idx_pg_space_id, next, page->btr_level, node.nodePointer - (UCHAR*) page, __FILE__, __LINE__); release_page(&window); return rtn_corrupt; } @@ -2126,7 +2163,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ { duplicateNode = false; corrupt(VAL_INDEX_PAGE_CORRUPT, relation, - id + 1, next, page->btr_level, (ULONG) (q - (UCHAR*) page), + id + 1, idx.idx_pg_space_id, next, page->btr_level, (ULONG) (q - (UCHAR*) page), __FILE__, __LINE__); } else if (*p < *q) @@ -2148,7 +2185,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ { duplicateNode = false; corrupt(VAL_INDEX_PAGE_CORRUPT, relation, - id + 1, next, page->btr_level, (ULONG) (node.nodePointer - (UCHAR*) page), + id + 1, idx.idx_pg_space_id, next, page->btr_level, (ULONG) (node.nodePointer - (UCHAR*) page), __FILE__, __LINE__); } @@ -2172,7 +2209,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ { duplicateNode = false; corrupt(VAL_INDEX_PAGE_CORRUPT, relation, - id + 1, next, page->btr_level, (ULONG) (node.nodePointer - (UCHAR*) page), + id + 1, idx.idx_pg_space_id, next, page->btr_level, (ULONG) (node.nodePointer - (UCHAR*) page), __FILE__, __LINE__); } } @@ -2193,7 +2230,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ (node.recordNumber < lastNode.recordNumber)) { corrupt(VAL_INDEX_PAGE_CORRUPT, relation, - id + 1, next, page->btr_level, (ULONG) (node.nodePointer - (UCHAR*) page), + id + 1, idx.idx_pg_space_id, next, page->btr_level, (ULONG) (node.nodePointer - (UCHAR*) page), __FILE__, __LINE__); } } @@ -2232,11 +2269,11 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ // Note: mark == false for the fetch_page() call here // as we don't want to mark the page as visited yet - we'll // mark it when we visit it for real later on - WIN down_window(DB_PAGE_SPACE, -1); + WIN down_window(idx.idx_pg_space_id, -1); down_window.win_flags = WIN_garbage_collector; btree_page* down_page = 0; - fetch_page(false, down_number, pag_index, &down_window, &down_page); + fetch_page(false, PageNumber(idx.idx_pg_space_id, down_number), pag_index, &down_window, &down_page); const bool downLeafPage = (down_page->btr_level == 0); // make sure the initial key is greater than the pointer key @@ -2253,7 +2290,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ if (*p < *q) { corrupt(VAL_INDEX_PAGE_CORRUPT, relation, - id + 1, next, page->btr_level, (ULONG) (node.nodePointer - (UCHAR*) page), + id + 1, idx.idx_pg_space_id, next, page->btr_level, (ULONG) (node.nodePointer - (UCHAR*) page), __FILE__, __LINE__); } else if (*p > *q) @@ -2274,7 +2311,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ (downNode.recordNumber < down_record_number)) { corrupt(VAL_INDEX_PAGE_CORRUPT, relation, - id + 1, next, page->btr_level, (ULONG) (node.nodePointer - (UCHAR*) page), + id + 1, idx.idx_pg_space_id, next, page->btr_level, (ULONG) (node.nodePointer - (UCHAR*) page), __FILE__, __LINE__); } } @@ -2283,7 +2320,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ if (previous_number != down_page->btr_left_sibling) { corrupt(VAL_INDEX_BAD_LEFT_SIBLING, relation, - id + 1, next, page->btr_level, (ULONG) (node.nodePointer - (UCHAR*) page)); + id + 1, idx.idx_pg_space_id, next, page->btr_level, (ULONG) (node.nodePointer - (UCHAR*) page)); } downNode.readNode(pointer, leafPage); @@ -2293,11 +2330,11 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ (next_number != down_page->btr_sibling)) { corrupt(VAL_INDEX_MISSES_NODE, relation, - id + 1, next, page->btr_level, (ULONG) (node.nodePointer - (UCHAR*) page)); + id + 1, idx.idx_pg_space_id, next, page->btr_level, (ULONG) (node.nodePointer - (UCHAR*) page)); } if (downNode.isEndLevel && down_page->btr_sibling) { - corrupt(VAL_INDEX_ORPHAN_CHILD, relation, id + 1, next); + corrupt(VAL_INDEX_ORPHAN_CHILD, relation, id + 1, idx.idx_pg_space_id, next); } previous_number = down_number; @@ -2307,7 +2344,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ if (pointer != endPointer || page->btr_length > dbb->dbb_page_size) { - corrupt(VAL_INDEX_PAGE_CORRUPT, relation, id + 1, + corrupt(VAL_INDEX_PAGE_CORRUPT, relation, id + 1, idx.idx_pg_space_id, next, page->btr_level, (ULONG) (pointer - (UCHAR*) page), __FILE__, __LINE__); } @@ -2338,7 +2375,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_ // check for circular referenes if (next && visited_pages.test(next)) { - corrupt(VAL_INDEX_CYCLE, relation, id + 1, next); + corrupt(VAL_INDEX_CYCLE, relation, id + 1, idx.idx_pg_space_id, next); next = 0; } release_page(&window); @@ -2380,117 +2417,124 @@ void Validation::walk_pip() Database* dbb = vdr_tdbb->getDatabase(); PageManager& pageSpaceMgr = dbb->dbb_page_manager; - const PageSpace* pageSpace = pageSpaceMgr.findPageSpace(DB_PAGE_SPACE); - fb_assert(pageSpace); - page_inv_page* page = 0; + MET_scan_tablespaces(vdr_tdbb); - for (USHORT sequence = 0; true; sequence++) + for (USHORT pageSpaceId = DB_PAGE_SPACE; pageSpaceId < TRANS_PAGE_SPACE; pageSpaceId++) { - const ULONG page_number = - sequence ? sequence * pageSpaceMgr.pagesPerPIP - 1 : pageSpace->pipFirst; -#ifdef DEBUG_VAL_VERBOSE - if (VAL_debug_level) - fprintf(stdout, "walk_pip: page %d\n", page_number); -#endif - WIN window(DB_PAGE_SPACE, -1); - fetch_page(true, page_number, pag_pages, &window, &page); + const PageSpace* pageSpace = pageSpaceMgr.findPageSpace(pageSpaceId); + if (!pageSpace) + continue; - ULONG pipMin = MAX_ULONG; - ULONG pipExtent = MAX_ULONG; - ULONG pipUsed = 0; + page_inv_page* page = 0; - UCHAR* bytes = page->pip_bits; - const UCHAR* end = (UCHAR*) page + dbb->dbb_page_size; - for (; bytes < end; bytes++) + for (USHORT sequence = 0; true; sequence++) { - if (*bytes == 0) + const ULONG page_number = + sequence ? sequence * pageSpaceMgr.pagesPerPIP - 1 : pageSpace->pipFirst; + #ifdef DEBUG_VAL_VERBOSE + if (VAL_debug_level) + fprintf(stdout, "walk_pip: page %d\n", page_number); + #endif + WIN window(pageSpaceId, -1); + fetch_page(true, PageNumber(pageSpaceId, page_number), pag_pages, &window, &page); + + ULONG pipMin = MAX_ULONG; + ULONG pipExtent = MAX_ULONG; + ULONG pipUsed = 0; + + UCHAR* bytes = page->pip_bits; + const UCHAR* end = (UCHAR*) page + dbb->dbb_page_size; + for (; bytes < end; bytes++) { - pipUsed = (bytes - page->pip_bits + 1) * 8; - continue; - } + if (*bytes == 0) + { + pipUsed = (bytes - page->pip_bits + 1) * 8; + continue; + } - if (*bytes == 0xFF && pipExtent == MAX_ULONG) - pipExtent = (bytes - page->pip_bits) * 8; + if (*bytes == 0xFF && pipExtent == MAX_ULONG) + pipExtent = (bytes - page->pip_bits) * 8; - if (pipMin == MAX_ULONG) - { - UCHAR mask = 1; - for (int i = 0; i < 8; i++, mask <<= 1) + if (pipMin == MAX_ULONG) { - if (*bytes & mask) + UCHAR mask = 1; + for (int i = 0; i < 8; i++, mask <<= 1) { - pipMin = (bytes - page->pip_bits) * 8 + i; - break; + if (*bytes & mask) + { + pipMin = (bytes - page->pip_bits) * 8 + i; + break; + } } } - } - if (*bytes != 0xFF) - { - UCHAR mask = 0x80; - for (int i = 8; i > 0; i--, mask >>= 1) + if (*bytes != 0xFF) { - if ((*bytes & mask) == 0) + UCHAR mask = 0x80; + for (int i = 8; i > 0; i--, mask >>= 1) { - pipUsed = (bytes - page->pip_bits) * 8 + i; - break; + if ((*bytes & mask) == 0) + { + pipUsed = (bytes - page->pip_bits) * 8 + i; + break; + } } } } - } - if (pipMin == MAX_ULONG) { - pipMin = pageSpaceMgr.pagesPerPIP; - } - - if (pipExtent == MAX_ULONG) { - pipExtent = pageSpaceMgr.pagesPerPIP; - } - - bool fixme = false; - if (pipMin < page->pip_min) - { - corrupt(VAL_PIP_WRONG_MIN, NULL, page_number, sequence, page->pip_min, pipMin); - fixme = (vdr_flags & VDR_update); - } - - if (pipExtent < page->pip_extent) - { - corrupt(VAL_PIP_WRONG_EXTENT, NULL, page_number, sequence, page->pip_extent, pipExtent); - fixme = (vdr_flags & VDR_update); - } + if (pipMin == MAX_ULONG) { + pipMin = pageSpaceMgr.pagesPerPIP; + } - if (pipUsed > page->pip_used) - { - corrupt(VAL_PIP_WRONG_USED, NULL, page_number, sequence, page->pip_used, pipUsed); - fixme = (vdr_flags & VDR_update); - } + if (pipExtent == MAX_ULONG) { + pipExtent = pageSpaceMgr.pagesPerPIP; + } - if (fixme) - { - CCH_MARK(vdr_tdbb, &window); + bool fixme = false; if (pipMin < page->pip_min) { - page->pip_min = pipMin; - vdr_fixed++; + corrupt(VAL_PIP_WRONG_MIN, NULL, pageSpaceId, page_number, sequence, page->pip_min, pipMin); + fixme = (vdr_flags & VDR_update); } + if (pipExtent < page->pip_extent) { - page->pip_extent = pipExtent; - vdr_fixed++; + corrupt(VAL_PIP_WRONG_EXTENT, NULL, pageSpaceId, page_number, sequence, page->pip_extent, pipExtent); + fixme = (vdr_flags & VDR_update); } + if (pipUsed > page->pip_used) { - page->pip_used = pipUsed; - vdr_fixed++; + corrupt(VAL_PIP_WRONG_USED, NULL, pageSpaceId, page_number, sequence, page->pip_used, pipUsed); + fixme = (vdr_flags & VDR_update); } - } - const UCHAR byte = page->pip_bits[pageSpaceMgr.bytesBitPIP - 1]; - release_page(&window); - if (byte & 0x80) - break; + if (fixme) + { + CCH_MARK(vdr_tdbb, &window); + if (pipMin < page->pip_min) + { + page->pip_min = pipMin; + vdr_fixed++; + } + if (pipExtent < page->pip_extent) + { + page->pip_extent = pipExtent; + vdr_fixed++; + } + if (pipUsed > page->pip_used) + { + page->pip_used = pipUsed; + vdr_fixed++; + } + } + + const UCHAR byte = page->pip_bits[pageSpaceMgr.bytesBitPIP - 1]; + release_page(&window); + if (byte & 0x80) + break; + } } } @@ -2514,10 +2558,11 @@ Validation::RTN Validation::walk_pointer_page(jrd_rel* relation, ULONG sequence) return corrupt(VAL_P_PAGE_LOST, relation, sequence); pointer_page* page = 0; - WIN window(DB_PAGE_SPACE, -1); + const USHORT pageSpaceId = relation->getBasePages()->rel_pg_space_id; + WIN window(pageSpaceId, -1); window.win_flags = WIN_garbage_collector; - fetch_page(true, (*vector)[sequence], pag_pointer, &window, &page); + fetch_page(true, PageNumber(pageSpaceId, (*vector)[sequence]), pag_pointer, &window, &page); #ifdef DEBUG_VAL_VERBOSE if (VAL_debug_level) @@ -2532,7 +2577,7 @@ Validation::RTN Validation::walk_pointer_page(jrd_rel* relation, ULONG sequence) if (page->ppg_relation != relation->rel_id || page->ppg_sequence != sequence) { release_page(&window); - return corrupt(VAL_P_PAGE_INCONSISTENT, relation, (*vector)[sequence], sequence); + return corrupt(VAL_P_PAGE_INCONSISTENT, relation, pageSpaceId, (*vector)[sequence], sequence); } // Walk the data pages (someday we may optionally walk pages with "large objects" @@ -2570,7 +2615,7 @@ Validation::RTN Validation::walk_pointer_page(jrd_rel* relation, ULONG sequence) explain_pp_bits(pp_bits, s_pp); explain_pp_bits(new_pp_bits, s_dp); - corrupt(VAL_P_PAGE_WRONG_BITS, relation, + corrupt(VAL_P_PAGE_WRONG_BITS, relation, pageSpaceId, page->ppg_header.pag_pageno, sequence, pp_bits, s_pp.c_str(), *pages, seq, new_pp_bits, s_dp.c_str()); @@ -2609,7 +2654,7 @@ Validation::RTN Validation::walk_pointer_page(jrd_rel* relation, ULONG sequence) // relation could be extended before we acquired its lock in PR mode // let's re-read pointer pages and check again - DPM_scan_pages(vdr_tdbb); + DPM_scan_pages(vdr_tdbb, pag_pointer, relation->rel_id); vector = relation->getBasePages()->rel_pages; @@ -2618,7 +2663,7 @@ Validation::RTN Validation::walk_pointer_page(jrd_rel* relation, ULONG sequence) return corrupt(VAL_P_PAGE_LOST, relation, sequence); } - fetch_page(false, (*vector)[sequence], pag_pointer, &window, &page); + fetch_page(false, PageNumber(pageSpaceId, (*vector)[sequence]), pag_pointer, &window, &page); ++sequence; const bool error = (sequence >= vector->count()) || @@ -2630,7 +2675,7 @@ Validation::RTN Validation::walk_pointer_page(jrd_rel* relation, ULONG sequence) return rtn_ok; } - return corrupt(VAL_P_PAGE_INCONSISTENT, relation, page->ppg_next, sequence); + return corrupt(VAL_P_PAGE_INCONSISTENT, relation, pageSpaceId, page->ppg_next, sequence); } release_page(&window); @@ -2740,10 +2785,11 @@ Validation::RTN Validation::walk_record(jrd_rel* relation, const rhd* header, US data_page* page = 0; while (flags & rhd_incomplete) { - WIN window(DB_PAGE_SPACE, -1); + const USHORT pageSpaceId = relation->getBasePages()->rel_pg_space_id; + WIN window(pageSpaceId, -1); window.win_flags = WIN_garbage_collector; - fetch_page(true, page_number, pag_data, &window, &page); + fetch_page(true, PageNumber(pageSpaceId, page_number), pag_data, &window, &page); const data_page::dpg_repeat* line = &page->dpg_rpt[line_number]; if (page->dpg_relation != relation->rel_id || line_number >= page->dpg_count || !(length = line->dpg_length)) @@ -2841,7 +2887,7 @@ void restoreFlags(UCHAR* byte, UCHAR flags, bool empty) *byte &= ~bit; } -void Validation::checkDPinPP(jrd_rel* relation, SLONG page_number) +void Validation::checkDPinPP(jrd_rel* relation, ULONG page_number) { /************************************** * @@ -2851,9 +2897,11 @@ void Validation::checkDPinPP(jrd_rel* relation, SLONG page_number) * Early in walk_chain we observed that this page in related to the relation so we skip such kind of check here. **************************************/ - WIN window(DB_PAGE_SPACE, page_number); + const USHORT pageSpaceId = relation->getBasePages()->rel_pg_space_id; + + WIN window(pageSpaceId, page_number); data_page* dpage; - fetch_page(false, page_number, pag_data, &window, &dpage); + fetch_page(false, window.win_page, pag_data, &window, &dpage); const SLONG sequence = dpage->dpg_sequence; const bool dpEmpty = (dpage->dpg_count == 0); release_page(&window); @@ -2867,10 +2915,11 @@ void Validation::checkDPinPP(jrd_rel* relation, SLONG page_number) pointer_page* ppage = 0; if (pp_sequence < vector->count()) { - fetch_page(false, (*vector)[pp_sequence], pag_pointer, &window, &ppage); + fetch_page(false, PageNumber(pageSpaceId, (*vector)[pp_sequence]), pag_pointer, &window, &ppage); if (slot >= ppage->ppg_count) { - corrupt(VAL_DATA_PAGE_SLOT_NOT_FOUND, relation, page_number, window.win_page.getPageNum(), slot); + corrupt(VAL_DATA_PAGE_SLOT_NOT_FOUND, relation, pageSpaceId, page_number, + window.win_page.getPageNum(), slot); if (vdr_flags & VDR_update && slot < dbb->dbb_dp_per_pp) { CCH_MARK(vdr_tdbb, &window); @@ -2893,7 +2942,8 @@ void Validation::checkDPinPP(jrd_rel* relation, SLONG page_number) } else if (page_number != ppage->ppg_page[slot]) { - corrupt(VAL_DATA_PAGE_SLOT_BAD_VAL, relation, page_number, window.win_page.getPageNum(), slot, ppage->ppg_page[slot]); + corrupt(VAL_DATA_PAGE_SLOT_BAD_VAL, relation, pageSpaceId, page_number, + window.win_page.getPageNum(), slot, ppage->ppg_page[slot]); if (vdr_flags & VDR_update && !ppage->ppg_page[slot]) { CCH_MARK(vdr_tdbb, &window); @@ -2907,12 +2957,12 @@ void Validation::checkDPinPP(jrd_rel* relation, SLONG page_number) } } else - corrupt(VAL_DATA_PAGE_HASNO_PP, relation, page_number, dpage->dpg_sequence); + corrupt(VAL_DATA_PAGE_HASNO_PP, relation, pageSpaceId, page_number, dpage->dpg_sequence); release_page(&window); } -void Validation::checkDPinPIP(jrd_rel* relation, SLONG page_number) +void Validation::checkDPinPIP(jrd_rel* relation, ULONG page_number) { /************************************** * @@ -2923,20 +2973,22 @@ void Validation::checkDPinPIP(jrd_rel* relation, SLONG page_number) Database* dbb = vdr_tdbb->getDatabase(); + const USHORT pageSpaceId = relation->getBasePages()->rel_pg_space_id; PageManager& pageMgr = dbb->dbb_page_manager; - PageSpace* pageSpace = pageMgr.findPageSpace(DB_PAGE_SPACE); + PageSpace* pageSpace = pageMgr.findPageSpace(pageSpaceId); fb_assert(pageSpace); const SLONG sequence = page_number / pageMgr.pagesPerPIP; const SLONG relative_bit = page_number % pageMgr.pagesPerPIP; - WIN pip_window(DB_PAGE_SPACE, (sequence == 0) ? pageSpace->pipFirst : sequence * pageMgr.pagesPerPIP - 1); + WIN pip_window(pageSpaceId, (sequence == 0) ? pageSpace->pipFirst : sequence * pageMgr.pagesPerPIP - 1); page_inv_page* pages; - fetch_page(false, pip_window.win_page.getPageNum(), pag_pages, &pip_window, &pages); + fetch_page(false, pip_window.win_page, pag_pages, &pip_window, &pages); if (pages->pip_bits[relative_bit >> 3] & (1 << (relative_bit & 7))) { - corrupt(VAL_DATA_PAGE_ISNT_IN_PIP, relation, page_number, pip_window.win_page.getPageNum(), relative_bit); + corrupt(VAL_DATA_PAGE_ISNT_IN_PIP, relation, pageSpaceId, page_number, + pip_window.win_page.getPageNum(), relative_bit); if (vdr_flags & VDR_update) { CCH_MARK(vdr_tdbb, &pip_window); @@ -3009,11 +3061,65 @@ Validation::RTN Validation::walk_relation(jrd_rel* relation) WIN window(DB_PAGE_SPACE, -1); header_page* page = NULL; - fetch_page(false, (SLONG) HEADER_PAGE, pag_header, &window, &page); + fetch_page(false, PageNumber(DB_PAGE_SPACE, HEADER_PAGE), pag_header, &window, &page); vdr_max_transaction = Ods::getNT(page); release_page(&window); } + // Check if the first pointer page is lost and try to restore it if VDR_update is set + // We use POINTER_PAGE and ROOT_PAGE of RDB$RELATIONS for this purpose + if ((vdr_flags & VDR_update) && !relation->getBasePages()->rel_instance_id && + (!relation->getBasePages()->rel_pages || !relation->getBasePages()->rel_pages->count()) + ) + { + Jrd::Attachment* attachment = vdr_tdbb->getAttachment(); + + // Get POINTER_PAGE and ROOT_PAGE from RDB$RELATIONS + PreparedStatement::Builder sql; + SLONG pointerPage; // Must be ULONG + SLONG rootPage; // Must be ULONG + SLONG relId; + sql << "select" + << sql("rdb$pointer_page, " , pointerPage) + << sql("rdb$root_page", rootPage) + << "from rdb$relations where rdb$relation_id = " << relId; + AutoPreparedStatement ps(attachment->prepareStatement(vdr_tdbb, attachment->getSysTransaction(), sql)); + relId = relation->rel_id; + AutoResultSet rs(ps->executeQuery(vdr_tdbb, attachment->getSysTransaction())); + + if (rs->fetch(vdr_tdbb)) + { + // Try to restore pages and check every page that it is a pointer page and belongs to the relation + const USHORT pageSpaceId = relation->getBasePages()->rel_pg_space_id; + ULONG sequence = 0; + while (pointerPage) + { + pointer_page* page = NULL; + WIN window(pageSpaceId, -1); + fetch_page(false, PageNumber(pageSpaceId, pointerPage), pag_pointer, &window, &page); + if (page->ppg_relation != relation->rel_id) + break; + const ULONG next_ppg = page->ppg_next; + release_page(&window); + + DPM_pages(vdr_tdbb, relation->rel_id, pag_pointer, sequence, pointerPage); + pointerPage = next_ppg; + sequence++; + } + index_root_page* root = NULL; + WIN window(pageSpaceId, -1); + fetch_page(false, PageNumber(pageSpaceId, rootPage), pag_root, &window, &root); + const bool correctRoot = (root->irt_relation == relation->rel_id); + release_page(&window); + if (correctRoot) + DPM_pages(vdr_tdbb, relation->rel_id, pag_root, 0, rootPage); + + DPM_scan_pages(vdr_tdbb, pag_pointer, relation->rel_id); + DPM_scan_pages(vdr_tdbb, pag_root, relation->rel_id); + } + } + + // Walk pointer and selected data pages associated with relation vdr_rel_backversion_counter = 0; @@ -3133,20 +3239,21 @@ Validation::RTN Validation::walk_root(jrd_rel* relation) if (!relPages->rel_index_root) return corrupt(VAL_INDEX_ROOT_MISSING, relation); + const USHORT pageSpaceId = relPages->rel_pg_space_id; index_root_page* page = 0; - WIN window(DB_PAGE_SPACE, -1); - fetch_page(true, relPages->rel_index_root, pag_root, &window, &page); + WIN window(pageSpaceId, -1); + fetch_page(true, PageNumber(pageSpaceId, relPages->rel_index_root), pag_root, &window, &page); for (USHORT i = 0; i < page->irt_count; i++) { - if (page->irt_rpt[i].getRoot() == 0) + if (page->irt_rpt[i].getRootPage() == 0) continue; MetaName index; release_page(&window); MET_lookup_index(vdr_tdbb, index, relation->rel_name, i + 1); - fetch_page(false, relPages->rel_index_root, pag_root, &window, &page); + fetch_page(false, PageNumber(pageSpaceId, relPages->rel_index_root), pag_root, &window, &page); if (vdr_idx_incl) { @@ -3204,7 +3311,7 @@ Validation::RTN Validation::walk_tip(TraNumber transaction) } WIN window(DB_PAGE_SPACE, -1); - fetch_page(true, (*vector)[sequence], pag_transactions, &window, &page); + fetch_page(true, PageNumber(DB_PAGE_SPACE, (*vector)[sequence]), pag_transactions, &window, &page); #ifdef DEBUG_VAL_VERBOSE if (VAL_debug_level) @@ -3237,31 +3344,37 @@ Validation::RTN Validation::walk_scns() Database* dbb = vdr_tdbb->getDatabase(); PageManager& pageMgr = dbb->dbb_page_manager; - PageSpace* pageSpace = pageMgr.findPageSpace(DB_PAGE_SPACE); - - const ULONG lastPage = pageSpace->lastUsedPage(); - const ULONG cntSCNs = lastPage / pageMgr.pagesPerSCN + 1; - for (ULONG sequence = 0; sequence < cntSCNs; sequence++) + for (USHORT pageSpaceId = DB_PAGE_SPACE; pageSpaceId < TRANS_PAGE_SPACE; pageSpaceId++) { - const ULONG scnPage = pageSpace->getSCNPageNum(sequence); - WIN scnWindow(pageSpace->pageSpaceID, scnPage); - scns_page* scns = NULL; - fetch_page(true, scnPage, pag_scns, &scnWindow, &scns); + PageSpace* pageSpace = pageMgr.findPageSpace(pageSpaceId); + if (!pageSpace) + continue; + + const ULONG lastPage = pageSpace->lastUsedPage(); + const ULONG cntSCNs = lastPage / pageMgr.pagesPerSCN + 1; - if (scns->scn_sequence != sequence) + for (ULONG sequence = 0; sequence < cntSCNs; sequence++) { - corrupt(VAL_SCNS_PAGE_INCONSISTENT, 0, scnPage, sequence); + const ULONG scnPage = pageSpace->getSCNPageNum(sequence); + WIN scnWindow(pageSpace->pageSpaceID, scnPage); + scns_page* scns = NULL; + fetch_page(true, PageNumber(pageSpaceId, scnPage), pag_scns, &scnWindow, &scns); - if (vdr_flags & VDR_update) + if (scns->scn_sequence != sequence) { - CCH_MARK(vdr_tdbb, &scnWindow); - scns->scn_sequence = sequence; - vdr_fixed++; + corrupt(VAL_SCNS_PAGE_INCONSISTENT, 0, pageSpaceId, scnPage, sequence); + + if (vdr_flags & VDR_update) + { + CCH_MARK(vdr_tdbb, &scnWindow); + scns->scn_sequence = sequence; + vdr_fixed++; + } } - } - release_page(&scnWindow); + release_page(&scnWindow); + } } return rtn_ok; diff --git a/src/jrd/validation.h b/src/jrd/validation.h index a6aa2c5279e..449b6a8ec17 100644 --- a/src/jrd/validation.h +++ b/src/jrd/validation.h @@ -122,7 +122,7 @@ class Validation VAL_DATA_PAGE_HASNO_PP = 38, VAL_DATA_PAGE_SEC_PRI = 39, - VAL_MAX_ERROR = 40 + VAL_MAX_ERROR }; struct MSG_ENTRY @@ -135,19 +135,23 @@ class Validation static const MSG_ENTRY vdr_msg_table[VAL_MAX_ERROR]; thread_db* vdr_tdbb; - ULONG vdr_max_page; + ULONG vdr_max_page[TRANS_PAGE_SPACE]; // Keep max page in every available tablespace USHORT vdr_flags; int vdr_errors; int vdr_warns; int vdr_fixed; TraNumber vdr_max_transaction; + + // Note vdr_backversion_pages and vdr_chain_pages are reset check every relation + // so it's not necessary to keep page space but we can know it from relation context FB_UINT64 vdr_rel_backversion_counter; // Counts slots w/rhd_chain PageBitmap* vdr_backversion_pages; // 1 bit per visited table page FB_UINT64 vdr_rel_chain_counter; // Counts chains w/rdr_chain PageBitmap* vdr_chain_pages; // 1 bit per visited record chain page + RecordBitmap* vdr_rel_records; // 1 bit per valid record RecordBitmap* vdr_idx_records; // 1 bit per index item - PageBitmap* vdr_page_bitmap; + PageBitmap* vdr_page_bitmap[TRANS_PAGE_SPACE]; // fetched pages in every tablespace ULONG vdr_err_counts[VAL_MAX_ERROR]; Firebird::UtilSvc* vdr_service; @@ -156,8 +160,8 @@ class Validation Firebird::AutoPtr vdr_idx_incl; Firebird::AutoPtr vdr_idx_excl; int vdr_lock_tout; - void checkDPinPP(jrd_rel *relation, SLONG page_number); - void checkDPinPIP(jrd_rel *relation, SLONG page_number); + void checkDPinPP(jrd_rel *relation, ULONG page_number); + void checkDPinPIP(jrd_rel *relation, ULONG page_number); public: explicit Validation(thread_db*, Firebird::UtilSvc* uSvc = NULL); @@ -174,23 +178,23 @@ class Validation BufferDesc* bdb; int count; - static const ULONG generate(const UsedBdb& p) + static const PageNumber generate(const UsedBdb& p) { - return p.bdb ? p.bdb->bdb_page.getPageNum() : 0; + return p.bdb ? p.bdb->bdb_page : PageNumber(0, 0); } }; typedef Firebird::SortedArray< UsedBdb, Firebird::EmptyStorage, - ULONG, + PageNumber, UsedBdb> UsedBdbs; UsedBdbs vdr_used_bdbs; void cleanup(); RTN corrupt(int, const jrd_rel*, ...); - FETCH_CODE fetch_page(bool mark, ULONG, USHORT, WIN*, void*); + FETCH_CODE fetch_page(bool mark, PageNumber, USHORT, WIN*, void*); void release_page(WIN*); void garbage_collect(); diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index 46d5de6bfbd..5870e0d6808 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -84,6 +84,7 @@ #include "../jrd/tpc_proto.h" #include "../jrd/tra_proto.h" #include "../jrd/vio_proto.h" +#include "../jrd/os/pio_proto.h" #include "../jrd/dyn_ut_proto.h" #include "../jrd/Function.h" #include "../common/StatusArg.h" @@ -169,7 +170,7 @@ static void protect_system_table_delupd(thread_db* tdbb, const jrd_rel* relation static void purge(thread_db*, record_param*); static void replace_record(thread_db*, record_param*, PageStack*, const jrd_tra*); static void refresh_fk_fields(thread_db*, Record*, record_param*, record_param*); -static SSHORT set_metadata_id(thread_db*, Record*, USHORT, drq_type_t, const char*); +static SSHORT set_metadata_id(thread_db*, Record*, USHORT, drq_type_t, const char*, SLONG shift = 0); static void set_nbackup_id(thread_db*, Record*, USHORT, drq_type_t, const char*); static void set_owner_name(thread_db*, Record*, USHORT); static bool set_security_class(thread_db*, Record*, USHORT); @@ -1858,6 +1859,15 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) DFW_post_work(transaction, dfw_grant, &desc, id); break; + case rel_tablespaces: + { + protect_system_table_delupd(tdbb, relation, "DELETE"); + if (EVL_field(0, rpb->rpb_record, f_ts_name, &desc)) + SCL_check_tablespace(tdbb, &desc, SCL_drop); + break; + } + + default: // Shut up compiler warnings break; } @@ -3072,15 +3082,24 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j { EVL_field(0, new_rpb->rpb_record, f_idx_name, &desc1); - if (EVL_field(0, new_rpb->rpb_record, f_idx_exp_blr, &desc2)) + if (!dfw_should_know(tdbb, org_rpb, new_rpb, f_idx_ts_name, true)) { - DFW_post_work(transaction, dfw_create_expression_index, - &desc1, tdbb->getDatabase()->dbb_max_idx); + // Only tablespace name was changed. Move index data by pages + DFW_post_work(transaction, dfw_move_index, &desc1, + tdbb->getDatabase()->dbb_max_idx); } else { - DFW_post_work(transaction, dfw_create_index, &desc1, - tdbb->getDatabase()->dbb_max_idx); + if (EVL_field(0, new_rpb->rpb_record, f_idx_exp_blr, &desc2)) + { + DFW_post_work(transaction, dfw_create_expression_index, + &desc1, tdbb->getDatabase()->dbb_max_idx); + } + else + { + DFW_post_work(transaction, dfw_create_index, &desc1, + tdbb->getDatabase()->dbb_max_idx); + } } } break; @@ -3442,7 +3461,6 @@ bool VIO_refetch_record(thread_db* tdbb, record_param* rpb, jrd_tra* transaction return true; } - void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) { /************************************** @@ -3785,6 +3803,31 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) f_backup_id, drq_g_nxt_nbakhist_id, "RDB$BACKUP_HISTORY"); break; + case rel_tablespaces: + { + protect_system_table_insert(tdbb, request, relation); + EVL_field(0, rpb->rpb_record, f_ts_name, &desc); + EVL_field(0, rpb->rpb_record, f_ts_file, &desc2); + + // File with tablespace should not exist. Check it in DFW is silent and cause to + // clean up of existing files at phase 0. Early checking preserve existing files. + const PathName fileName = MOV_make_string2(tdbb, &desc2, ttype_metadata).ToPathName(); + if (PIO_file_exists(fileName)) + { + string tableSpace = MOV_make_string2(tdbb, &desc, ttype_metadata); + tableSpace.trim(); + ERR_post(Arg::Gds(isc_ts_file_exists) << Arg::Str(tableSpace) << Arg::Str(fileName)); + } + + object_id = set_metadata_id(tdbb, rpb->rpb_record, + f_ts_id, drq_g_nxt_ts_id, "RDB$TABLESPACES", 1); + DFW_post_work(transaction, dfw_create_tablespace, &desc, object_id); + set_owner_name(tdbb, rpb->rpb_record, f_ts_owner); + if (set_security_class(tdbb, rpb->rpb_record, f_ts_class)) + DFW_post_work(transaction, dfw_grant, &desc, obj_tablespace); + break; + } + default: // Shut up compiler warnings break; } @@ -6111,7 +6154,7 @@ static void refresh_fk_fields(thread_db* tdbb, Record* old_rec, record_param* cu static SSHORT set_metadata_id(thread_db* tdbb, Record* record, USHORT field_id, drq_type_t dyn_id, - const char* name) + const char* name, SLONG shift) { /************************************** * @@ -6129,7 +6172,7 @@ static SSHORT set_metadata_id(thread_db* tdbb, Record* record, USHORT field_id, if (EVL_field(0, record, field_id, &desc1)) return MOV_get_long(tdbb, &desc1, 0); - SSHORT value = (SSHORT) DYN_UTIL_gen_unique_id(tdbb, dyn_id, name); + SSHORT value = (SSHORT) DYN_UTIL_gen_unique_id(tdbb, dyn_id, name) + shift; dsc desc2; desc2.makeShort(0, &value); MOV_move(tdbb, &desc2, &desc1); diff --git a/src/msgs/facilities2.sql b/src/msgs/facilities2.sql index 33020962fdf..7a9dd638362 100644 --- a/src/msgs/facilities2.sql +++ b/src/msgs/facilities2.sql @@ -1,19 +1,19 @@ /* MAX_NUMBER is the next number to be used, always one more than the highest message number. */ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?); -- -('2020-03-04 16:39:50', 'JRD', 0, 949) +('2021-01-09 12:00:00', 'JRD', 0, 951) ('2015-03-17 18:33:00', 'QLI', 1, 533) ('2018-03-17 12:00:00', 'GFIX', 3, 136) ('1996-11-07 13:39:40', 'GPRE', 4, 1) ('2017-02-05 20:37:00', 'DSQL', 7, 41) -('2018-06-22 11:46:00', 'DYN', 8, 309) +('2021-01-09 12:00:00', 'DYN', 8, 312) ('1996-11-07 13:39:40', 'INSTALL', 10, 1) ('1996-11-07 13:38:41', 'TEST', 11, 4) -('2019-12-27 20:10:00', 'GBAK', 12, 396) -('2019-04-13 21:10:00', 'SQLERR', 13, 1047) +('2021-01-09 12:00:00', 'GBAK', 12, 403) +('2021-01-09 12:00:00', 'SQLERR', 13, 1052) ('1996-11-07 13:38:42', 'SQLWARN', 14, 613) ('2018-02-27 14:50:31', 'JRD_BUGCHK', 15, 308) -('2016-05-26 13:53:45', 'ISQL', 17, 197) +('2021-01-09 12:00:00', 'ISQL', 17, 200) ('2010-07-10 10:50:30', 'GSEC', 18, 105) ('2019-10-19 12:52:29', 'GSTAT', 21, 63) ('2019-12-10 17:55:05', 'FBSVCMGR', 22, 61) diff --git a/src/msgs/messages2.sql b/src/msgs/messages2.sql index 493f6c54540..c3d4e34144b 100644 --- a/src/msgs/messages2.sql +++ b/src/msgs/messages2.sql @@ -1056,6 +1056,8 @@ Data source : @4', NULL, NULL) ('truncate_warn', NULL, 'cvt.cpp', NULL, 0, 946, NULL, 'String truncated warning due to the following reason', NULL, NULL); ('truncate_monitor', NULL, 'Monitoring.cpp', NULL, 0, 947, NULL, 'Monitoring data does not fit into the field', NULL, NULL); ('truncate_context', NULL, 'SysFunction.cpp', NULL, 0, 948, NULL, 'Engine data does not fit into return value of system function', NULL, NULL); +('ts_file_exists', NULL, NULL, NULL, 0, 949, NULL, 'Tablespace "@1" creation error. File "@2" exists.', NULL, NULL); --//TODO: fix error refs +('tablespace_name', 'handleDependencies', 'TablespaceNodes.epp', NULL, 0, 950, NULL, 'TABLESPACE @1', NULL, NULL); --//TODO: fix error refs -- QLI (NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL); (NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL); @@ -2151,6 +2153,8 @@ COMMIT WORK; ('dyn_exc_not_exist', 'GrantRevokeNode::grantRevoke', 'DdlNodes.epp', NULL, 8, 307, NULL, 'Exception @1 does not exist', NULL, NULL); ('dyn_gen_not_exist', 'GrantRevokeNode::grantRevoke', 'DdlNodes.epp', NULL, 8, 308, NULL, 'Generator/Sequence @1 does not exist', NULL, NULL); ('dyn_fld_not_exist', 'GrantRevokeNode::grantRevoke', 'DdlNodes.epp', NULL, 8, 309, NULL, 'Field @1 of table @2 does not exist', NULL, NULL); +('dyn_ts_not_found', NULL, 'DdlNodes.epp/TablespaceNodes.epp', NULL, 8, 310, NULL, 'Tablespace @1 not found', NULL, NULL); +('dyn_cant_alter_ts', NULL, 'DdlNodes.epp', NULL, 8, 311, NULL, 'Cannot alter tablespace for temporary table @1', NULL, NULL); COMMIT WORK; -- TEST (NULL, 'main', 'test.c', NULL, 11, 0, NULL, 'This is a modified text message', NULL, NULL); @@ -2563,6 +2567,13 @@ ERROR: Backup incomplete', NULL, NULL); (NULL, 'get_db_creators', 'restore.epp', NULL, 12, 393, NULL, ' restoring database create grant for @1', NULL, NULL); (NULL, 'get_db_creators', 'restore.epp', NULL, 12, 394, NULL, 'restoring database create grants', NULL, NULL); (NULL, 'get_db_creators', 'restore.epp', NULL, 12, 395, NULL, 'database create grant', NULL, NULL); +(NULL, 'BACKUP_backup', 'backup.epp', NULL, 12, 396, NULL, 'writing tablespaces', NULL, NULL); +(NULL, 'write_tablespaces', 'backup.epp', NULL, 12, 397, NULL, 'writing tablespace @1', NULL, NULL); +(NULL, 'get_tablespace', 'restore.epp', NULL, 12, 398, NULL, 'restoring tablespace @1', NULL, NULL); +(NULL, 'get_tablespace', 'restore.epp', NULL, 12, 399, NULL, 'tablespace', NULL, NULL); +(NULL, 'burp_usage', 'burp.c', NULL, 12, 400, NULL, ' @1TABLESPACE_MAP(PING_FILE) mapping file for tablespaces', NULL, NULL); +(NULL, 'main()', 'burp.c', NULL, 12, 401, NULL, 'tablespace mapping file parameter missing', NULL, NULL); +(NULL, NULL, 'burp.c', NULL, 12, 402, NULL, 'cannot open mapping file "@1"', NULL, NULL); -- SQLERR (NULL, NULL, NULL, NULL, 13, 1, NULL, 'Firebird error', NULL, NULL); (NULL, NULL, NULL, NULL, 13, 74, NULL, 'Rollback not performed', NULL, NULL); @@ -2853,6 +2864,11 @@ ERROR: Backup incomplete', NULL, NULL); ('dsql_string_char_length', NULL, 'Parser.cpp', NULL, 13, 1044, NULL, 'String literal with @1 characters exceeds the maximum length of @2 characters for the @3 character set', NULL, NULL); ('dsql_max_nesting', NULL, 'StmtNodes.cpp', NULL, 13, 1045, NULL, 'Too many BEGIN...END nesting. Maximum level is @1', NULL, NULL); ('dsql_recreate_user_failed', 'getMainErrorCode', 'DdlNodes.h', NULL, 13, 1046, NULL, 'RECREATE USER @1 failed', NULL, NULL); +('dsql_create_ts_failed', 'getMainErrorCode', 'TablespaceNodes.h', NULL, 13, 1047, NULL, 'CREATE TABLESPACE @1 failed', NULL, NULL); +('dsql_alter_ts_failed', 'getMainErrorCode', 'TablespaceNodes.h', NULL, 13, 1048, NULL, 'ALTER TABLESPACE @1 failed', NULL, NULL); +('dsql_create_alter_ts_failed', 'getMainErrorCode', 'TablespaceNodes.h', NULL, 13, 1049, NULL, 'CREATE OR ALTER TABLESPACE @1 failed', NULL, NULL); +('dsql_drop_ts_failed', 'getMainErrorCode', 'TablespaceNodes.h', NULL, 13, 1050, NULL, 'DROP TABLESPACE @1 failed', NULL, NULL); +('dsql_recreate_ts_failed', 'getMainErrorCode', 'TablespaceNodes.h', NULL, 13, 1051, NULL, 'RECREATE TABLESPACE @1 failed', NULL, NULL); -- SQLWARN (NULL, NULL, NULL, NULL, 14, 100, NULL, 'Row not found for fetch, update or delete, or the result of a query is an empty table.', NULL, NULL); (NULL, NULL, NULL, NULL, 14, 101, NULL, 'segment buffer length shorter than expected', NULL, NULL); @@ -3250,12 +3266,12 @@ Elapsed time = ~ sec Reads = ! Writes = ! Fetches = !', NULL, NULL); -('NO_MAP', 'SHOW_metadata', 'show.epp', NULL, 17, 184, NULL, 'There is no mapping @1 in this database', NULL, NULL) -('NO_MAPS', 'SHOW_metadata', 'show.epp', NULL, 17, 185, NULL, 'There are no mappings in this database', NULL, NULL) -('INVALID_TERM_CHARS', 'frontend_set', 'isql.epp', NULL, 17, 186, NULL, 'Invalid characters for SET TERMINATOR are @1', NULL, NULL) -('REC_DISPLAYCOUNT', 'process_statement', 'isql.epp', NULL, 17, 187, NULL, 'Records displayed: @1', NULL, NULL) -('COLUMNS_HIDDEN', 'process_statement', 'isql.epp', NULL, 17, 188, NULL, 'Full NULL columns hidden due to RecordBuff: @1', NULL, NULL) -('HLP_SETRECORDBUF', 'help', 'isql.epp', NULL, 17, 189, NULL, ' SET RECORDBuf -- toggle limited buffering and trimming of columns', NULL, NULL) +('NO_MAP', 'SHOW_metadata', 'show.epp', NULL, 17, 184, NULL, 'There is no mapping @1 in this database', NULL, NULL); +('NO_MAPS', 'SHOW_metadata', 'show.epp', NULL, 17, 185, NULL, 'There are no mappings in this database', NULL, NULL); +('INVALID_TERM_CHARS', 'frontend_set', 'isql.epp', NULL, 17, 186, NULL, 'Invalid characters for SET TERMINATOR are @1', NULL, NULL); +('REC_DISPLAYCOUNT', 'process_statement', 'isql.epp', NULL, 17, 187, NULL, 'Records displayed: @1', NULL, NULL); +('COLUMNS_HIDDEN', 'process_statement', 'isql.epp', NULL, 17, 188, NULL, 'Full NULL columns hidden due to RecordBuff: @1', NULL, NULL); +('HLP_SETRECORDBUF', 'help', 'isql.epp', NULL, 17, 189, NULL, ' SET RECORDBuf -- toggle limited buffering and trimming of columns', NULL, NULL); ('NUMBER_USED_PAGES', 'SHOW_dbb_parameters', 'show.epp', NULL, 17, 190, NULL, 'Number of DB pages used = @1', NULL, NULL); ('NUMBER_FREE_PAGES', 'SHOW_dbb_parameters', 'show.epp', NULL, 17, 191, NULL, 'Number of DB pages free = @1', NULL, NULL); ('DATABASE_CRYPTED', 'SHOW_dbb_parameters', 'show.epp', NULL, 17, 192, NULL, 'Database encrypted', NULL, NULL); @@ -3263,6 +3279,9 @@ Fetches = !', NULL, NULL); ('DATABASE_CRYPT_PROCESS', 'SHOW_dbb_parameters', 'show.epp', NULL, 17, 194, NULL, 'crypt thread not complete', NULL, NULL); ('MSG_ROLES', 'SHOW_metadata', 'show.epp', NULL, 17, 195, NULL, 'Roles:', NULL, NULL); ('NO_TIMEOUTS', 'process_statement', 'isql.epp', NULL, 17, 196, NULL, 'Timeouts are not supported by server', NULL, NULL); +('NO_TABLESPACE', 'SHOW_metadata', 'show.epp', NULL, 17, 197, NULL, 'There is no tablespace @1 in this database', NULL, NULL); +('NO_TABLESPACES', 'SHOW_metadata', 'show.epp', NULL, 17, 198, NULL, 'There are no tablespaces in this database', NULL, NULL); +('MSG_TABLESPACES', 'SHOW_metadata', 'show.e', NULL, 17, 199, NULL, 'Tablespaces:', NULL, NULL); -- GSEC ('GsecMsg1', 'get_line', 'gsec.e', NULL, 18, 1, NULL, 'GSEC>', NULL, NULL); ('GsecMsg2', 'printhelp', 'gsec.e', 'This message is used in the Help display. It should be the same as number 1 (but in lower case).', 18, 2, NULL, 'gsec', NULL, NULL); diff --git a/src/msgs/system_errors2.sql b/src/msgs/system_errors2.sql index e85428a9ef6..3df26715c67 100644 --- a/src/msgs/system_errors2.sql +++ b/src/msgs/system_errors2.sql @@ -955,6 +955,8 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA (304, '01', '004', 0, 946, 'truncate_warn', NULL, NULL) (304, '01', '004', 0, 947, 'truncate_monitor', NULL, NULL) (304, '01', '004', 0, 948, 'truncate_context', NULL, NULL) +(-902, '08', '001', 0, 949, 'ts_file_exists', NULL, NULL) +(-901, '42', '000', 0, 950, 'tablespace_name', NULL, NULL) -- GFIX (-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL) (-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL) @@ -1114,6 +1116,8 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA (-901, '42', '000', 8, 307, 'dyn_exc_not_exist', NULL, NULL) (-901, '42', '000', 8, 308, 'dyn_gen_not_exist', NULL, NULL) (-901, '42', '000', 8, 309, 'dyn_fld_not_exist', NULL, NULL) +(-901, '42', '000', 8, 310, 'dyn_ts_not_found', NULL, NULL) +(-901, '42', '000', 8, 311, 'dyn_cant_alter_ts', NULL, NULL) -- GBAK (-901, '00', '000', 12, 1, 'gbak_unknown_switch', NULL, NULL) (-901, '00', '000', 12, 2, 'gbak_page_size_missing', NULL, NULL) @@ -1347,6 +1351,11 @@ COMMIT WORK; (-901, '42', '000', 13, 1044, 'dsql_string_char_length', NULL, NULL) (-901, '07', '002', 13, 1045, 'dsql_max_nesting', NULL, NULL) (-901, '42', '000', 13, 1046, 'dsql_recreate_user_failed', NULL, NULL); +(-901, '42', '000', 13, 1047, 'dsql_create_ts_failed', NULL, NULL); +(-901, '42', '000', 13, 1048, 'dsql_alter_ts_failed', NULL, NULL); +(-901, '42', '000', 13, 1049, 'dsql_create_alter_ts_failed', NULL, NULL); +(-901, '42', '000', 13, 1050, 'dsql_drop_ts_failed', NULL, NULL); +(-901, '42', '000', 13, 1051, 'dsql_recreate_ts_failed', NULL, NULL); -- GSEC (-901, '00', '000', 18, 15, 'gsec_cant_open_db', NULL, NULL) (-901, '00', '000', 18, 16, 'gsec_switches_error', NULL, NULL) diff --git a/src/utilities/gstat/dba.epp b/src/utilities/gstat/dba.epp index b38f9634a68..10d5ce44116 100644 --- a/src/utilities/gstat/dba.epp +++ b/src/utilities/gstat/dba.epp @@ -1557,7 +1557,7 @@ static void analyze_index( const dba_rel* relation, dba_idx* index) SLONG page; if (index_root->irt_count <= index->idx_id || - !(page = index_root->irt_rpt[index->idx_id].getRoot())) + !(page = index_root->irt_rpt[index->idx_id].getRootPage())) { return; } From 2f9ac74ee5684f15295017b1d1b198ba39c2f4b6 Mon Sep 17 00:00:00 2001 From: Roman Date: Sun, 17 May 2020 01:50:06 +0300 Subject: [PATCH 02/97] Now checks and erasing are performed in transaction and only file deleting is left at post DFW stage. Added missed object type of TABLESPACES. Added security class for tablespaces which allows not to skip check of the privileges. Corrected page space before fetching of the root index page. --- lang_helpers/gds_codes.ftn | 2 + lang_helpers/gds_codes.pas | 2 + src/dsql/TablespaceNodes.epp | 71 +++++++++++++++--- src/include/gen/Firebird.pas | 1 + src/include/gen/codetext.h | 1 + src/include/gen/iberror.h | 6 +- src/include/gen/msgs.h | 1 + src/include/gen/sql_code.h | 1 + src/include/gen/sql_state.h | 1 + src/jrd/btr.cpp | 2 +- src/jrd/dfw.epp | 140 ++++++----------------------------- src/jrd/dfw_proto.h | 2 +- src/jrd/grant.epp | 17 ++++- src/jrd/irq.h | 2 + src/jrd/met.epp | 130 +++++++++++++++++++++++++------- src/jrd/met_proto.h | 1 + src/jrd/scl.epp | 3 +- src/jrd/tra.h | 3 +- src/msgs/facilities2.sql | 2 +- src/msgs/messages2.sql | 5 +- src/msgs/system_errors2.sql | 1 + 21 files changed, 228 insertions(+), 166 deletions(-) diff --git a/lang_helpers/gds_codes.ftn b/lang_helpers/gds_codes.ftn index 18eacc6d388..f14e617a9e0 100644 --- a/lang_helpers/gds_codes.ftn +++ b/lang_helpers/gds_codes.ftn @@ -1960,6 +1960,8 @@ C -- PARAMETER (GDS__ts_file_exists = 335545273) INTEGER*4 GDS__tablespace_name PARAMETER (GDS__tablespace_name = 335545274) + INTEGER*4 GDS__ts_file_not_exists + PARAMETER (GDS__ts_file_not_exists = 335545275) INTEGER*4 GDS__gfix_db_name PARAMETER (GDS__gfix_db_name = 335740929) INTEGER*4 GDS__gfix_invalid_sw diff --git a/lang_helpers/gds_codes.pas b/lang_helpers/gds_codes.pas index b121b998c77..cc04fcd83fe 100644 --- a/lang_helpers/gds_codes.pas +++ b/lang_helpers/gds_codes.pas @@ -1955,6 +1955,8 @@ gds_ts_file_exists = 335545273; isc_tablespace_name = 335545274; gds_tablespace_name = 335545274; + isc_ts_file_not_exists = 335545275; + gds_ts_file_not_exists = 335545275; isc_gfix_db_name = 335740929; gds_gfix_db_name = 335740929; isc_gfix_invalid_sw = 335740930; diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index 2332e32f2a1..55641cc62dd 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -37,6 +37,7 @@ #include "../jrd/scl_proto.h" #include "../jrd/dyn_ut_proto.h" #include "../jrd/pag_proto.h" +#include "../jrd/os/pio_proto.h" using namespace Firebird; @@ -167,9 +168,7 @@ void CreateAlterTablespaceNode::executeCreate(thread_db* tdbb, DsqlCompilerScrat dbb->dbb_page_manager.allocTableSpace(tdbb, id, true, PathName(fileName.c_str())); -// RS: Not sure TS should have SECURITY CLASS. It's not DB SCHEMA. Only DDL privileges for managing it. -// storePrivileges(tdbb, transaction, name, obj_tablespaces, EXEC_PRIVILEGES); -// owner = userName; + storePrivileges(tdbb, transaction, name, obj_tablespaces, ALL_PRIVILEGES); executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_TABLESPACE, name, NULL); @@ -195,7 +194,9 @@ bool CreateAlterTablespaceNode::executeAlter(thread_db* tdbb, DsqlCompilerScratc MODIFY X if (fileName.hasData()) { - fb_assert(X.RDB$FILE_NAME.NULL == FALSE); + fb_assert(X.RDB$FILE_NAME.NULL == FALSE); + if (!PIO_file_exists(fileName.c_str())) + ERR_post(Arg::Gds(isc_ts_file_not_exists) << Arg::Str(name) << Arg::Str(fileName)); strcpy(X.RDB$FILE_NAME, fileName.c_str()); } @@ -245,7 +246,7 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); - bool found = false; + bool found = false; USHORT tableSpaceId = 0; AutoCacheRequest requestHandle(tdbb, drq_e_tablespace, DYN_REQUESTS); @@ -256,6 +257,9 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat found = true; tableSpaceId = X.RDB$TABLESPACE_ID; + // cache it for DFW stage + MET_tablespace_id(tdbb, tableSpaceId); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_TABLESPACE, name, NULL); @@ -264,19 +268,64 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat if (!X.RDB$SECURITY_CLASS.NULL) deleteSecurityClass(tdbb, transaction, X.RDB$SECURITY_CLASS); - DFW_post_work(transaction, dropDependencies ? dfw_drop_tablespace_dependencies - : dfw_check_tablespace_dependencies, - name.c_str(), tableSpaceId); + if (dropDependencies) + DFW_post_work(transaction, dfw_drop_tablespace, X.RDB$FILE_NAME, tableSpaceId); } - END_FOR - - if (!found && !silent) + END_FOR + + SLONG total = 0; + + // Find all indices + requestHandle.reset(tdbb, irq_ts_drop_idx_dfw, DYN_REQUESTS); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + X IN RDB$INDICES + WITH X.RDB$TABLESPACE_NAME EQ name.c_str() + { + if (dropDependencies) + { + ERASE X; + } + else + { + total++; + } + } + END_FOR + + // Find all tables + requestHandle.reset(tdbb, irq_ts_drop_rel_dfw, DYN_REQUESTS); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + X IN RDB$RELATIONS + WITH X.RDB$TABLESPACE_NAME EQ name.c_str() + { + if (dropDependencies) + { + ERASE X; + } + else + { + total++; + } + } + END_FOR + + if (!found && !silent) { status_exception::raise( Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(name)); } + if (total) + { + status_exception::raise(Arg::Gds(isc_no_meta_update) << + Arg::Gds(isc_no_delete) << // Msg353: can not delete + Arg::Gds(isc_tablespace_name) << Arg::Str(name) << + Arg::Gds(isc_dependency) << Arg::Num(total)); // Msg310: there are %ld dependencies + } + if (found) { executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_TABLESPACE, diff --git a/src/include/gen/Firebird.pas b/src/include/gen/Firebird.pas index ee30e274dc3..5b100e1f672 100644 --- a/src/include/gen/Firebird.pas +++ b/src/include/gen/Firebird.pas @@ -5063,6 +5063,7 @@ IReplicatedSessionImpl = class(IReplicatedSession) isc_ses_reset_failed = 335545272; isc_ts_file_exists = 335545273; isc_tablespace_name = 335545274; + isc_ts_file_not_exists = 335545275; isc_gfix_db_name = 335740929; isc_gfix_invalid_sw = 335740930; isc_gfix_incmp_sw = 335740932; diff --git a/src/include/gen/codetext.h b/src/include/gen/codetext.h index 5ab32a6d79a..7c4fa63e81a 100644 --- a/src/include/gen/codetext.h +++ b/src/include/gen/codetext.h @@ -976,6 +976,7 @@ static const struct { {"ses_reset_failed", 335545272}, {"ts_file_exists", 335545273}, {"tablespace_name", 335545274}, + {"ts_file_not_exists", 335545275}, {"gfix_db_name", 335740929}, {"gfix_invalid_sw", 335740930}, {"gfix_incmp_sw", 335740932}, diff --git a/src/include/gen/iberror.h b/src/include/gen/iberror.h index 376d5a4d269..f24d891b7e9 100644 --- a/src/include/gen/iberror.h +++ b/src/include/gen/iberror.h @@ -1010,6 +1010,7 @@ const ISC_STATUS isc_repl_error = 335545271L; const ISC_STATUS isc_ses_reset_failed = 335545272L; const ISC_STATUS isc_ts_file_exists = 335545273L; const ISC_STATUS isc_tablespace_name = 335545274L; +const ISC_STATUS isc_ts_file_not_exists = 335545275L; const ISC_STATUS isc_gfix_db_name = 335740929L; const ISC_STATUS isc_gfix_invalid_sw = 335740930L; const ISC_STATUS isc_gfix_incmp_sw = 335740932L; @@ -1508,7 +1509,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L; const ISC_STATUS isc_trace_switch_param_miss = 337182758L; const ISC_STATUS isc_trace_param_act_notcompat = 337182759L; const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L; -const ISC_STATUS isc_err_max = 1452; +const ISC_STATUS isc_err_max = 1453; #else /* c definitions */ @@ -2488,6 +2489,7 @@ const ISC_STATUS isc_err_max = 1452; #define isc_ses_reset_failed 335545272L #define isc_ts_file_exists 335545273L #define isc_tablespace_name 335545274L +#define isc_ts_file_not_exists 335545275L #define isc_gfix_db_name 335740929L #define isc_gfix_invalid_sw 335740930L #define isc_gfix_incmp_sw 335740932L @@ -2986,7 +2988,7 @@ const ISC_STATUS isc_err_max = 1452; #define isc_trace_switch_param_miss 337182758L #define isc_trace_param_act_notcompat 337182759L #define isc_trace_mandatory_switch_miss 337182760L -#define isc_err_max 1452 +#define isc_err_max 1453 #endif diff --git a/src/include/gen/msgs.h b/src/include/gen/msgs.h index d8633e6c13d..2d849b5bf76 100644 --- a/src/include/gen/msgs.h +++ b/src/include/gen/msgs.h @@ -979,6 +979,7 @@ Data source : @4"}, /* eds_statement */ {335545272, "Reset of user session failed. Connection is shut down."}, /* ses_reset_failed */ {335545273, "Tablespace \"@1\" creation error. File \"@2\" exists."}, /* ts_file_exists */ {335545274, "TABLESPACE @1"}, /* tablespace_name */ + {335545275, "Tablespace \"@1\" alteration error. File \"@2\" does not exists."}, /* ts_file_not_exists */ {335740929, "data base file name (@1) already given"}, /* gfix_db_name */ {335740930, "invalid switch @1"}, /* gfix_invalid_sw */ {335740932, "incompatible switch combination"}, /* gfix_incmp_sw */ diff --git a/src/include/gen/sql_code.h b/src/include/gen/sql_code.h index 4a4413c7c21..4a4ccb619ef 100644 --- a/src/include/gen/sql_code.h +++ b/src/include/gen/sql_code.h @@ -975,6 +975,7 @@ static const struct { {335545272, -902}, /* 952 ses_reset_failed */ {335545273, -902}, /* 953 ts_file_exists */ {335545274, -901}, /* 954 tablespace_name */ + {335545275, -902}, /* 955 ts_file_not_exists */ {335740929, -901}, /* 1 gfix_db_name */ {335740930, -901}, /* 2 gfix_invalid_sw */ {335740932, -901}, /* 4 gfix_incmp_sw */ diff --git a/src/include/gen/sql_state.h b/src/include/gen/sql_state.h index c4e9e76fba9..b2feff4cafd 100644 --- a/src/include/gen/sql_state.h +++ b/src/include/gen/sql_state.h @@ -975,6 +975,7 @@ static const struct { {335545272, "08003"}, // 952 ses_reset_failed {335545273, "08001"}, // 953 ts_file_exists {335545274, "42000"}, // 954 tablespace_name + {335545275, "08001"}, // 955 ts_file_not_exists {335740929, "00000"}, // 1 gfix_db_name {335740930, "00000"}, // 2 gfix_invalid_sw {335740932, "00000"}, // 4 gfix_incmp_sw diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index 09c446c3246..298a94bc826 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -2234,7 +2234,7 @@ void BTR_selectivity(thread_db* tdbb, jrd_rel* relation, USHORT id, SelectivityL selectivity[0] = (float) (nodes ? 1.0 / (float) (nodes - duplicates) : 0.0); // Store the selectivity on the root page - window.win_page = relPages->rel_index_root; + window.win_page = PageNumber(relPages->rel_pg_space_id, relPages->rel_index_root); window.win_flags = 0; root = (index_root_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_root); CCH_MARK(tdbb, &window); diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 85364aa58d9..a108d68413b 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -491,8 +491,7 @@ static bool clear_cache(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool change_repl_state(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool create_tablespace(thread_db*, SSHORT, DeferredWork*, jrd_tra*); -static bool check_tablespace_dependencies(thread_db*, SSHORT, DeferredWork*, jrd_tra*); -static bool drop_tablespace_dependencies(thread_db*, SSHORT, DeferredWork*, jrd_tra*); +static bool drop_tablespace(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool move_relation(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool move_index(thread_db*, SSHORT, DeferredWork*, jrd_tra*); @@ -1246,8 +1245,7 @@ static const deferred_task task_table[] = { dfw_change_repl_state, change_repl_state }, { dfw_create_tablespace, create_tablespace }, - { dfw_check_tablespace_dependencies, check_tablespace_dependencies }, - { dfw_drop_tablespace_dependencies, drop_tablespace_dependencies }, + { dfw_drop_tablespace, drop_tablespace }, { dfw_move_relation, move_relation }, { dfw_move_index, move_index }, @@ -1577,6 +1575,7 @@ void DFW_perform_work(thread_db* tdbb, jrd_tra* transaction) case dfw_delete_shadow: case dfw_clear_datapages: case dfw_clear_indexpages: + case dfw_drop_tablespace: break; default: @@ -1635,6 +1634,7 @@ void DFW_perform_post_commit_work(thread_db* tdbb, jrd_tra* transaction) pending_events = true; break; + case dfw_drop_tablespace: case dfw_delete_shadow: if (work->dfw_name.hasData()) unlink(work->dfw_name.c_str()); @@ -6518,16 +6518,16 @@ static bool create_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, } -static bool check_tablespace_dependencies(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction) +static bool drop_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction) { /************************************** * - * c h e c k _ t a b l e s p a c e _ d e p e n d e n c i e s + * d r o p _ t a b l e s p a c e * ************************************** * * Functional description - * Check tablespace dependencies before drop + * Drop tablespace and its file at post commit stage * **************************************/ @@ -6535,122 +6535,30 @@ static bool check_tablespace_dependencies(thread_db* tdbb, SSHORT phase, Deferre Database* dbb = tdbb->getDatabase(); Attachment* attachment = tdbb->getAttachment(); - switch (phase) - { - case 1: - { - SLONG total = 0; - - { // Find all indices - AutoCacheRequest requestHandle(tdbb, irq_ts_find_idx_dfw, DYN_REQUESTS); - - FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) - X IN RDB$INDICES - WITH X.RDB$TABLESPACE_NAME EQ work->dfw_name.c_str() - { - total++; - } - END_FOR - } - - { // Find all tables - AutoCacheRequest requestHandle(tdbb, irq_ts_find_rel_dfw, DYN_REQUESTS); - - FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) - X IN RDB$RELATIONS - WITH X.RDB$TABLESPACE_NAME EQ work->dfw_name.c_str() - { - total++; - } - END_FOR - } - - if (total) - { - status_exception::raise(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_no_delete) << // Msg353: can not delete - Arg::Gds(isc_tablespace_name) << Arg::Str(work->dfw_name) << - Arg::Gds(isc_dependency) << Arg::Num(total)); // Msg310: there are %ld dependencies - } - } - return true; - - case 2: - case 3: - case 4: - break; - } - - return false; -} - + Tablespace* tablespace = MET_tablespace_id(tdbb, work->dfw_id); -static bool drop_tablespace_dependencies(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction) -{ -/************************************** - * - * d r o p _ t a b l e s p a c e _ d e p e n d e n c i e s - * - ************************************** - * - * Functional description - * Drop tablespace dependencies - * - **************************************/ - - SET_TDBB(tdbb); - Database* dbb = tdbb->getDatabase(); - Attachment* attachment = tdbb->getAttachment(); + // We assume the tablespace must exists if dfw with has added + fb_assert(tablespace); switch (phase) { case 0: - if (work->dfw_id <= attachment->getTablespaceCount()) - { - Tablespace* tablespace = attachment->getTablespace(work->dfw_id); - if ( tablespace->existenceLock && tablespace->isUsed() ) - LCK_convert(tdbb, tablespace->existenceLock, LCK_SR, transaction->getLockWait()); - } + if ( tablespace->existenceLock && tablespace->isUsed() ) + LCK_convert(tdbb, tablespace->existenceLock, LCK_SR, transaction->getLockWait()); return false; case 1: { - // Make sure nobady uses tablespace - if (work->dfw_id <= attachment->getTablespaceCount()) + // Make sure that nobody uses the tablespace + if ( tablespace->isUsed() || // RS: if isUsed maybe I must try to convert SR to EX? + (tablespace->existenceLock && + !LCK_lock(tdbb, tablespace->existenceLock, LCK_EX, transaction->getLockWait()) ) + ) { - Tablespace* tablespace = attachment->getTablespace(work->dfw_id); - if ( (tablespace && tablespace->isUsed()) || // RS: if isUsed maybe I must try to convert SR to EX? - (tablespace->existenceLock && - !LCK_lock(tdbb, tablespace->existenceLock, LCK_EX, transaction->getLockWait()) ) - ) - { - raiseObjectInUseError("TABLESPACE", work->dfw_name); - } - } - - { // Find all indices - AutoCacheRequest requestHandle(tdbb, irq_ts_drop_idx_dfw, DYN_REQUESTS); - - FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) - X IN RDB$INDICES - WITH X.RDB$TABLESPACE_NAME EQ work->dfw_name.c_str() - { - ERASE X; - } - END_FOR - } - - { // Find all tables - AutoCacheRequest requestHandle(tdbb, irq_ts_drop_rel_dfw, DYN_REQUESTS); - - FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) - X IN RDB$RELATIONS - WITH X.RDB$TABLESPACE_NAME EQ work->dfw_name.c_str() - { - ERASE X; - } - END_FOR + raiseObjectInUseError("TABLESPACE", tablespace->name.c_str()); } + // Probably here we need to remove the cache tablespace from attachment. Need to think... + // Also it's necessary to close open file descriptor of the tablespace } return true; @@ -6658,12 +6566,8 @@ static bool drop_tablespace_dependencies(thread_db* tdbb, SSHORT phase, Deferred case 3: return true; case 4: - if (work->dfw_id <= attachment->getTablespaceCount()) - { - Tablespace* tablespace = attachment->getTablespace(work->dfw_id); - if (tablespace->existenceLock) - LCK_release(tdbb, tablespace->existenceLock); - } + if (tablespace->existenceLock) + LCK_release(tdbb, tablespace->existenceLock); break; } diff --git a/src/jrd/dfw_proto.h b/src/jrd/dfw_proto.h index 69618f6cf69..e330fb4bac0 100644 --- a/src/jrd/dfw_proto.h +++ b/src/jrd/dfw_proto.h @@ -1,4 +1,4 @@ -/* + /* * PROGRAM: JRD Access Method * MODULE: dfw_proto.h * DESCRIPTION: Prototype header file for dfw.cpp diff --git a/src/jrd/grant.epp b/src/jrd/grant.epp index 6106c098721..1ab009e5fab 100644 --- a/src/jrd/grant.epp +++ b/src/jrd/grant.epp @@ -519,7 +519,22 @@ static void get_object_info(thread_db* tdbb, } END_FOR } - else + else if (obj_type == obj_tablespace) + { + AutoCacheRequest request(tdbb, irq_grant20, IRQ_REQUESTS); + + FOR(REQUEST_HANDLE request) + X IN RDB$TABLESPACES WITH + X.RDB$TABLESPACE_NAME EQ object_name + { + s_class = X.RDB$SECURITY_CLASS; + default_class = ""; + owner = X.RDB$OWNER_NAME; + view = false; + } + END_FOR + } + else { s_class = get_object_name(obj_type); default_class = ""; diff --git a/src/jrd/irq.h b/src/jrd/irq.h index b30fc415a98..0d65887cf4a 100644 --- a/src/jrd/irq.h +++ b/src/jrd/irq.h @@ -176,6 +176,7 @@ enum irq_type_t irq_grant17, // process grant option (database) irq_grant18, // process grant option (filters) irq_grant19, // process grant option (roles) + irq_grant20, // process grant option (tablespaces) irq_l_curr_format, // lookup table's current format irq_c_relation3, // lookup relation in phase 0 to cleanup irq_linger, // get database linger value @@ -185,6 +186,7 @@ enum irq_type_t irq_find_ts, // find tablespace options by name irq_out_proc_param_dep, // check output procedure parameter dependency irq_l_pub_tab_state, // lookup publication state for a table + irq_find_ts_id, // find tablespace options by id irq_list_ts_files, // list tablespace files irq_find_ts_dfw, // find tablespace options by name in dfw irq_find_ts_dfw0, // find tablespace options by name in dfw for cleanup diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 15c337e5926..83e0907ca3b 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -5587,17 +5587,17 @@ USHORT MET_index_pagespace(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, USHORT return pageSpaceId; } -Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const MetaName& tableSpaceName) +Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id) { /************************************** * - * M E T _ t a b l e s p a c e + * M E T _ t a b l e s p a c e _ i d * ************************************** * * Functional description - * Find tablespace by its name in attach cache first of all. - * If not found alloc pagespace, get exist tablespace lock and + * Find tablespace by its id in attach cache first of all. + * If it's not found alloc pagespace, get exist tablespace lock and * add it in attachment cache. * * Return a pointer to the tablespace. @@ -5607,60 +5607,138 @@ Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const MetaName& tableSpaceName) Database* dbb = tdbb->getDatabase(); CHECK_DBB(dbb); - Attachment* attachment = tdbb->getAttachment(); - if (tableSpaceName.isEmpty()) - return attachment->getTablespace(DB_PAGE_SPACE); + // Check that pageSpaceId has reasonable value + fb_assert( (id > DB_PAGE_SPACE) && (id < TRANS_PAGE_SPACE) ); - const USHORT tsCount = attachment->getTablespaceCount(); + Attachment* attachment = tdbb->getAttachment(); - for (USHORT i = 2; i <= tsCount; i++) + const USHORT tsCount = attachment->getTablespaceCount(); + + // tablespace id is started from 1 + if (id <= tsCount) { - Tablespace* ts = attachment->getTablespace(i); - if (ts && (ts->name == tableSpaceName) ) + Tablespace* ts = attachment->getTablespace(id); + if (ts) + { + fb_assert(ts->id == id); return ts; + } } // Now we need to find tablespace in system table - AutoCacheRequest request(tdbb, irq_find_ts, IRQ_REQUESTS); + AutoCacheRequest request(tdbb, irq_find_ts_id, IRQ_REQUESTS); - USHORT pageSpaceId; + MetaName tableSpaceName; PathName file; bool found = false; - FOR(REQUEST_HANDLE request) + FOR(REQUEST_HANDLE request) TS IN RDB$TABLESPACES - WITH TS.RDB$TABLESPACE_NAME EQ tableSpaceName.c_str() - { - found = true; - pageSpaceId = TS.RDB$TABLESPACE_ID; - file = TS.RDB$FILE_NAME; + WITH TS.RDB$TABLESPACE_ID EQ id + { + found = true; + tableSpaceName = TS.RDB$TABLESPACE_NAME; + file = TS.RDB$FILE_NAME; } END_FOR if (!found) status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(tableSpaceName)); - // Check that pageSpaceId has reasonable value - fb_assert( (pageSpaceId > DB_PAGE_SPACE) && (pageSpaceId < TRANS_PAGE_SPACE) ); - // Check that pageSpaceId is either new or is not set (else it should be found in att_tablespaces above) - fb_assert( (pageSpaceId >= tsCount + 1) || !attachment->getTablespace(pageSpaceId)); + fb_assert( (id >= tsCount + 1) || !attachment->getTablespace(id)); - dbb->dbb_page_manager.allocTableSpace(tdbb, pageSpaceId, false, file); + dbb->dbb_page_manager.allocTableSpace(tdbb, id, false, file); Tablespace* tableSpace = FB_NEW_POOL(*attachment->att_pool) Tablespace(*attachment->att_pool); - tableSpace->id = pageSpaceId; + tableSpace->id = id; tableSpace->name = tableSpaceName; Lock* lock = FB_NEW_RPT(*attachment->att_pool, 0) Lock(tdbb, sizeof(SLONG), LCK_tablespace_exist, tableSpace); tableSpace->existenceLock = lock; lock->setKey(tableSpace->id); - attachment->setTablespace(pageSpaceId, tableSpace); + attachment->setTablespace(id, tableSpace); return tableSpace; } + +Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const MetaName& tableSpaceName) +{ +/************************************** + * + * M E T _ t a b l e s p a c e + * + ************************************** + * + * Functional description + * Find tablespace by its name in attach cache first of all. + * If not found alloc pagespace, get exist tablespace lock and + * add it in attachment cache. + * + * Return a pointer to the tablespace. + * + **************************************/ + SET_TDBB(tdbb); + Database* dbb = tdbb->getDatabase(); + CHECK_DBB(dbb); + + Attachment* attachment = tdbb->getAttachment(); + if (tableSpaceName.isEmpty()) + return attachment->getTablespace(DB_PAGE_SPACE); + + const USHORT tsCount = attachment->getTablespaceCount(); + + for (USHORT i = 2; i <= tsCount; i++) + { + Tablespace* ts = attachment->getTablespace(i); + if (ts && (ts->name == tableSpaceName) ) + return ts; + } + + // Now we need to find tablespace in system table + AutoCacheRequest request(tdbb, irq_find_ts, IRQ_REQUESTS); + + USHORT pageSpaceId; + PathName file; + bool found = false; + + FOR(REQUEST_HANDLE request) + TS IN RDB$TABLESPACES + WITH TS.RDB$TABLESPACE_NAME EQ tableSpaceName.c_str() + { + found = true; + pageSpaceId = TS.RDB$TABLESPACE_ID; + file = TS.RDB$FILE_NAME; + } + END_FOR + + if (!found) + status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(tableSpaceName)); + + // Check that pageSpaceId has reasonable value + fb_assert( (pageSpaceId > DB_PAGE_SPACE) && (pageSpaceId < TRANS_PAGE_SPACE) ); + + // Check that pageSpaceId is either new or is not set (else it should be found in att_tablespaces above) + fb_assert( (pageSpaceId >= tsCount + 1) || !attachment->getTablespace(pageSpaceId)); + + dbb->dbb_page_manager.allocTableSpace(tdbb, pageSpaceId, false, file); + + Tablespace* tableSpace = FB_NEW_POOL(*attachment->att_pool) Tablespace(*attachment->att_pool); + tableSpace->id = pageSpaceId; + tableSpace->name = tableSpaceName; + + Lock* lock = FB_NEW_RPT(*attachment->att_pool, 0) + Lock(tdbb, sizeof(SLONG), LCK_tablespace_exist, tableSpace); + tableSpace->existenceLock = lock; + lock->setKey(tableSpace->id); + attachment->setTablespace(pageSpaceId, tableSpace); + + return tableSpace; +} + + void MET_ts_files(Jrd::thread_db* tdbb, ObjectsArray& files) { /************************************** diff --git a/src/jrd/met_proto.h b/src/jrd/met_proto.h index 5cd8783347f..59eecc0351e 100644 --- a/src/jrd/met_proto.h +++ b/src/jrd/met_proto.h @@ -146,6 +146,7 @@ Nullable MET_get_ss_definer(Jrd::thread_db*); USHORT MET_rel_pagespace(Jrd::thread_db* tdbb, USHORT rel_id); USHORT MET_index_pagespace(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, USHORT idx_id); +Jrd::Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id); Jrd::Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const Jrd::MetaName& tableSpaceName); void MET_ts_files(Jrd::thread_db* tdbb, Firebird::ObjectsArray &files); void MET_scan_tablespaces(Jrd::thread_db*); diff --git a/src/jrd/scl.epp b/src/jrd/scl.epp index 5265d782dbf..9fa980ab41c 100644 --- a/src/jrd/scl.epp +++ b/src/jrd/scl.epp @@ -123,6 +123,7 @@ namespace const char* const object_str_view = "VIEW"; const char* const object_str_role = "ROLE"; const char* const object_str_filter = "FILTER"; + const char* const object_str_tablespace = "TABLESPACE"; struct SecObjectNamePriority @@ -148,6 +149,7 @@ namespace {object_str_view, SCL_object_view}, {object_str_role, SCL_object_role}, {object_str_filter, SCL_object_filter}, + {object_str_tablespace, SCL_object_tablespace}, {"", 0} }; @@ -1875,4 +1877,3 @@ static bool check_object(thread_db* tdbb, } return found; } - diff --git a/src/jrd/tra.h b/src/jrd/tra.h index d8eda9d5495..9b828a2ffcb 100644 --- a/src/jrd/tra.h +++ b/src/jrd/tra.h @@ -513,8 +513,7 @@ enum dfw_t { dfw_set_generator, dfw_change_repl_state, dfw_create_tablespace, - dfw_check_tablespace_dependencies, - dfw_drop_tablespace_dependencies, + dfw_drop_tablespace, dfw_move_relation, dfw_move_index, dfw_clear_datapages, diff --git a/src/msgs/facilities2.sql b/src/msgs/facilities2.sql index 35a8c672c7b..08fdf8d7261 100644 --- a/src/msgs/facilities2.sql +++ b/src/msgs/facilities2.sql @@ -1,7 +1,7 @@ /* MAX_NUMBER is the next number to be used, always one more than the highest message number. */ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?); -- -('2021-01-09 12:00:00', 'JRD', 0, 955) +('2021-01-10 12:00:00', 'JRD', 0, 956) ('2015-03-17 18:33:00', 'QLI', 1, 533) ('2018-03-17 12:00:00', 'GFIX', 3, 136) ('1996-11-07 13:39:40', 'GPRE', 4, 1) diff --git a/src/msgs/messages2.sql b/src/msgs/messages2.sql index 34102976f8e..b3cfc63d960 100644 --- a/src/msgs/messages2.sql +++ b/src/msgs/messages2.sql @@ -1060,8 +1060,9 @@ Data source : @4', NULL, NULL) ('wrong_page', 'get_header', 'dpm.epp', NULL, 0, 950, NULL, 'RDB$PAGES written by non-system transaction, DB appears to be damaged', NULL, NULL); ('repl_error', 'checkStatus', 'Publisher.cpp', NULL, 0, 951, NULL, 'Replication error', NULL, NULL); ('ses_reset_failed', NULL, 'Attachment.cpp', NULL, 0, 952, NULL, 'Reset of user session failed. Connection is shut down.', NULL, NULL); -('ts_file_exists', NULL, NULL, NULL, 0, 953, NULL, 'Tablespace "@1" creation error. File "@2" exists.', NULL, NULL); --//TODO: fix error refs -('tablespace_name', 'handleDependencies', 'TablespaceNodes.epp', NULL, 0, 954, NULL, 'TABLESPACE @1', NULL, NULL); --//TODO: fix error refs +('ts_file_exists', NULL, NULL, NULL, 0, 953, NULL, 'Tablespace "@1" creation error. File "@2" exists.', NULL, NULL); +('tablespace_name', 'handleDependencies', 'TablespaceNodes.epp', NULL, 0, 954, NULL, 'TABLESPACE @1', NULL, NULL); +('ts_file_not_exists', NULL, NULL, NULL, 0, 955, NULL, 'Tablespace "@1" alteration error. File "@2" does not exists.', NULL, NULL); -- QLI (NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL); (NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL); diff --git a/src/msgs/system_errors2.sql b/src/msgs/system_errors2.sql index ab0cdee79fb..e414169882d 100644 --- a/src/msgs/system_errors2.sql +++ b/src/msgs/system_errors2.sql @@ -961,6 +961,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA (-902, '08', '003', 0, 952, 'ses_reset_failed', NULL, NULL) (-902, '08', '001', 0, 953, 'ts_file_exists', NULL, NULL) (-901, '42', '000', 0, 954, 'tablespace_name', NULL, NULL) +(-902, '08', '001', 0, 955, 'ts_file_not_exists', NULL, NULL) -- GFIX (-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL) (-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL) From 766fc1b0e6dce35a42b63c0c53a959cbf677fd60 Mon Sep 17 00:00:00 2001 From: Roman Simakov Date: Thu, 28 May 2020 16:34:21 +0300 Subject: [PATCH 03/97] Avoid deleting an index tree if it does not exist --- src/dsql/TablespaceNodes.epp | 120 ++++++++++++++++++----------------- src/jrd/btr.cpp | 3 +- 2 files changed, 65 insertions(+), 58 deletions(-) diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index 55641cc62dd..f5bb21054b7 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -168,7 +168,7 @@ void CreateAlterTablespaceNode::executeCreate(thread_db* tdbb, DsqlCompilerScrat dbb->dbb_page_manager.allocTableSpace(tdbb, id, true, PathName(fileName.c_str())); - storePrivileges(tdbb, transaction, name, obj_tablespaces, ALL_PRIVILEGES); + storePrivileges(tdbb, transaction, name, obj_tablespaces, ALL_PRIVILEGES); executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_TABLESPACE, name, NULL); @@ -194,9 +194,9 @@ bool CreateAlterTablespaceNode::executeAlter(thread_db* tdbb, DsqlCompilerScratc MODIFY X if (fileName.hasData()) { - fb_assert(X.RDB$FILE_NAME.NULL == FALSE); - if (!PIO_file_exists(fileName.c_str())) - ERR_post(Arg::Gds(isc_ts_file_not_exists) << Arg::Str(name) << Arg::Str(fileName)); + fb_assert(X.RDB$FILE_NAME.NULL == FALSE); + if (!PIO_file_exists(fileName.c_str())) + ERR_post(Arg::Gds(isc_ts_file_not_exists) << Arg::Str(name) << Arg::Str(fileName)); strcpy(X.RDB$FILE_NAME, fileName.c_str()); } @@ -246,7 +246,7 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); - bool found = false; + bool found = false; USHORT tableSpaceId = 0; AutoCacheRequest requestHandle(tdbb, drq_e_tablespace, DYN_REQUESTS); @@ -257,8 +257,8 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat found = true; tableSpaceId = X.RDB$TABLESPACE_ID; - // cache it for DFW stage - MET_tablespace_id(tdbb, tableSpaceId); + // cache it for DFW stage + MET_tablespace_id(tdbb, tableSpaceId); executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_TABLESPACE, name, NULL); @@ -268,63 +268,69 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat if (!X.RDB$SECURITY_CLASS.NULL) deleteSecurityClass(tdbb, transaction, X.RDB$SECURITY_CLASS); - if (dropDependencies) - DFW_post_work(transaction, dfw_drop_tablespace, X.RDB$FILE_NAME, tableSpaceId); + if (dropDependencies) + DFW_post_work(transaction, dfw_drop_tablespace, X.RDB$FILE_NAME, tableSpaceId); } - END_FOR - - SLONG total = 0; - - // Find all indices - requestHandle.reset(tdbb, irq_ts_drop_idx_dfw, DYN_REQUESTS); - - FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) - X IN RDB$INDICES - WITH X.RDB$TABLESPACE_NAME EQ name.c_str() - { - if (dropDependencies) - { - ERASE X; - } - else - { - total++; - } - } - END_FOR - - // Find all tables - requestHandle.reset(tdbb, irq_ts_drop_rel_dfw, DYN_REQUESTS); - - FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) - X IN RDB$RELATIONS - WITH X.RDB$TABLESPACE_NAME EQ name.c_str() - { - if (dropDependencies) - { - ERASE X; - } - else - { - total++; - } - } - END_FOR - - if (!found && !silent) + END_FOR + + SLONG total = 0; + + // Find all indices + requestHandle.reset(tdbb, irq_ts_drop_idx_dfw, DYN_REQUESTS); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + X IN RDB$INDICES + WITH X.RDB$TABLESPACE_NAME EQ name.c_str() + { + if (dropDependencies) + { + if (X.RDB$EXPRESSION_BLR.NULL && !DropIndexNode::deleteSegmentRecords(tdbb, transaction, X.RDB$INDEX_NAME)) + { + // msg 50: "No segments found for index" + status_exception::raise(Arg::PrivateDyn(50)); + } + + ERASE X; + } + else + { + total++; + } + } + END_FOR + + // Find all tables + requestHandle.reset(tdbb, irq_ts_drop_rel_dfw, DYN_REQUESTS); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + X IN RDB$RELATIONS + WITH X.RDB$TABLESPACE_NAME EQ name.c_str() + { + if (dropDependencies) + { + ERASE X; + } + else + { + total++; + } + } + END_FOR + + if (!found && !silent) { status_exception::raise( Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(name)); } - if (total) - { - status_exception::raise(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_no_delete) << // Msg353: can not delete - Arg::Gds(isc_tablespace_name) << Arg::Str(name) << - Arg::Gds(isc_dependency) << Arg::Num(total)); // Msg310: there are %ld dependencies - } + if (total) + { + status_exception::raise(Arg::Gds(isc_no_meta_update) << + Arg::Gds(isc_no_delete) << // Msg353: can not delete + Arg::Gds(isc_tablespace_name) << Arg::Str(name) << + Arg::Gds(isc_dependency) << Arg::Num(total)); // Msg310: there are %ld dependencies + } if (found) { diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index 298a94bc826..fbec3687622 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -477,7 +477,8 @@ bool BTR_delete_index(thread_db* tdbb, Jrd::jrd_rel* relation, WIN* window, USHO const USHORT relation_id = root->irt_relation; CCH_RELEASE(tdbb, window); - delete_tree(tdbb, relation_id, id, next, prior); + if (tree_exists) + delete_tree(tdbb, relation_id, id, next, prior); } return tree_exists; From 1cf0b811fbf5f0c829d2bda93c75a47bf6f1864e Mon Sep 17 00:00:00 2001 From: Roman Simakov Date: Thu, 28 May 2020 20:57:24 +0300 Subject: [PATCH 04/97] Wrong constant for the object. --- src/dsql/TablespaceNodes.epp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index f5bb21054b7..9824771c81a 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -168,7 +168,7 @@ void CreateAlterTablespaceNode::executeCreate(thread_db* tdbb, DsqlCompilerScrat dbb->dbb_page_manager.allocTableSpace(tdbb, id, true, PathName(fileName.c_str())); - storePrivileges(tdbb, transaction, name, obj_tablespaces, ALL_PRIVILEGES); + storePrivileges(tdbb, transaction, name, obj_tablespace, ALL_PRIVILEGES); executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_TABLESPACE, name, NULL); From 6598a01a9cc0152d02f0ab39455626ab81e6b703 Mon Sep 17 00:00:00 2001 From: Roman Simakov Date: Wed, 10 Jun 2020 16:02:01 +0300 Subject: [PATCH 05/97] Now to delete the tables while deleting a tablespace we use the same code as for deleting a table. NOTE: Now we fire DDL trigger for deleling tables even if they are deleting as result of DROP TABLESPACE ... INCLUDING CONTENTS --- src/dsql/DdlNodes.epp | 420 ++++++++++++++++++----------------- src/dsql/DdlNodes.h | 2 + src/dsql/TablespaceNodes.epp | 11 +- src/jrd/drq.h | 2 + src/jrd/irq.h | 4 - 5 files changed, 226 insertions(+), 213 deletions(-) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 979ef59d97a..5cdcafdbec3 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -8495,6 +8495,217 @@ void DropRelationNode::deleteGlobalField(thread_db* tdbb, jrd_tra* transaction, END_FOR } + +void DropRelationNode::dropRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, bool view, jrd_rel* rel_drop) +{ + MetaName name(rel_drop->rel_name); + + if (!view) + { + RelationPages* relPages = rel_drop->getBasePages(); + if (!relPages->rel_pages || (relPages->rel_pages->count() == 0)) + DPM_scan_pages(tdbb, pag_pointer, rel_drop->rel_id); + if (!relPages->rel_index_root) + DPM_scan_pages(tdbb, pag_root, rel_drop->rel_id); + } + + const int ddlTriggerAction = (view ? DDL_TRIGGER_DROP_VIEW : DDL_TRIGGER_DROP_TABLE); + + // run all statements under savepoint control + AutoSavePoint savePoint(tdbb, transaction); + + AutoCacheRequest request(tdbb, drq_l_relation, DYN_REQUESTS); + bool found = false; + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + R IN RDB$RELATIONS + WITH R.RDB$RELATION_NAME EQ name.c_str() + { + executeDdlTrigger(tdbb, transaction, DTW_BEFORE, ddlTriggerAction, name, NULL, *dsqlScratch->getStatement()->getSqlText()); + found = true; + } + END_FOR + + request.reset(tdbb, drq_e_rel_con2, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + CRT IN RDB$RELATION_CONSTRAINTS + WITH CRT.RDB$RELATION_NAME EQ name.c_str() AND + (CRT.RDB$CONSTRAINT_TYPE EQ PRIMARY_KEY OR + CRT.RDB$CONSTRAINT_TYPE EQ UNIQUE_CNSTRT OR + CRT.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY) + SORTED BY ASCENDING CRT.RDB$CONSTRAINT_TYPE + { + ERASE CRT; + } + END_FOR + + request.reset(tdbb, drq_e_rel_idxs, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + IDX IN RDB$INDICES + WITH IDX.RDB$RELATION_NAME EQ name.c_str() + { + DropIndexNode::deleteSegmentRecords(tdbb, transaction, IDX.RDB$INDEX_NAME); + ERASE IDX; + } + END_FOR + + request.reset(tdbb, drq_e_trg_msgs2, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + TM IN RDB$TRIGGER_MESSAGES + CROSS T IN RDB$TRIGGERS + WITH T.RDB$RELATION_NAME EQ name.c_str() AND + TM.RDB$TRIGGER_NAME EQ T.RDB$TRIGGER_NAME + { + ERASE TM; + } + END_FOR + + // CVC: Moved this block here to avoid SF Bug #1111570. + request.reset(tdbb, drq_e_rel_con3, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + CRT IN RDB$RELATION_CONSTRAINTS + WITH CRT.RDB$RELATION_NAME EQ name.c_str() AND + (CRT.RDB$CONSTRAINT_TYPE EQ CHECK_CNSTRT OR + CRT.RDB$CONSTRAINT_TYPE EQ NOT_NULL_CNSTRT) + { + ERASE CRT; + } + END_FOR + + request.reset(tdbb, drq_e_rel_flds, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + RFR IN RDB$RELATION_FIELDS + WITH RFR.RDB$RELATION_NAME EQ name.c_str() + { + if (!RFR.RDB$GENERATOR_NAME.NULL) + DropSequenceNode::deleteIdentity(tdbb, transaction, RFR.RDB$GENERATOR_NAME); + + ERASE RFR; + + if (!RFR.RDB$SECURITY_CLASS.NULL && + !strncmp(RFR.RDB$SECURITY_CLASS, SQL_SECCLASS_PREFIX, SQL_SECCLASS_PREFIX_LEN)) + { + deleteSecurityClass(tdbb, transaction, RFR.RDB$SECURITY_CLASS); + } + + deleteGlobalField(tdbb, transaction, RFR.RDB$FIELD_SOURCE); + } + END_FOR + + request.reset(tdbb, drq_e_view_rels, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + VR IN RDB$VIEW_RELATIONS + WITH VR.RDB$VIEW_NAME EQ name.c_str() + { + ERASE VR; + } + END_FOR + + request.reset(tdbb, drq_e_relation, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + R IN RDB$RELATIONS + WITH R.RDB$RELATION_NAME EQ name.c_str() + { + ERASE R; + + if (!R.RDB$SECURITY_CLASS.NULL && + !strncmp(R.RDB$SECURITY_CLASS, SQL_SECCLASS_PREFIX, SQL_SECCLASS_PREFIX_LEN)) + { + deleteSecurityClass(tdbb, transaction, R.RDB$SECURITY_CLASS); + } + } + END_FOR + + if (!found) + { + // msg 61: "Relation not found" + status_exception::raise(Arg::PrivateDyn(61)); + } + + // Triggers must be deleted after check constraints + + MetaName triggerName; + + request.reset(tdbb, drq_e_trigger2, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + X IN RDB$TRIGGERS + WITH X.RDB$RELATION_NAME EQ name.c_str() + { + triggerName = X.RDB$TRIGGER_NAME; + ERASE X; + + AutoCacheRequest request2(tdbb, drq_e_trg_prv, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + WITH PRIV.RDB$USER EQ triggerName.c_str() AND + PRIV.RDB$USER_TYPE = obj_trigger AND + PRIV.RDB$GRANTOR NOT MISSING + { + ERASE PRIV; + } + END_FOR + } + END_FOR + + request.reset(tdbb, drq_e_usr_prvs, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + WITH PRIV.RDB$RELATION_NAME EQ name.c_str() AND + PRIV.RDB$OBJECT_TYPE = obj_relation AND + PRIV.RDB$GRANTOR NOT MISSING + { + ERASE PRIV; + } + END_FOR + + request.reset(tdbb, drq_e_view_prv, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + WITH PRIV.RDB$USER EQ name.c_str() AND + PRIV.RDB$USER_TYPE = obj_view AND + PRIV.RDB$GRANTOR NOT MISSING + { + ERASE PRIV; + } + END_FOR + + // Drop table from all publications + + request.reset(tdbb, drq_e_pub_tab_all, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + PTAB IN RDB$PUBLICATION_TABLES + WITH PTAB.RDB$TABLE_NAME EQ name.c_str() + { + ERASE PTAB; + } + END_FOR + + if (found) + executeDdlTrigger(tdbb, transaction, DTW_AFTER, ddlTriggerAction, name, NULL, *dsqlScratch->getStatement()->getSqlText()); + else + { + // msg 61: "Relation not found" + status_exception::raise(Arg::PrivateDyn(61)); + } + + savePoint.release(); // everything is ok + + METD_drop_relation(transaction, name.c_str()); + MET_dsql_cache_release(tdbb, SYM_relation, name); +} + string DropRelationNode::internalPrint(NodePrinter& printer) const { DdlNode::internalPrint(printer); @@ -8531,7 +8742,7 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch // Check that DROP TABLE is dropping a table and that DROP VIEW is dropping a view. if (view) { - if (!relation || (relation && !(relation->rel_flags & REL_view))) + if (!relation || !(relation->rel_flags & REL_view)) { status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-607) << @@ -8541,7 +8752,7 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch } else { - if (!relation || (relation && (relation->rel_flags & REL_view))) + if (!relation || (relation->rel_flags & REL_view)) { status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-607) << @@ -8550,210 +8761,7 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch } } - if (!view) - { - RelationPages* relPages = rel_drop->getBasePages(); - if (!relPages->rel_pages || (relPages->rel_pages->count() == 0)) - DPM_scan_pages(tdbb, pag_pointer, rel_drop->rel_id); - if (!relPages->rel_index_root) - DPM_scan_pages(tdbb, pag_root, rel_drop->rel_id); - } - - const int ddlTriggerAction = (view ? DDL_TRIGGER_DROP_VIEW : DDL_TRIGGER_DROP_TABLE); - - // run all statements under savepoint control - AutoSavePoint savePoint(tdbb, transaction); - - AutoCacheRequest request(tdbb, drq_l_relation, DYN_REQUESTS); - bool found = false; - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - R IN RDB$RELATIONS - WITH R.RDB$RELATION_NAME EQ name.c_str() - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, ddlTriggerAction, name, NULL); - found = true; - } - END_FOR - - request.reset(tdbb, drq_e_rel_con2, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - CRT IN RDB$RELATION_CONSTRAINTS - WITH CRT.RDB$RELATION_NAME EQ name.c_str() AND - (CRT.RDB$CONSTRAINT_TYPE EQ PRIMARY_KEY OR - CRT.RDB$CONSTRAINT_TYPE EQ UNIQUE_CNSTRT OR - CRT.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY) - SORTED BY ASCENDING CRT.RDB$CONSTRAINT_TYPE - { - ERASE CRT; - } - END_FOR - - request.reset(tdbb, drq_e_rel_idxs, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - IDX IN RDB$INDICES - WITH IDX.RDB$RELATION_NAME EQ name.c_str() - { - DropIndexNode::deleteSegmentRecords(tdbb, transaction, IDX.RDB$INDEX_NAME); - ERASE IDX; - } - END_FOR - - request.reset(tdbb, drq_e_trg_msgs2, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - TM IN RDB$TRIGGER_MESSAGES - CROSS T IN RDB$TRIGGERS - WITH T.RDB$RELATION_NAME EQ name.c_str() AND - TM.RDB$TRIGGER_NAME EQ T.RDB$TRIGGER_NAME - { - ERASE TM; - } - END_FOR - - // CVC: Moved this block here to avoid SF Bug #1111570. - request.reset(tdbb, drq_e_rel_con3, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - CRT IN RDB$RELATION_CONSTRAINTS - WITH CRT.RDB$RELATION_NAME EQ name.c_str() AND - (CRT.RDB$CONSTRAINT_TYPE EQ CHECK_CNSTRT OR - CRT.RDB$CONSTRAINT_TYPE EQ NOT_NULL_CNSTRT) - { - ERASE CRT; - } - END_FOR - - request.reset(tdbb, drq_e_rel_flds, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - RFR IN RDB$RELATION_FIELDS - WITH RFR.RDB$RELATION_NAME EQ name.c_str() - { - if (!RFR.RDB$GENERATOR_NAME.NULL) - DropSequenceNode::deleteIdentity(tdbb, transaction, RFR.RDB$GENERATOR_NAME); - - ERASE RFR; - - if (!RFR.RDB$SECURITY_CLASS.NULL && - !strncmp(RFR.RDB$SECURITY_CLASS, SQL_SECCLASS_PREFIX, SQL_SECCLASS_PREFIX_LEN)) - { - deleteSecurityClass(tdbb, transaction, RFR.RDB$SECURITY_CLASS); - } - - deleteGlobalField(tdbb, transaction, RFR.RDB$FIELD_SOURCE); - } - END_FOR - - request.reset(tdbb, drq_e_view_rels, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - VR IN RDB$VIEW_RELATIONS - WITH VR.RDB$VIEW_NAME EQ name.c_str() - { - ERASE VR; - } - END_FOR - - request.reset(tdbb, drq_e_relation, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - R IN RDB$RELATIONS - WITH R.RDB$RELATION_NAME EQ name.c_str() - { - ERASE R; - - if (!R.RDB$SECURITY_CLASS.NULL && - !strncmp(R.RDB$SECURITY_CLASS, SQL_SECCLASS_PREFIX, SQL_SECCLASS_PREFIX_LEN)) - { - deleteSecurityClass(tdbb, transaction, R.RDB$SECURITY_CLASS); - } - } - END_FOR - - if (!found) - { - // msg 61: "Relation not found" - status_exception::raise(Arg::PrivateDyn(61)); - } - - // Triggers must be deleted after check constraints - - MetaName triggerName; - - request.reset(tdbb, drq_e_trigger2, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - X IN RDB$TRIGGERS - WITH X.RDB$RELATION_NAME EQ name.c_str() - { - triggerName = X.RDB$TRIGGER_NAME; - ERASE X; - - AutoCacheRequest request2(tdbb, drq_e_trg_prv, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) - PRIV IN RDB$USER_PRIVILEGES - WITH PRIV.RDB$USER EQ triggerName.c_str() AND - PRIV.RDB$USER_TYPE = obj_trigger AND - PRIV.RDB$GRANTOR NOT MISSING - { - ERASE PRIV; - } - END_FOR - } - END_FOR - - request.reset(tdbb, drq_e_usr_prvs, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - PRIV IN RDB$USER_PRIVILEGES - WITH PRIV.RDB$RELATION_NAME EQ name.c_str() AND - PRIV.RDB$OBJECT_TYPE = obj_relation AND - PRIV.RDB$GRANTOR NOT MISSING - { - ERASE PRIV; - } - END_FOR - - request.reset(tdbb, drq_e_view_prv, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - PRIV IN RDB$USER_PRIVILEGES - WITH PRIV.RDB$USER EQ name.c_str() AND - PRIV.RDB$USER_TYPE = obj_view AND - PRIV.RDB$GRANTOR NOT MISSING - { - ERASE PRIV; - } - END_FOR - - // Drop table from all publications - - request.reset(tdbb, drq_e_pub_tab_all, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - PTAB IN RDB$PUBLICATION_TABLES - WITH PTAB.RDB$TABLE_NAME EQ name.c_str() - { - ERASE PTAB; - } - END_FOR - - if (found) - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, ddlTriggerAction, name, NULL); - else - { - // msg 61: "Relation not found" - status_exception::raise(Arg::PrivateDyn(61)); - } - - savePoint.release(); // everything is ok - - METD_drop_relation(transaction, name.c_str()); - MET_dsql_cache_release(tdbb, SYM_relation, name); + dropRelation(tdbb, dsqlScratch, transaction, view, rel_drop); } diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index be36e6e1fe9..6415d652f03 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -1642,6 +1642,8 @@ class DropRelationNode : public DdlNode static void deleteGlobalField(thread_db* tdbb, jrd_tra* transaction, const MetaName& globalName); + static void dropRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, bool view, jrd_rel* rel_drop); + public: virtual Firebird::string internalPrint(NodePrinter& printer) const; virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction); diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index 9824771c81a..afa3ccd688b 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -276,7 +276,7 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat SLONG total = 0; // Find all indices - requestHandle.reset(tdbb, irq_ts_drop_idx_dfw, DYN_REQUESTS); + requestHandle.reset(tdbb, drq_ts_drop_idx_dfw, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) X IN RDB$INDICES @@ -300,7 +300,7 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat END_FOR // Find all tables - requestHandle.reset(tdbb, irq_ts_drop_rel_dfw, DYN_REQUESTS); + requestHandle.reset(tdbb, drq_ts_drop_rel_dfw, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) X IN RDB$RELATIONS @@ -308,7 +308,12 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat { if (dropDependencies) { - ERASE X; + MetaName relationName(X.RDB$RELATION_NAME); + jrd_rel* rel_drop = MET_lookup_relation(tdbb, relationName); + if (rel_drop) + MET_scan_relation(tdbb, rel_drop); + + DropRelationNode::dropRelation(tdbb, dsqlScratch, transaction, false, rel_drop); } else { diff --git a/src/jrd/drq.h b/src/jrd/drq.h index 69674b53fd5..30b189581cd 100644 --- a/src/jrd/drq.h +++ b/src/jrd/drq.h @@ -257,6 +257,8 @@ enum drq_type_t drq_l_pub_rel_name, // lookup relation by name drq_l_pub_all_rels, // iterate through all user relations drq_e_pub_tab_all, // erase relation from all publication + drq_ts_drop_idx_dfw, // find index of tablespace in dfw for drop + drq_ts_drop_rel_dfw, // find relation of tablespace in dfw for drop drq_MAX }; diff --git a/src/jrd/irq.h b/src/jrd/irq.h index 0d65887cf4a..fbf49e8eb93 100644 --- a/src/jrd/irq.h +++ b/src/jrd/irq.h @@ -190,10 +190,6 @@ enum irq_type_t irq_list_ts_files, // list tablespace files irq_find_ts_dfw, // find tablespace options by name in dfw irq_find_ts_dfw0, // find tablespace options by name in dfw for cleanup - irq_ts_find_rel_dfw, // find relation of tablespace in dfw for check - irq_ts_drop_rel_dfw, // find relation of tablespace in dfw for drop - irq_ts_find_idx_dfw, // find index of tablespace in dfw for check - irq_ts_drop_idx_dfw, // find index of tablespace in dfw for drop irq_scan_ts, // scn tablespaces irq_ts_security, // verify security for tablespace irq_r_pages2, From 390547ad10268ca895df10a455795bae7418ed44 Mon Sep 17 00:00:00 2001 From: Roman Simakov Date: Wed, 17 Jun 2020 10:04:53 +0300 Subject: [PATCH 06/97] Now we get tablespace before operations on index data and by the moment of usage have the page space in the pace space manager. Also the same behaviour has been ported to the expression index handling. --- src/jrd/cch.cpp | 4 ++-- src/jrd/dfw.epp | 19 ++++++++++++++----- src/jrd/met.epp | 4 ++-- src/jrd/pag.cpp | 4 +++- src/jrd/pag.h | 10 ++++++++++ 5 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/jrd/cch.cpp b/src/jrd/cch.cpp index f6b0c9d0e2e..7fb1b4984b5 100644 --- a/src/jrd/cch.cpp +++ b/src/jrd/cch.cpp @@ -3127,8 +3127,8 @@ static void check_precedence(thread_db* tdbb, WIN* window, PageNumber page) break; default: - if ((pageSpaceId > DB_PAGE_SPACE) && (pageSpaceId < TRANS_PAGE_SPACE)) - break; // tablespace + if (PageSpace::isTablespace(pageSpaceId)) + break; fb_assert(false); return; } diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index a108d68413b..8e5830d2b93 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -2747,6 +2747,7 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* index_desc idx; MemoryPool* new_pool = NULL; MetaName tableSpace; + USHORT tableSpaceId = DB_PAGE_SPACE; SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); @@ -2769,7 +2770,15 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* relation->rel_name = REL.RDB$RELATION_NAME; } - if (IDX.RDB$INDEX_ID && IDX.RDB$STATISTICS < 0.0) + if (!IDX.RDB$TABLESPACE_NAME.NULL) + tableSpace = IDX.RDB$TABLESPACE_NAME; + else // By default index data is in tablespace of relation + if (!REL.RDB$TABLESPACE_NAME.NULL) + tableSpace = REL.RDB$TABLESPACE_NAME; + + tableSpaceId = MET_tablespace(tdbb, tableSpace)->id; + + if (IDX.RDB$INDEX_ID && IDX.RDB$STATISTICS < 0.0) { SelectivityList selectivity(*tdbb->getDefaultPool()); const USHORT localId = IDX.RDB$INDEX_ID - 1; @@ -2802,9 +2811,6 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* if (IDX.RDB$INDEX_TYPE == 1) idx.idx_flags |= idx_descending; - if (!IDX.RDB$TABLESPACE_NAME.NULL) - tableSpace = IDX.RDB$TABLESPACE_NAME; - CompilerScratch* csb = NULL; // allocate a new pool to contain the expression tree for the expression index new_pool = attachment->createPool(); @@ -3390,6 +3396,7 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ idx.idx_flags = 0; MetaName tableSpace; + USHORT tableSpaceId = DB_PAGE_SPACE; // Fetch the information necessary to create the index. On the first // time thru, check to see if the index already exists. If so, delete @@ -3416,6 +3423,8 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ if (!REL.RDB$TABLESPACE_NAME.NULL) tableSpace = REL.RDB$TABLESPACE_NAME; + tableSpaceId = MET_tablespace(tdbb, tableSpace)->id; + if (IDX.RDB$INDEX_ID && IDX.RDB$STATISTICS < 0.0) { // we need to know if this relation is temporary or not @@ -3653,7 +3662,7 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ fb_assert(work->dfw_id <= dbb->dbb_max_idx); idx.idx_id = work->dfw_id; - idx.idx_pg_space_id = MET_tablespace(tdbb, tableSpace)->id; + idx.idx_pg_space_id = tableSpaceId; SelectivityList selectivity(*tdbb->getDefaultPool()); IDX_create_index(tdbb, relation, &idx, work->dfw_name.c_str(), &work->dfw_id, transaction, selectivity); diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 83e0907ca3b..bb7611097c6 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -5608,7 +5608,7 @@ Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id) CHECK_DBB(dbb); // Check that pageSpaceId has reasonable value - fb_assert( (id > DB_PAGE_SPACE) && (id < TRANS_PAGE_SPACE) ); + fb_assert(PageSpace::isTablespace(id)); Attachment* attachment = tdbb->getAttachment(); @@ -5718,7 +5718,7 @@ Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const MetaName& tableSpaceName) status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(tableSpaceName)); // Check that pageSpaceId has reasonable value - fb_assert( (pageSpaceId > DB_PAGE_SPACE) && (pageSpaceId < TRANS_PAGE_SPACE) ); + fb_assert(PageSpace::isTablespace(pageSpaceId)); // Check that pageSpaceId is either new or is not set (else it should be found in att_tablespaces above) fb_assert( (pageSpaceId >= tsCount + 1) || !attachment->getTablespace(pageSpaceId)); diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index fe72e670a81..41a61a7292e 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -2487,6 +2487,8 @@ PageSpace* PageManager::findPageSpace(const USHORT pageSpace) const return pageSpaces[pos]; } + if (pageSpace) + return 0; } @@ -2575,7 +2577,7 @@ void PageManager::allocTableSpace(thread_db* tdbb, USHORT tableSpaceID, bool cre /*** * NOTE: PageSpaceId of Tablespaces is equal to tablespace id */ - fb_assert((tableSpaceID > DB_PAGE_SPACE) && (tableSpaceID < TRANS_PAGE_SPACE)); + fb_assert(PageSpace::isTablespace(tableSpaceID)); PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(tableSpaceID); if (!pageSpace) diff --git a/src/jrd/pag.h b/src/jrd/pag.h index ebce378777c..b67c24e6262 100644 --- a/src/jrd/pag.h +++ b/src/jrd/pag.h @@ -109,6 +109,16 @@ class PageSpace : public pool_alloc return isTemporary(pageSpaceID); } + static inline bool isTablespace(USHORT aPageSpaceID) + { + return (aPageSpaceID > DB_PAGE_SPACE) && (aPageSpaceID < TRANS_PAGE_SPACE); + } + + inline bool isTablespace() const + { + return isTablespace(pageSpaceID); + } + static inline SLONG generate(const PageSpace* Item) { return Item->pageSpaceID; From 5eeadddd20dfcb75a8ab278bd8aeb53bebe033a8 Mon Sep 17 00:00:00 2001 From: Roman Simakov Date: Sat, 20 Jun 2020 11:57:04 +0300 Subject: [PATCH 07/97] Added looking up tablespace in BTR_description after reading pagespace id --- src/jrd/btr.cpp | 6 ++++++ src/msgs/facilities2.sql | 2 +- src/msgs/messages2.sql | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index fbec3687622..5daf5644eb6 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -542,6 +542,12 @@ bool BTR_description(thread_db* tdbb, jrd_rel* relation, index_root_page* root, fb_assert(idx->idx_expression != NULL); } + if (PageSpace::isTablespace(idx->idx_pg_space_id) && + !MET_tablespace_id(tdbb, idx->idx_pg_space_id)) + { + BUGCHECK(307); // msg 307 Tablespace not found + } + return true; } diff --git a/src/msgs/facilities2.sql b/src/msgs/facilities2.sql index 08fdf8d7261..5659ab6acee 100644 --- a/src/msgs/facilities2.sql +++ b/src/msgs/facilities2.sql @@ -12,7 +12,7 @@ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUM ('2021-01-09 12:00:00', 'GBAK', 12, 410) ('2021-01-09 12:00:00', 'SQLERR', 13, 1052) ('1996-11-07 13:38:42', 'SQLWARN', 14, 613) -('2018-02-27 14:50:31', 'JRD_BUGCHK', 15, 307) +('2021-01-10 12:00:00', 'JRD_BUGCHK', 15, 308) ('2021-01-09 12:00:00', 'ISQL', 17, 200) ('2010-07-10 10:50:30', 'GSEC', 18, 105) ('2019-10-19 12:52:29', 'GSTAT', 21, 63) diff --git a/src/msgs/messages2.sql b/src/msgs/messages2.sql index b3cfc63d960..52139d47d75 100644 --- a/src/msgs/messages2.sql +++ b/src/msgs/messages2.sql @@ -3052,6 +3052,7 @@ COMMIT WORK; (NULL, 'CMP_get_desc', 'cmp.cpp', NULL, 15, 306, NULL, 'Found array data type with more than 16 dimensions', NULL, NULL); -- Do not change the arguments of the previous JRD_BUGCHK messages. -- Write the new JRD_BUGCHK messages here. +(NULL, NULL, NULL, NULL, 15, 307, NULL, 'Tablespace not found', NULL, NULL); -- ISQL ('GEN_ERR', 'errmsg', 'isql.e', NULL, 17, 0, NULL, 'Statement failed, SQLSTATE = @1', NULL, NULL); ('USAGE', 'ISQL_main', 'isql.epp', NULL, 17, 1, NULL, 'usage: isql [options] []', NULL, NULL); From bb73db9815571d2695493af71df383b1cb4d14b2 Mon Sep 17 00:00:00 2001 From: Roman Simakov Date: Fri, 17 Jul 2020 13:30:22 +0300 Subject: [PATCH 08/97] Corrupted index after altering its tablespace The recent change added a couple of new fields into CreationIndex which were not initialized before fast loading while index moving. --- src/jrd/btr.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index 5daf5644eb6..67cea60e719 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -2387,6 +2387,8 @@ bool BTR_move_index(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, SLONG indexId, creation.relation = relation; //creation.sort is unused in this fast_load call //creation.transaction is unused in this fast_load call + creation.dup_recno = -1; + creation.duplicates = 0; const int nullIndLen = !(idx.idx_flags & idx_descending) && (idx.idx_count == 1) ? 1 : 0; creation.key_length = ROUNDUP(BTR_key_length(tdbb, relation, &idx) + nullIndLen, sizeof(SINT64));; From 30b58c4f36a497491519279e9c157a31aff1a8d3 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 15:56:30 +0300 Subject: [PATCH 09/97] Do not allow ALTER TABLESPACE for tables which are not commited. RDB$RELATION_ID is NULL in that case --- src/dsql/DdlNodes.epp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 5cdcafdbec3..6a19c675ee3 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -7878,6 +7878,12 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc REL IN RDB$RELATIONS WITH REL.RDB$RELATION_NAME EQ name.c_str() { + if (REL.RDB$RELATION_ID.NULL) + { + // msg 306: "Table @1 does not exist" + status_exception::raise(Arg::PrivateDyn(306) << name); + } + // RS: We need to have relation in the cache with current pageSpaceId // to copy data from it. So check it in assert. jrd_rel* rel = MET_lookup_relation_id(tdbb, REL.RDB$RELATION_ID, false); From 9bb1f425762ca53feaffa4718c3f2b064ab5ff84 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 15:57:20 +0300 Subject: [PATCH 10/97] Remove wrong line which was added accidentally during merge --- src/jrd/pag.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index 41a61a7292e..d3e2e65c3ac 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -2487,8 +2487,6 @@ PageSpace* PageManager::findPageSpace(const USHORT pageSpace) const return pageSpaces[pos]; } - if (pageSpace) - return 0; } From f8c52a855dcc39b719e77a2ef8fc2243341bcb1d Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 16:04:42 +0300 Subject: [PATCH 11/97] Fix race condition when several attachments are simultaneously finding, adding and deleting page spaces --- src/jrd/Database.cpp | 2 +- src/jrd/Database.h | 2 +- src/jrd/pag.cpp | 69 +++++++++++++++++++++++++++--------------- src/jrd/pag.h | 12 +++++--- src/jrd/validation.cpp | 2 +- 5 files changed, 55 insertions(+), 32 deletions(-) diff --git a/src/jrd/Database.cpp b/src/jrd/Database.cpp index d995cd21858..69c097d2c51 100644 --- a/src/jrd/Database.cpp +++ b/src/jrd/Database.cpp @@ -49,7 +49,7 @@ using namespace Firebird; namespace Jrd { - bool Database::onRawDevice() const + bool Database::onRawDevice() { const PageSpace* const pageSpace = dbb_page_manager.findPageSpace(DB_PAGE_SPACE); return pageSpace->onRawDevice(); diff --git a/src/jrd/Database.h b/src/jrd/Database.h index 0aef9a6bba2..8d8fd2cf9fd 100644 --- a/src/jrd/Database.h +++ b/src/jrd/Database.h @@ -546,7 +546,7 @@ class Database : public pool_alloc Firebird::InitInstance dbb_keywords_map; // returns true if primary file is located on raw device - bool onRawDevice() const; + bool onRawDevice(); // returns an unique ID string for a database file const Firebird::string& getUniqueFileId(); diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index d3e2e65c3ac..820be225393 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -2154,7 +2154,7 @@ ULONG PageSpace::actAlloc() return tot_pages; } -ULONG PageSpace::actAlloc(const Database* dbb) +ULONG PageSpace::actAlloc(Database* dbb) { PageSpace* pgSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); return pgSpace->actAlloc(); @@ -2186,7 +2186,7 @@ ULONG PageSpace::maxAlloc() return nPages; } -ULONG PageSpace::maxAlloc(const Database* dbb) +ULONG PageSpace::maxAlloc(Database* dbb) { PageSpace* pgSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); return pgSpace->maxAlloc(); @@ -2291,7 +2291,7 @@ ULONG PageSpace::lastUsedPage() return last_bit + (pipLast == pipFirst ? 0 : pipLast); } -ULONG PageSpace::lastUsedPage(const Database* dbb) +ULONG PageSpace::lastUsedPage(Database* dbb) { PageSpace* pgSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); return pgSpace->lastUsedPage(); @@ -2375,7 +2375,7 @@ ULONG PageSpace::usedPages() return used; } -ULONG PageSpace::usedPages(const Database* dbb) +ULONG PageSpace::usedPages(Database* dbb) { PageSpace* pgSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); return pgSpace->usedPages(); @@ -2470,18 +2470,24 @@ ULONG PageSpace::getSCNPageNum(ULONG sequence) const PageSpace* PageManager::addPageSpace(const USHORT pageSpaceID) { - PageSpace* newPageSpace = findPageSpace(pageSpaceID); - if (!newPageSpace) - { - newPageSpace = FB_NEW_POOL(pool) PageSpace(dbb, pageSpaceID); - pageSpaces.add(newPageSpace); + WriteLockGuard guard(pageSpacesLock, FB_FUNCTION); + + FB_SIZE_T pos; + if (pageSpaces.find(pageSpaceID, pos)) { + fb_assert(false); + return pageSpaces[pos]; } + PageSpace* newPageSpace = FB_NEW_POOL(pool) PageSpace(dbb, pageSpaceID); + pageSpaces.add(newPageSpace); + return newPageSpace; } -PageSpace* PageManager::findPageSpace(const USHORT pageSpace) const +PageSpace* PageManager::findPageSpace(const USHORT pageSpace) { + ReadLockGuard guard(pageSpacesLock, FB_FUNCTION); + FB_SIZE_T pos; if (pageSpaces.find(pageSpace, pos)) { return pageSpaces[pos]; @@ -2492,6 +2498,8 @@ PageSpace* PageManager::findPageSpace(const USHORT pageSpace) const void PageManager::delPageSpace(const USHORT pageSpace) { + WriteLockGuard guard(pageSpacesLock, FB_FUNCTION); + FB_SIZE_T pos; if (pageSpaces.find(pageSpace, pos)) { @@ -2577,28 +2585,41 @@ void PageManager::allocTableSpace(thread_db* tdbb, USHORT tableSpaceID, bool cre */ fb_assert(PageSpace::isTablespace(tableSpaceID)); - PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(tableSpaceID); - if (!pageSpace) + if (!findPageSpace(tableSpaceID)) { Firebird::MutexLockGuard guard(initTmpMtx, FB_FUNCTION); + // Double check if someone concurrently have added the tablespaceid - if (pageSpace = dbb->dbb_page_manager.findPageSpace(tableSpaceID)) + if (findPageSpace(tableSpaceID)) return; - pageSpace = dbb->dbb_page_manager.addPageSpace(tableSpaceID); - if (create) + + PageSpace* newPageSpace = FB_NEW_POOL(pool) PageSpace(dbb, tableSpaceID); + + try { - pageSpace->file = PIO_create(tdbb, fileName, false, false); - PAG_format_pip(tdbb, *pageSpace); + if (create) + { + newPageSpace->file = PIO_create(tdbb, fileName, false, false); + PAG_format_pip(tdbb, *newPageSpace); + } + else + { + newPageSpace->file = PIO_open(tdbb, fileName, fileName); + newPageSpace->pipFirst = FIRST_PIP_PAGE; + newPageSpace->scnFirst = FIRST_SCN_PAGE; + } + + if (dbb->dbb_flags & (DBB_force_write | DBB_no_fs_cache)) + PIO_force_write(newPageSpace->file, dbb->dbb_flags & DBB_force_write, dbb->dbb_flags & DBB_no_fs_cache); } - else + catch (...) { - pageSpace->file = PIO_open(tdbb, fileName, fileName); - pageSpace->pipFirst = FIRST_PIP_PAGE; - pageSpace->scnFirst = FIRST_SCN_PAGE; + delete newPageSpace; + throw; } - if (dbb->dbb_flags & (DBB_force_write | DBB_no_fs_cache)) - PIO_force_write(pageSpace->file, dbb->dbb_flags & DBB_force_write, dbb->dbb_flags & DBB_no_fs_cache); - + + WriteLockGuard writeGuard(pageSpacesLock, FB_FUNCTION); + pageSpaces.add(newPageSpace); } } diff --git a/src/jrd/pag.h b/src/jrd/pag.h index b67c24e6262..6f2958dc71f 100644 --- a/src/jrd/pag.h +++ b/src/jrd/pag.h @@ -37,6 +37,7 @@ #include "../include/fb_blk.h" #include "../common/classes/array.h" #include "../common/classes/locks.h" +#include "../common/classes/rwlock.h" #include "../jrd/ods.h" #include "../jrd/lls.h" @@ -126,19 +127,19 @@ class PageSpace : public pool_alloc // how many pages allocated ULONG actAlloc(); - static ULONG actAlloc(const Database* dbb); + static ULONG actAlloc(Database* dbb); // number of last allocated page ULONG maxAlloc(); - static ULONG maxAlloc(const Database* dbb); + static ULONG maxAlloc(Database* dbb); // number of last used page ULONG lastUsedPage(); - static ULONG lastUsedPage(const Database* dbb); + static ULONG lastUsedPage(Database* dbb); // number of used pages ULONG usedPages(); - static ULONG usedPages(const Database* dbb); + static ULONG usedPages(Database* dbb); // extend page space bool extend(thread_db*, const ULONG, const bool); @@ -180,7 +181,7 @@ class PageManager : public pool_alloc delete pageSpaces.pop(); } - PageSpace* findPageSpace(const USHORT pageSpaceID) const; + PageSpace* findPageSpace(const USHORT pageSpaceID); void initTempPageSpace(thread_db* tdbb); USHORT getTempPageSpaceID(thread_db* tdbb); @@ -204,6 +205,7 @@ class PageManager : public pool_alloc Database* dbb; PageSpaceArray pageSpaces; + Firebird::RWLock pageSpacesLock; Firebird::MemoryPool& pool; Firebird::Mutex initTmpMtx; USHORT tempPageSpaceID; diff --git a/src/jrd/validation.cpp b/src/jrd/validation.cpp index 0856cbc01e5..8a9c094c230 100644 --- a/src/jrd/validation.cpp +++ b/src/jrd/validation.cpp @@ -1233,7 +1233,7 @@ Validation::FETCH_CODE Validation::fetch_page(bool mark, PageNumber page_number, } const int pageSpaceId = page_number.getPageSpaceID(); - const PageManager& pageMgr = dbb->dbb_page_manager; + PageManager& pageMgr = dbb->dbb_page_manager; const PageSpace* pageSpace = pageMgr.findPageSpace(pageSpaceId); vdr_max_page[pageSpaceId] = MAX(vdr_max_page[pageSpaceId], page_number.getPageNum()); From 09b9ae709c2537167db6bad4a3dbf34fdc5cfcc2 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 16:05:14 +0300 Subject: [PATCH 12/97] Remove assertion which is wrong because pageSpace is NULL during tablespace creation Page space should be added into pageSpaces array after creating/opening of tablespace file to prevent other attachments from getting incomplete page space. --- src/jrd/cch.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/jrd/cch.cpp b/src/jrd/cch.cpp index 7fb1b4984b5..8b5e9cfcfb4 100644 --- a/src/jrd/cch.cpp +++ b/src/jrd/cch.cpp @@ -1811,9 +1811,7 @@ bool set_diff_page(thread_db* tdbb, BufferDesc* bdb) BackupManager* const bm = dbb->dbb_backup_manager; // Temporary pages don't write to delta and need no SCN - PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(bdb->bdb_page.getPageSpaceID()); - fb_assert(pageSpace); - if (pageSpace->isTemporary()) + if (PageSpace::isTemporary(bdb->bdb_page.getPageSpaceID())) return true; // Take backup state lock From 83630edef5bcfeed847afca4aa5a03db4f67aca1 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 16:08:38 +0300 Subject: [PATCH 13/97] Fix closing and deletion of tablespace file after DROP TABLESPACE INCLUDING CONTENTS. Deleting from tablespaces cache is implemented. --- src/dsql/TablespaceNodes.epp | 7 ++++--- src/jrd/Attachment.h | 36 ++++++++++++++++++++++++++++++++---- src/jrd/Tablespace.cpp | 7 +++++++ src/jrd/Tablespace.h | 2 ++ src/jrd/dfw.epp | 6 ++++-- src/jrd/met.epp | 30 ++++++++++++------------------ 6 files changed, 61 insertions(+), 27 deletions(-) diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index afa3ccd688b..9cf9334a486 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -248,6 +248,7 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat bool found = false; USHORT tableSpaceId = 0; + string tableSpaceFileName; AutoCacheRequest requestHandle(tdbb, drq_e_tablespace, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) @@ -256,6 +257,7 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat { found = true; tableSpaceId = X.RDB$TABLESPACE_ID; + tableSpaceFileName = X.RDB$FILE_NAME; // cache it for DFW stage MET_tablespace_id(tdbb, tableSpaceId); @@ -267,9 +269,6 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat if (!X.RDB$SECURITY_CLASS.NULL) deleteSecurityClass(tdbb, transaction, X.RDB$SECURITY_CLASS); - - if (dropDependencies) - DFW_post_work(transaction, dfw_drop_tablespace, X.RDB$FILE_NAME, tableSpaceId); } END_FOR @@ -341,6 +340,8 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat { executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_TABLESPACE, name, NULL); + + DFW_post_work(transaction, dfw_drop_tablespace, tableSpaceFileName, tableSpaceId); } savePoint.release(); // everything is ok diff --git a/src/jrd/Attachment.h b/src/jrd/Attachment.h index dbec47a1bee..20ace610fca 100644 --- a/src/jrd/Attachment.h +++ b/src/jrd/Attachment.h @@ -48,6 +48,8 @@ #include "../jrd/EngineInterface.h" #include "../jrd/sbm.h" +#include "../jrd/Tablespace.h" + #define DEBUG_LCK_LIST namespace EDS { @@ -94,7 +96,6 @@ namespace Jrd class Function; class JrdStatement; class Validation; - class Tablespace; class Applier; @@ -636,19 +637,46 @@ class Attachment : public pool_alloc Tablespace* getTablespace(USHORT id) { - return att_tablespaces[id - 1]; + // tablespace id is started from 1 + if (id <= att_tablespaces.getCount()) + return att_tablespaces[id - 1]; + + return NULL; + } + + Tablespace* getTablespaceByName(const MetaName name) + { + Tablespace** iter = att_tablespaces.begin(); + ++iter; // skip DB_PAGE_SPACE + + for (; iter < att_tablespaces.end(); ++iter) + { + Tablespace* const tablespace = *iter; + + if (tablespace && tablespace->name == name) + return tablespace; + } + + return NULL; } void setTablespace(USHORT id, Tablespace* value) { if (id > att_tablespaces.getCount()) att_tablespaces.grow(id); + + fb_assert(!att_tablespaces[id - 1]); att_tablespaces[id - 1] = value; } - USHORT getTablespaceCount() const + void delTablespace(USHORT id) { - return att_tablespaces.getCount(); + if (id <= att_tablespaces.getCount()) + { + Tablespace* tablespaceToDelete = att_tablespaces[id - 1]; + att_tablespaces[id - 1] = NULL; + delete tablespaceToDelete; + } } UserId* getUserId(const Firebird::MetaString& userName); diff --git a/src/jrd/Tablespace.cpp b/src/jrd/Tablespace.cpp index 0935dbaadf0..94a02a504ca 100644 --- a/src/jrd/Tablespace.cpp +++ b/src/jrd/Tablespace.cpp @@ -28,6 +28,13 @@ using namespace Firebird; namespace Jrd { +Tablespace::~Tablespace() +{ + fb_assert(useCount == 0); + delete existenceLock; + existenceLock = NULL; +} + void Tablespace::addRef(thread_db *tdbb) { useCount++; diff --git a/src/jrd/Tablespace.h b/src/jrd/Tablespace.h index f4e3550722d..484e51dc27e 100644 --- a/src/jrd/Tablespace.h +++ b/src/jrd/Tablespace.h @@ -47,6 +47,8 @@ namespace Jrd { } + ~Tablespace(); + USHORT id; // tablespace id = pagespace id MetaName name; // tablespace name Lock* existenceLock; // existence lock, if any diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 8e5830d2b93..5ecd0320010 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -6566,8 +6566,6 @@ static bool drop_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, j { raiseObjectInUseError("TABLESPACE", tablespace->name.c_str()); } - // Probably here we need to remove the cache tablespace from attachment. Need to think... - // Also it's necessary to close open file descriptor of the tablespace } return true; @@ -6575,9 +6573,13 @@ static bool drop_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, j case 3: return true; case 4: + dbb->dbb_page_manager.delPageSpace(work->dfw_id); + if (tablespace->existenceLock) LCK_release(tdbb, tablespace->existenceLock); + attachment->delTablespace(work->dfw_id); + break; } diff --git a/src/jrd/met.epp b/src/jrd/met.epp index bb7611097c6..44da14e57ba 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -5612,17 +5612,12 @@ Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id) Attachment* attachment = tdbb->getAttachment(); - const USHORT tsCount = attachment->getTablespaceCount(); + Tablespace* ts = attachment->getTablespace(id); - // tablespace id is started from 1 - if (id <= tsCount) + if (ts) { - Tablespace* ts = attachment->getTablespace(id); - if (ts) - { - fb_assert(ts->id == id); - return ts; - } + fb_assert(ts->id == id); + return ts; } // Now we need to find tablespace in system table @@ -5646,7 +5641,7 @@ Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id) status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(tableSpaceName)); // Check that pageSpaceId is either new or is not set (else it should be found in att_tablespaces above) - fb_assert( (id >= tsCount + 1) || !attachment->getTablespace(id)); + fb_assert(!attachment->getTablespace(id)); dbb->dbb_page_manager.allocTableSpace(tdbb, id, false, file); @@ -5688,14 +5683,13 @@ Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const MetaName& tableSpaceName) if (tableSpaceName.isEmpty()) return attachment->getTablespace(DB_PAGE_SPACE); - const USHORT tsCount = attachment->getTablespaceCount(); + Tablespace* ts = attachment->getTablespaceByName(tableSpaceName); - for (USHORT i = 2; i <= tsCount; i++) - { - Tablespace* ts = attachment->getTablespace(i); - if (ts && (ts->name == tableSpaceName) ) - return ts; - } + if (ts) + { + fb_assert(ts->name == tableSpaceName); + return ts; + } // Now we need to find tablespace in system table AutoCacheRequest request(tdbb, irq_find_ts, IRQ_REQUESTS); @@ -5721,7 +5715,7 @@ Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const MetaName& tableSpaceName) fb_assert(PageSpace::isTablespace(pageSpaceId)); // Check that pageSpaceId is either new or is not set (else it should be found in att_tablespaces above) - fb_assert( (pageSpaceId >= tsCount + 1) || !attachment->getTablespace(pageSpaceId)); + fb_assert(!attachment->getTablespace(pageSpaceId)); dbb->dbb_page_manager.allocTableSpace(tdbb, pageSpaceId, false, file); From e2929aa8db7ba549763b72d4a72b594362d0751c Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 16:10:11 +0300 Subject: [PATCH 14/97] Do not create tablespace file immediately at CREATE TABLESPACE to make rollback work correctly. The file will be created at DFW stage --- src/dsql/TablespaceNodes.epp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index 9cf9334a486..7a8a9e46369 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -166,8 +166,6 @@ void CreateAlterTablespaceNode::executeCreate(thread_db* tdbb, DsqlCompilerScrat } } - dbb->dbb_page_manager.allocTableSpace(tdbb, id, true, PathName(fileName.c_str())); - storePrivileges(tdbb, transaction, name, obj_tablespace, ALL_PRIVILEGES); executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_TABLESPACE, From f44a17d688eb5a1c64375f94483e4751dd0de3c5 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 16:10:31 +0300 Subject: [PATCH 15/97] Post dfw_drop_tablespace before trigger execution like in other DDL nodes --- src/dsql/TablespaceNodes.epp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index 7a8a9e46369..9dd0e51ed69 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -336,10 +336,10 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat if (found) { + DFW_post_work(transaction, dfw_drop_tablespace, tableSpaceFileName, tableSpaceId); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_TABLESPACE, name, NULL); - - DFW_post_work(transaction, dfw_drop_tablespace, tableSpaceFileName, tableSpaceId); } savePoint.release(); // everything is ok From 89b2dc266dcf2a5df2a552082078e533055dd1db Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 16:10:56 +0300 Subject: [PATCH 16/97] Do not allow to ALTER TABLESPACE for a table if the tablespace was dropped in the same transaction --- src/dsql/DdlNodes.epp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 6a19c675ee3..7d89d517ea4 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -7872,9 +7872,29 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc case Clause::TYPE_ALTER_TABLESPACE: { + const MetaName& tableSpaceName = + static_cast(i->getObject())->name; + + bool found = false; AutoRequest request; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + X IN RDB$TABLESPACES + WITH X.RDB$TABLESPACE_NAME EQ tableSpaceName.c_str() + { + found = true; + } + END_FOR + + if (!found) + { + status_exception::raise( + Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(tableSpaceName)); + } + + AutoRequest request2; + + FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) REL IN RDB$RELATIONS WITH REL.RDB$RELATION_NAME EQ name.c_str() { @@ -7895,9 +7915,6 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc status_exception::raise(Arg::PrivateDyn(311) << name); } - const MetaName& tableSpaceName = - static_cast(i->getObject())->name; - // Check if we are try to change tablespace name to the already set if ( (REL.RDB$TABLESPACE_NAME.NULL && tableSpaceName.isEmpty()) || (!REL.RDB$TABLESPACE_NAME.NULL && (tableSpaceName == REL.RDB$TABLESPACE_NAME) ) ) From d2cdd8ed7ce6c85a369ed338ba71d81f95c93273 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 16:11:44 +0300 Subject: [PATCH 17/97] Fix crash by checking existence of a relation at dfw_clear_datapages. A relation may already be deleted by dfw_delete_relation in the same transaction --- src/jrd/dfw.epp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 5ecd0320010..3d44e3a30d0 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -1642,6 +1642,11 @@ void DFW_perform_post_commit_work(thread_db* tdbb, jrd_tra* transaction) case dfw_clear_datapages: { jrd_rel* relation = MET_lookup_relation_id(tdbb, work->dfw_id, false); + + // A relation may already be deleted by dfw_delete_relation in the same transaction + if (!relation) + break; + RelationPages* relationPages = relation->getPages(tdbb); DPM_delete_relation_pages(tdbb, relation, relationPages); From 70469e6fe163fc48239c00c45bb62e42236db8ee Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 16:12:15 +0300 Subject: [PATCH 18/97] Print ID of a missing tablespace in the error message --- src/jrd/met.epp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 44da14e57ba..034143fef3b 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -5638,7 +5638,10 @@ Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id) END_FOR if (!found) + { + tableSpaceName.printf("id %d", id); status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(tableSpaceName)); + } // Check that pageSpaceId is either new or is not set (else it should be found in att_tablespaces above) fb_assert(!attachment->getTablespace(id)); From 9f1aa54dc49b6723be9e5b8645faaddb997504bf Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 16:15:14 +0300 Subject: [PATCH 19/97] Get the SR lock for a tablespace when putting it into tablespaces cache It allows to determine if there are attachments that use a tablespace (and have its page space opened) when another attachment needs the EX lock on that tablespace (for example, to execute ALTER TABLESPACE). --- src/dsql/TablespaceNodes.epp | 22 +++++++ src/jrd/JrdStatement.cpp | 8 ++- src/jrd/Tablespace.cpp | 8 +-- src/jrd/Tablespace.h | 4 +- src/jrd/dfw.epp | 71 +++++++++++++++++++--- src/jrd/met.epp | 111 +++++++++++++++++++++++++++++------ src/jrd/met_proto.h | 2 +- src/jrd/tra.cpp | 8 ++- src/jrd/tra.h | 1 + 9 files changed, 198 insertions(+), 37 deletions(-) diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index 9dd0e51ed69..d664087f52c 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -38,6 +38,7 @@ #include "../jrd/dyn_ut_proto.h" #include "../jrd/pag_proto.h" #include "../jrd/os/pio_proto.h" +#include "../jrd/lck_proto.h" using namespace Firebird; @@ -179,12 +180,31 @@ bool CreateAlterTablespaceNode::executeAlter(thread_db* tdbb, DsqlCompilerScratc Attachment* attachment = transaction->getAttachment(); AutoCacheRequest requestHandle(tdbb, drq_m_tablespace, DYN_REQUESTS); bool modified = false; + USHORT tableSpaceId = 0; FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) X IN RDB$TABLESPACES WITH X.RDB$TABLESPACE_NAME EQ name.c_str() { modified = true; + tableSpaceId = X.RDB$TABLESPACE_ID; + + fb_assert(PageSpace::isTablespace(tableSpaceId)); + + Tablespace* tablespace = MET_tablespace_id(tdbb, tableSpaceId, false); + tablespace->modified = true; + + // Get the EX lock here to prevent other attachments from using the tablespace. + // It's needed because other attachments see uncommitted changes in RDB$TABLESPACES. + // I think this solution is temporary and should be reconsidered. + if (tablespace->isUsed() || + !LCK_convert(tdbb, tablespace->existenceLock, LCK_EX, transaction->getLockWait())) + { + string obj_name; + obj_name.printf("TABLESPACE \"%s\"", name.c_str()); + + ERR_post(Arg::Gds(isc_obj_in_use) << Arg::Str(obj_name)); + } executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_TABLESPACE, name, NULL); @@ -209,6 +229,8 @@ bool CreateAlterTablespaceNode::executeAlter(thread_db* tdbb, DsqlCompilerScratc if (modified) { + DFW_post_work(transaction, dfw_modify_tablespace, NULL, tableSpaceId); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_TABLESPACE, name, NULL); } diff --git a/src/jrd/JrdStatement.cpp b/src/jrd/JrdStatement.cpp index 95e053b9469..17a70583d56 100644 --- a/src/jrd/JrdStatement.cpp +++ b/src/jrd/JrdStatement.cpp @@ -164,7 +164,7 @@ JrdStatement::JrdStatement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb) { // Tablespace is locking after the use in relation and indices. // Should we check it here again? - tdbb->getAttachment()->getTablespace(i)->addRef(tdbb); + MET_tablespace_id(tdbb, i)->addRef(tdbb); } // make a vector of all used RSEs @@ -662,7 +662,11 @@ void JrdStatement::release(thread_db* tdbb) { // Tablespace is locking after the use in relation and indices. // Should we check it here again? - tdbb->getAttachment()->getTablespace(i)->release(tdbb); + Tablespace* ts = tdbb->getAttachment()->getTablespace(i); + fb_assert(ts); + + if (ts) + ts->release(tdbb); } for (jrd_req** instance = requests.begin(); instance != requests.end(); ++instance) diff --git a/src/jrd/Tablespace.cpp b/src/jrd/Tablespace.cpp index 94a02a504ca..a511a066e88 100644 --- a/src/jrd/Tablespace.cpp +++ b/src/jrd/Tablespace.cpp @@ -38,18 +38,18 @@ Tablespace::~Tablespace() void Tablespace::addRef(thread_db *tdbb) { useCount++; - if (useCount == 1) + /*if (useCount == 1) { LCK_lock(tdbb, existenceLock, LCK_SR, LCK_WAIT); - } + }*/ } void Tablespace::release(thread_db *tdbb) { - if (useCount == 1) + /*if (useCount == 1) { LCK_release(tdbb, existenceLock); - } + }*/ useCount--; } diff --git a/src/jrd/Tablespace.h b/src/jrd/Tablespace.h index 484e51dc27e..0ca411d2f5c 100644 --- a/src/jrd/Tablespace.h +++ b/src/jrd/Tablespace.h @@ -43,6 +43,7 @@ namespace Jrd id(INVALID_PAGE_SPACE), name(p), existenceLock(NULL), + modified(false), useCount(0) { } @@ -51,7 +52,8 @@ namespace Jrd USHORT id; // tablespace id = pagespace id MetaName name; // tablespace name - Lock* existenceLock; // existence lock, if any + Lock* existenceLock; // existence lock, if any + bool modified; private: int useCount; diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 3d44e3a30d0..98548eebf0c 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -492,6 +492,7 @@ static bool change_repl_state(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool create_tablespace(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool drop_tablespace(thread_db*, SSHORT, DeferredWork*, jrd_tra*); +static bool modify_tablespace(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool move_relation(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool move_index(thread_db*, SSHORT, DeferredWork*, jrd_tra*); @@ -1246,6 +1247,7 @@ static const deferred_task task_table[] = { dfw_create_tablespace, create_tablespace }, { dfw_drop_tablespace, drop_tablespace }, + { dfw_modify_tablespace, modify_tablespace }, { dfw_move_relation, move_relation }, { dfw_move_index, move_index }, @@ -6553,21 +6555,19 @@ static bool drop_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, j // We assume the tablespace must exists if dfw with has added fb_assert(tablespace); + fb_assert(tablespace->existenceLock); switch (phase) { case 0: - if ( tablespace->existenceLock && tablespace->isUsed() ) - LCK_convert(tdbb, tablespace->existenceLock, LCK_SR, transaction->getLockWait()); + LCK_convert(tdbb, tablespace->existenceLock, LCK_SR, transaction->getLockWait()); return false; case 1: { // Make sure that nobody uses the tablespace - if ( tablespace->isUsed() || // RS: if isUsed maybe I must try to convert SR to EX? - (tablespace->existenceLock && - !LCK_lock(tdbb, tablespace->existenceLock, LCK_EX, transaction->getLockWait()) ) - ) + if (tablespace->isUsed() || + !LCK_convert(tdbb, tablespace->existenceLock, LCK_EX, transaction->getLockWait())) { raiseObjectInUseError("TABLESPACE", tablespace->name.c_str()); } @@ -6580,8 +6580,63 @@ static bool drop_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, j case 4: dbb->dbb_page_manager.delPageSpace(work->dfw_id); - if (tablespace->existenceLock) - LCK_release(tdbb, tablespace->existenceLock); + LCK_release(tdbb, tablespace->existenceLock); + + attachment->delTablespace(work->dfw_id); + + break; + } + + return false; +} + +static bool modify_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction) +{ +/************************************** + * + * m o d i f y _ t a b l e s p a c e + * + ************************************** + * + * Functional description + * Modify tablespace + * + **************************************/ + + SET_TDBB(tdbb); + Database* dbb = tdbb->getDatabase(); + Attachment* attachment = tdbb->getAttachment(); + + Tablespace* tablespace = attachment->getTablespace(work->dfw_id); + + // We assume the tablespace must exists if dfw with has added + fb_assert(tablespace); + fb_assert(tablespace->existenceLock); + + switch (phase) + { + case 0: + LCK_convert(tdbb, tablespace->existenceLock, LCK_SR, transaction->getLockWait()); + return false; + + case 1: + { + // Make sure that nobody uses the tablespace + if (tablespace->isUsed() || + !LCK_convert(tdbb, tablespace->existenceLock, LCK_EX, transaction->getLockWait())) + { + raiseObjectInUseError("TABLESPACE", tablespace->name.c_str()); + } + } + return true; + + case 2: + case 3: + return true; + case 4: + dbb->dbb_page_manager.delPageSpace(work->dfw_id); + + LCK_release(tdbb, tablespace->existenceLock); attachment->delTablespace(work->dfw_id); diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 034143fef3b..01ddb5b9cb7 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -5587,7 +5587,7 @@ USHORT MET_index_pagespace(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, USHORT return pageSpaceId; } -Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id) +Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id, bool open) { /************************************** * @@ -5617,6 +5617,16 @@ Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id) if (ts) { fb_assert(ts->id == id); + + // Do not allow to use tablespaces modified by ALTER TABLESPACE in the same transaction + if (ts->modified && open) + { + string name; + name.printf("TABLESPACE \"%s\"", ts->name.c_str()); + + ERR_post(Arg::Gds(isc_obj_in_use) << Arg::Str(name)); + } + return ts; } @@ -5646,18 +5656,45 @@ Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id) // Check that pageSpaceId is either new or is not set (else it should be found in att_tablespaces above) fb_assert(!attachment->getTablespace(id)); - dbb->dbb_page_manager.allocTableSpace(tdbb, id, false, file); + Tablespace* tableSpace = NULL; - Tablespace* tableSpace = FB_NEW_POOL(*attachment->att_pool) Tablespace(*attachment->att_pool); - tableSpace->id = id; - tableSpace->name = tableSpaceName; + try + { + tableSpace = FB_NEW_POOL(*attachment->att_pool) Tablespace(*attachment->att_pool); + tableSpace->id = id; + tableSpace->name = tableSpaceName; + + Lock* lock = FB_NEW_RPT(*attachment->att_pool, 0) + Lock(tdbb, sizeof(SLONG), LCK_tablespace_exist, tableSpace); + tableSpace->existenceLock = lock; + lock->setKey(tableSpace->id); + + // Get the SR lock to let other attachments know that we use the tablespace + if (!LCK_lock(tdbb, lock, LCK_SR, LCK_NO_WAIT)) + { + string name; + name.printf("TABLESPACE ID %d", id); - Lock* lock = FB_NEW_RPT(*attachment->att_pool, 0) - Lock(tdbb, sizeof(SLONG), LCK_tablespace_exist, tableSpace); - tableSpace->existenceLock = lock; - lock->setKey(tableSpace->id); - attachment->setTablespace(id, tableSpace); + ERR_post(Arg::Gds(isc_obj_in_use) << Arg::Str(name)); + } + + if (open) + dbb->dbb_page_manager.allocTableSpace(tdbb, id, false, file); + } + catch (...) + { + if (tableSpace) + { + if (tableSpace->existenceLock) + LCK_release(tdbb, tableSpace->existenceLock); + + delete tableSpace; + } + + throw; + } + attachment->setTablespace(id, tableSpace); return tableSpace; } @@ -5691,6 +5728,16 @@ Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const MetaName& tableSpaceName) if (ts) { fb_assert(ts->name == tableSpaceName); + + // Do not allow to use tablespaces modified by ALTER TABLESPACE in the same transaction + if (ts->modified) + { + string name; + name.printf("TABLESPACE \"%s\"", ts->name.c_str()); + + ERR_post(Arg::Gds(isc_obj_in_use) << Arg::Str(name)); + } + return ts; } @@ -5720,18 +5767,44 @@ Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const MetaName& tableSpaceName) // Check that pageSpaceId is either new or is not set (else it should be found in att_tablespaces above) fb_assert(!attachment->getTablespace(pageSpaceId)); - dbb->dbb_page_manager.allocTableSpace(tdbb, pageSpaceId, false, file); + Tablespace* tableSpace = NULL; - Tablespace* tableSpace = FB_NEW_POOL(*attachment->att_pool) Tablespace(*attachment->att_pool); - tableSpace->id = pageSpaceId; - tableSpace->name = tableSpaceName; + try + { + tableSpace = FB_NEW_POOL(*attachment->att_pool) Tablespace(*attachment->att_pool); + tableSpace->id = pageSpaceId; + tableSpace->name = tableSpaceName; + + Lock* lock = FB_NEW_RPT(*attachment->att_pool, 0) + Lock(tdbb, sizeof(SLONG), LCK_tablespace_exist, tableSpace); + tableSpace->existenceLock = lock; + lock->setKey(tableSpace->id); + + // Get the SR lock to let other attachments know that we use the tablespace + if (!LCK_lock(tdbb, lock, LCK_SR, LCK_NO_WAIT)) + { + string name; + name.printf("TABLESPACE \"%s\"", tableSpaceName.c_str()); - Lock* lock = FB_NEW_RPT(*attachment->att_pool, 0) - Lock(tdbb, sizeof(SLONG), LCK_tablespace_exist, tableSpace); - tableSpace->existenceLock = lock; - lock->setKey(tableSpace->id); - attachment->setTablespace(pageSpaceId, tableSpace); + ERR_post(Arg::Gds(isc_obj_in_use) << Arg::Str(name)); + } + + dbb->dbb_page_manager.allocTableSpace(tdbb, pageSpaceId, false, file); + } + catch (...) + { + if (tableSpace) + { + if (tableSpace->existenceLock) + LCK_release(tdbb, tableSpace->existenceLock); + + delete tableSpace; + } + + throw; + } + attachment->setTablespace(pageSpaceId, tableSpace); return tableSpace; } diff --git a/src/jrd/met_proto.h b/src/jrd/met_proto.h index 59eecc0351e..f1add958d67 100644 --- a/src/jrd/met_proto.h +++ b/src/jrd/met_proto.h @@ -146,7 +146,7 @@ Nullable MET_get_ss_definer(Jrd::thread_db*); USHORT MET_rel_pagespace(Jrd::thread_db* tdbb, USHORT rel_id); USHORT MET_index_pagespace(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, USHORT idx_id); -Jrd::Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id); +Jrd::Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id, bool open = true); Jrd::Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const Jrd::MetaName& tableSpaceName); void MET_ts_files(Jrd::thread_db* tdbb, Firebird::ObjectsArray &files); void MET_scan_tablespaces(Jrd::thread_db*); diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index 4a43b695af2..f3a539b5b56 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -1011,7 +1011,7 @@ void TRA_post_resources(thread_db* tdbb, jrd_tra* transaction, ResourceList& res { // Tablespace is locking after the use in relation and indices. // Should we check it here again? - tdbb->getAttachment()->getTablespace(i)->addRef(tdbb); + MET_tablespace_id(tdbb, i)->addRef(tdbb); } } @@ -1288,7 +1288,11 @@ void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction, Jrd::TraceTr { // Tablespace is locking after the use in relation and indices. // Should we check it here again? - tdbb->getAttachment()->getTablespace(i)->release(tdbb); + Tablespace* ts = tdbb->getAttachment()->getTablespace(i); + fb_assert(ts); + + if (ts) + ts->release(tdbb); } { // scope diff --git a/src/jrd/tra.h b/src/jrd/tra.h index 9b828a2ffcb..83a7d466ae0 100644 --- a/src/jrd/tra.h +++ b/src/jrd/tra.h @@ -514,6 +514,7 @@ enum dfw_t { dfw_change_repl_state, dfw_create_tablespace, dfw_drop_tablespace, + dfw_modify_tablespace, dfw_move_relation, dfw_move_index, dfw_clear_datapages, From b709ae13cbf829e92a4ebc1b685f10d03878f5a9 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 16:15:35 +0300 Subject: [PATCH 20/97] Do not try to find a tablespace during ALTER TABLE DROP TABLESPACE to make it work correctly --- src/dsql/DdlNodes.epp | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 7d89d517ea4..78d15429ca7 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -7875,21 +7875,24 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc const MetaName& tableSpaceName = static_cast(i->getObject())->name; - bool found = false; - AutoRequest request; - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - X IN RDB$TABLESPACES - WITH X.RDB$TABLESPACE_NAME EQ tableSpaceName.c_str() + if (!tableSpaceName.isEmpty()) { - found = true; - } - END_FOR + bool found = false; + AutoRequest request; - if (!found) - { - status_exception::raise( - Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(tableSpaceName)); + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + X IN RDB$TABLESPACES + WITH X.RDB$TABLESPACE_NAME EQ tableSpaceName.c_str() + { + found = true; + } + END_FOR + + if (!found) + { + status_exception::raise( + Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(tableSpaceName)); + } } AutoRequest request2; From ca7a668e91a1d236d6b5ba770f7bc93c0297954d Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 16:16:18 +0300 Subject: [PATCH 21/97] Avoid assertion failure in ~thread_db() when opening of a tablespace file containing an index is unsuccessful --- src/jrd/btr.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index 67cea60e719..ac5cf23969f 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -372,10 +372,19 @@ USHORT BTR_all(thread_db* tdbb, jrd_rel* relation, IndexDescAlloc** csb_idx, Rel index_desc* buffer = (*csb_idx)->items; USHORT count = 0; - for (USHORT i = 0; i < root->irt_count; i++) + + try { - if (BTR_description(tdbb, relation, root, &buffer[count], i)) - count++; + for (USHORT i = 0; i < root->irt_count; i++) + { + if (BTR_description(tdbb, relation, root, &buffer[count], i)) + count++; + } + } + catch (...) + { + CCH_RELEASE(tdbb, &window); + throw; } CCH_RELEASE(tdbb, &window); From 72a92fb9fcab04ff4e8ed1d8a13332b3c89a8d6d Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 16:16:56 +0300 Subject: [PATCH 22/97] Flush DB pages before closing a tablespace file. It prevents server crash while trying to write dirty pages of closed tablespace to disk --- src/jrd/dfw.epp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 98548eebf0c..a0190872d69 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -6578,6 +6578,7 @@ static bool drop_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, j case 3: return true; case 4: + CCH_flush(tdbb, FLUSH_ALL, 0); dbb->dbb_page_manager.delPageSpace(work->dfw_id); LCK_release(tdbb, tablespace->existenceLock); @@ -6634,6 +6635,7 @@ static bool modify_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, case 3: return true; case 4: + CCH_flush(tdbb, FLUSH_ALL, 0); dbb->dbb_page_manager.delPageSpace(work->dfw_id); LCK_release(tdbb, tablespace->existenceLock); From df16a6e733192e930461913d3ae4b72cfd00dac6 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 16:17:23 +0300 Subject: [PATCH 23/97] Do not allow to ALTER TABLESPACE for an index if the tablespace was dropped in the same transaction --- src/dsql/DdlNodes.epp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 78d15429ca7..57c8e305275 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -10096,6 +10096,23 @@ void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, MODIFY IDX if (op == OP_ALTER_TABLESPACE) { + bool ts_found = false; + AutoRequest request2; + + FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) + X IN RDB$TABLESPACES + WITH X.RDB$TABLESPACE_NAME EQ tableSpace.c_str() + { + ts_found = true; + } + END_FOR + + if (!ts_found) + { + status_exception::raise( + Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(tableSpace)); + } + IDX.RDB$TABLESPACE_NAME.NULL = FALSE; strcpy(IDX.RDB$TABLESPACE_NAME, tableSpace.c_str()); } From c8c98763961aea6c7fac24f5dae99d70d7db0526 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 16:18:03 +0300 Subject: [PATCH 24/97] Do not move index pages when the index is deleted in the same transaction --- src/jrd/dfw.epp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index a0190872d69..6bc035e7602 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -6801,7 +6801,10 @@ static bool move_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tr break; } - fb_assert(relation); + // An index may be deleted in the same transaction. + // Don't move index pages in this case. + if (!relation) + break; const USHORT newPageSpaceId = MET_tablespace(tdbb, tableSpace)->id; From 936f2ddbd54916e91e55394c3ee83d0ddc011b9e Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 13 May 2021 17:54:15 +0300 Subject: [PATCH 25/97] Fix build --- src/jrd/os/win32/winnt.cpp | 2 +- src/jrd/pag.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jrd/os/win32/winnt.cpp b/src/jrd/os/win32/winnt.cpp index e1f2b5f2bbd..95ba0a59ad3 100644 --- a/src/jrd/os/win32/winnt.cpp +++ b/src/jrd/os/win32/winnt.cpp @@ -792,7 +792,7 @@ ULONG PIO_get_number_of_pages(const jrd_file* file, const USHORT pagesize) bool PIO_file_exists(const Firebird::PathName& fileName) { - const FILE_DESC fd = CreateFile(fileName.c_str(), GENERIC_READ, FILE_SHARE_READ, + const HANDLE fd = CreateFile(fileName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (fd == INVALID_HANDLE_VALUE) return false; diff --git a/src/jrd/pag.h b/src/jrd/pag.h index 6f2958dc71f..1cdc2b2522b 100644 --- a/src/jrd/pag.h +++ b/src/jrd/pag.h @@ -187,6 +187,7 @@ class PageManager : public pool_alloc USHORT getTempPageSpaceID(thread_db* tdbb); void allocTableSpace(thread_db* tdbb, USHORT tableSpaceID, bool create, const Firebird::PathName& fileName); + void delPageSpace(const USHORT pageSpaceID); void closeAll(); @@ -201,7 +202,6 @@ class PageManager : public pool_alloc USHORT, PageSpace> PageSpaceArray; PageSpace* addPageSpace(const USHORT pageSpaceID); - void delPageSpace(const USHORT pageSpaceID); Database* dbb; PageSpaceArray pageSpaces; From 7426dac5fcdb6a91457ff2d14e6d8c3c5c288844 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 14:52:52 +0300 Subject: [PATCH 26/97] Add ability to ALTER TABLESPACE for tables which are not committed --- src/dsql/DdlNodes.epp | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 2ea24e2a415..56b710a033f 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -7875,21 +7875,15 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc REL IN RDB$RELATIONS WITH REL.RDB$RELATION_NAME EQ name.c_str() { - if (REL.RDB$RELATION_ID.NULL) + if (!REL.RDB$RELATION_TYPE.NULL) { - // msg 306: "Table @1 does not exist" - status_exception::raise(Arg::PrivateDyn(306) << name); - } - - // RS: We need to have relation in the cache with current pageSpaceId - // to copy data from it. So check it in assert. - jrd_rel* rel = MET_lookup_relation_id(tdbb, REL.RDB$RELATION_ID, false); - fb_assert(rel); + ULONG flags = MET_get_rel_flags_from_TYPE(REL.RDB$RELATION_TYPE); - if (rel->isTemporary()) - { - // msg 311: "Cannot alter tablespace for temporary table @1" - status_exception::raise(Arg::PrivateDyn(311) << name); + if (flags & (REL_temp_tran | REL_temp_conn)) + { + // msg 311: "Cannot alter tablespace for temporary table @1" + status_exception::raise(Arg::PrivateDyn(311) << name); + } } // Check if we are try to change tablespace name to the already set @@ -7899,9 +7893,16 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc break; } - MODIFY REL + if (!REL.RDB$RELATION_ID.NULL) { + // RS: We need to have relation in the cache with current pageSpaceId + // to copy data from it. So check it in assert. + jrd_rel* rel = MET_lookup_relation_id(tdbb, REL.RDB$RELATION_ID, false); + fb_assert(rel); + } + MODIFY REL + { if (tableSpaceName.hasData()) { REL.RDB$TABLESPACE_NAME.NULL = FALSE; @@ -7912,9 +7913,11 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc REL.RDB$TABLESPACE_NAME.NULL = TRUE; REL.RDB$TABLESPACE_NAME[0] = 0; } - DFW_post_work(transaction, dfw_move_relation, name.c_str(), REL.RDB$RELATION_ID); } END_MODIFY + + if (!REL.RDB$RELATION_ID.NULL) + DFW_post_work(transaction, dfw_move_relation, name.c_str(), REL.RDB$RELATION_ID); } END_FOR From 75d81b301a03efa2119fc81b1a3621d0b13d13fc Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 15:00:50 +0300 Subject: [PATCH 27/97] Fix DROP TABLE for tables which are not committed --- src/dsql/DdlNodes.epp | 8 +++----- src/dsql/DdlNodes.h | 2 +- src/dsql/TablespaceNodes.epp | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 56b710a033f..e1d1e1ba6f5 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -8499,11 +8499,9 @@ void DropRelationNode::deleteGlobalField(thread_db* tdbb, jrd_tra* transaction, } -void DropRelationNode::dropRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, bool view, jrd_rel* rel_drop) +void DropRelationNode::dropRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, bool view, jrd_rel* rel_drop, const MetaName& name) { - MetaName name(rel_drop->rel_name); - - if (!view) + if (!view && rel_drop) { RelationPages* relPages = rel_drop->getBasePages(); if (!relPages->rel_pages || (relPages->rel_pages->count() == 0)) @@ -8754,7 +8752,7 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch } } - dropRelation(tdbb, dsqlScratch, transaction, view, rel_drop); + dropRelation(tdbb, dsqlScratch, transaction, view, rel_drop, name); } diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index a0d4035f27b..efc9641a5a8 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -1642,7 +1642,7 @@ class DropRelationNode : public DdlNode static void deleteGlobalField(thread_db* tdbb, jrd_tra* transaction, const MetaName& globalName); - static void dropRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, bool view, jrd_rel* rel_drop); + static void dropRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, bool view, jrd_rel* rel_drop, const MetaName& name); public: virtual Firebird::string internalPrint(NodePrinter& printer) const; diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index d664087f52c..935e741283f 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -332,7 +332,7 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat if (rel_drop) MET_scan_relation(tdbb, rel_drop); - DropRelationNode::dropRelation(tdbb, dsqlScratch, transaction, false, rel_drop); + DropRelationNode::dropRelation(tdbb, dsqlScratch, transaction, false, rel_drop, relationName); } else { From b8ef3d5fd85c86195e43c2b68cb3831d631fa4c5 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 15:02:19 +0300 Subject: [PATCH 28/97] Add some useful assertions for SR lock of tablespace --- src/jrd/dfw.epp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 44824d6bc9a..47dc4682deb 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -6567,6 +6567,7 @@ static bool drop_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, j // We assume the tablespace must exists if dfw with has added fb_assert(tablespace); fb_assert(tablespace->existenceLock); + fb_assert(tablespace->existenceLock->lck_logical != LCK_none); switch (phase) { @@ -6624,6 +6625,7 @@ static bool modify_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, // We assume the tablespace must exists if dfw with has added fb_assert(tablespace); fb_assert(tablespace->existenceLock); + fb_assert(tablespace->existenceLock->lck_logical != LCK_none); switch (phase) { From 2bc0e215315693f601e4895cfc9f41af3d5221db Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 15:03:25 +0300 Subject: [PATCH 29/97] Remove redundant code which was accidentally added during merge of tablespaces GTTs pages are released in release_temp_tables function called above. --- src/jrd/tra.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index 92477e7582d..6a97972dc23 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -1296,19 +1296,6 @@ void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction, Jrd::TraceTr ts->release(tdbb); } - { // scope - vec& rels = *attachment->att_relations; - - for (FB_SIZE_T i = 0; i < rels.count(); i++) - { - jrd_rel* relation = rels[i]; - - if (relation && (relation->rel_flags & REL_temp_tran)) - relation->delPages(tdbb, transaction->tra_number); - } - - } // end scope - // Release the locks associated with the transaction if (transaction->tra_alter_db_lock) From a2a08676c45b9a1363c26411cbcf51f0bc1d901d Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 15:04:29 +0300 Subject: [PATCH 30/97] Put a relation into cache only if opening of a tablespace file containing the relation is successful --- src/jrd/met.epp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 258b2dbb552..46d6066d302 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -3698,6 +3698,11 @@ jrd_rel* MET_relation(thread_db* tdbb, USHORT id) // reserved for system relations const USHORT max_sys_rel = USER_DEF_REL_INIT_ID - 1; + USHORT pageSpaceId = DB_PAGE_SPACE; + + if (id > max_sys_rel) + pageSpaceId = MET_rel_pagespace(tdbb, id); + relation = FB_NEW_POOL(*pool) jrd_rel(*pool); (*vector)[id] = relation; relation->rel_id = id; @@ -3729,7 +3734,6 @@ jrd_rel* MET_relation(thread_db* tdbb, USHORT id) relation->rel_flags |= (REL_check_existence | REL_check_partners); - const USHORT pageSpaceId = MET_rel_pagespace(tdbb, id); relation->setPageSpace(pageSpaceId); return relation; From ebea006be6f64082c8a2783799439726fb5b9fe1 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 15:14:21 +0300 Subject: [PATCH 31/97] Fix error messages and gbak help --- src/burp/burpswi.h | 2 +- src/dsql/DdlNodes.epp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/burp/burpswi.h b/src/burp/burpswi.h index cee0369e0d6..68b983846a9 100644 --- a/src/burp/burpswi.h +++ b/src/burp/burpswi.h @@ -225,7 +225,7 @@ static const Switches::in_sw_tab_t reference_burp_in_sw_table[] = {IN_SW_BURP_HIDDEN_RDONLY, isc_spb_res_am_readonly, "MODE READ_ONLY", 0, 0, 0, false, false, 0, 14, NULL, boRestore}, {IN_SW_BURP_HIDDEN_RDWRITE, isc_spb_res_am_readwrite, "MODE READ_WRITE", 0, 0, 0, false, false, 0, 15, NULL, boRestore}, /**************************************************************************/ - {IN_SW_BURP_TS_MAPPING_FILE, 0, "TABLESPACE_MAPPING_FILE", 0, 0, 0, false, false, 1014, 14, NULL, boRestore}, //TODO: Check message no (1014) + {IN_SW_BURP_TS_MAPPING_FILE, 0, "TABLESPACE_MAPPING_FILE", 0, 0, 0, false, false, 410, 14, NULL, boRestore}, {IN_SW_BURP_0, 0, NULL, 0, 0, 0, false, false, 0, 0, NULL, boGeneral} }; diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index e1d1e1ba6f5..fa0b3ac7c48 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -6162,7 +6162,7 @@ void RelationNode::FieldDefinition::store(thread_db* tdbb, jrd_tra* transaction) if (tableSpace.hasData()) { if (!checkObjectExist(tdbb, transaction, tableSpace, obj_tablespaces)) - status_exception::raise(Arg::PrivateDyn(310) << tableSpace.c_str()); //Tablespace @1 not found + status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << tableSpace.c_str()); RFR.RDB$TABLESPACE_NAME.NULL = FALSE; strcpy(RFR.RDB$TABLESPACE_NAME, tableSpace.c_str()); } @@ -7455,7 +7455,7 @@ void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat if (!tableSpace.isEmpty()) { if (!checkObjectExist(tdbb, transaction, tableSpace, obj_tablespaces)) - status_exception::raise(Arg::PrivateDyn(310) << tableSpace.c_str()); //Tablespace @1 not found + status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << tableSpace.c_str()); REL.RDB$TABLESPACE_NAME.NULL = FALSE; strcpy(REL.RDB$TABLESPACE_NAME, tableSpace.c_str()); } @@ -9647,7 +9647,7 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam if (definition.tableSpace.hasData()) { if (!checkObjectExist(tdbb, transaction, definition.tableSpace, obj_tablespaces)) - status_exception::raise(Arg::PrivateDyn(310) << definition.tableSpace.c_str()); //Tablespace @1 not found + status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << definition.tableSpace.c_str()); strcpy(IDX.RDB$TABLESPACE_NAME, definition.tableSpace.c_str()); } else From 31cb30e08647963b1cbd0f829cb710b3496d3e9d Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 15:16:01 +0300 Subject: [PATCH 32/97] Open a tablespace file during index deletion to fix crash when DROP INDEX is executed immediately after connect --- src/jrd/btr.cpp | 17 ++++++++++++++++- src/jrd/dfw.epp | 11 ++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index 693c318cd4f..06e2919a3a8 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -468,9 +468,24 @@ bool BTR_delete_index(thread_db* tdbb, Jrd::jrd_rel* relation, WIN* window, USHO else { index_root_page::irt_repeat* irt_desc = root->irt_rpt + id; + const USHORT pg_space_id = irt_desc->getRootPageSpaceId(); + + if (PageSpace::isTablespace(pg_space_id)) + { + try + { + MET_tablespace_id(tdbb, pg_space_id); + } + catch (...) + { + CCH_RELEASE(tdbb, window); + throw; + } + } + CCH_MARK(tdbb, window); // next is on index page space!!! - const PageNumber next(irt_desc->getRootPageSpaceId(), irt_desc->getRootPage()); + const PageNumber next(pg_space_id, irt_desc->getRootPage()); tree_exists = (irt_desc->getRootPage() != 0); // remove the pointer to the top-level index page before we delete it diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 47dc4682deb..6e323e8dead 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -4721,7 +4721,16 @@ static bool delete_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ index = CMP_get_index_lock(tdbb, relation, id); if (isTempIndex && index) index->idl_count++; - IDX_delete_index(tdbb, relation, id); + + try + { + IDX_delete_index(tdbb, relation, id); + } + catch (...) + { + index->idl_count = 0; + throw; + } if (isTempIndex) return false; From 37b8c074c87c7076ebef664fa261bb60af13896c Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 15:17:03 +0300 Subject: [PATCH 33/97] Don't call MET_tablespace function here because it's already called in the right place above --- src/jrd/dfw.epp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 6e323e8dead..c80b1cc887a 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -2874,7 +2874,7 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* { fb_assert(work->dfw_id <= dbb->dbb_max_idx); idx.idx_id = work->dfw_id; - idx.idx_pg_space_id = MET_tablespace(tdbb, tableSpace)->id; + idx.idx_pg_space_id = tableSpaceId; IDX_create_index(tdbb, relation, &idx, work->dfw_name.c_str(), &work->dfw_id, transaction, selectivity); From 7a560312166f6fa5891d12d4f96fc3e4c6fccb5e Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 15:18:49 +0300 Subject: [PATCH 34/97] Eliminate situation when an index implicitly moves from one tablespace to another after ALTER INDEX IDX INACTIVE/ACTIVE NULL or an empty string in IDX.RDB$TABLESPACE_NAME now always means that the index is in DB_PAGE_SPACE. --- src/dsql/DdlNodes.epp | 7 +++++-- src/jrd/dfw.epp | 19 ++++--------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index fa0b3ac7c48..93622b6ba46 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -9604,7 +9604,7 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam IDX.RDB$RELATION_NAME.NULL = FALSE; IDX.RDB$SYSTEM_FLAG = 0; IDX.RDB$SYSTEM_FLAG.NULL = FALSE; // Probably redundant. - IDX.RDB$TABLESPACE_NAME.NULL = FALSE; + IDX.RDB$TABLESPACE_NAME.NULL = TRUE; MetaName relationTablespace; @@ -9648,15 +9648,18 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam { if (!checkObjectExist(tdbb, transaction, definition.tableSpace, obj_tablespaces)) status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << definition.tableSpace.c_str()); + + IDX.RDB$TABLESPACE_NAME.NULL = FALSE; strcpy(IDX.RDB$TABLESPACE_NAME, definition.tableSpace.c_str()); } - else + else if (relationTablespace.hasData()) { /** * if tablespace for the index is not defined we use relation tablespace. * It's necessary to write it explicitly since later we can move relation * into another tablespace. */ + IDX.RDB$TABLESPACE_NAME.NULL = FALSE; strcpy(IDX.RDB$TABLESPACE_NAME, relationTablespace.c_str()); } diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index c80b1cc887a..de1204ff83a 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -2753,7 +2753,7 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* jrd_rel* relation = NULL; index_desc idx; MemoryPool* new_pool = NULL; - MetaName tableSpace; + USHORT tableSpaceId = DB_PAGE_SPACE; SET_TDBB(tdbb); @@ -2777,13 +2777,8 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* relation->rel_name = REL.RDB$RELATION_NAME; } - if (!IDX.RDB$TABLESPACE_NAME.NULL) - tableSpace = IDX.RDB$TABLESPACE_NAME; - else // By default index data is in tablespace of relation - if (!REL.RDB$TABLESPACE_NAME.NULL) - tableSpace = REL.RDB$TABLESPACE_NAME; - - tableSpaceId = MET_tablespace(tdbb, tableSpace)->id; + if (!IDX.RDB$TABLESPACE_NAME.NULL) + tableSpaceId = MET_tablespace(tdbb, IDX.RDB$TABLESPACE_NAME)->id; if (IDX.RDB$INDEX_ID && IDX.RDB$STATISTICS < 0.0) { @@ -3405,7 +3400,6 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ relation = NULL; idx.idx_flags = 0; - MetaName tableSpace; USHORT tableSpaceId = DB_PAGE_SPACE; // Fetch the information necessary to create the index. On the first @@ -3428,12 +3422,7 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ } if (!IDX.RDB$TABLESPACE_NAME.NULL) - tableSpace = IDX.RDB$TABLESPACE_NAME; - else // By default index data is in tablespace of relation - if (!REL.RDB$TABLESPACE_NAME.NULL) - tableSpace = REL.RDB$TABLESPACE_NAME; - - tableSpaceId = MET_tablespace(tdbb, tableSpace)->id; + tableSpaceId = MET_tablespace(tdbb, IDX.RDB$TABLESPACE_NAME)->id; if (IDX.RDB$INDEX_ID && IDX.RDB$STATISTICS < 0.0) { From e4d2d723637993c635a19ba5c683a3cb4389dcb8 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 15:27:32 +0300 Subject: [PATCH 35/97] Fix an issue when pages of indexes for GTT were allocated in DB_PAGE_SPACE --- src/jrd/btr.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index 06e2919a3a8..a54f3860f29 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -426,12 +426,16 @@ void BTR_create(thread_db* tdbb, jrd_rel* const relation = creation.relation; index_desc* const idx = creation.index; + RelationPages* const relPages = relation->getPages(tdbb); + + if (relation->isTemporary()) + idx->idx_pg_space_id = relPages->rel_pg_space_id; + // Now that the index id has been checked out, create the index. idx->idx_root = fast_load(tdbb, creation, selectivity, creation.sort); // Index is created. Go back to the index root page and update it to // point to the index. - RelationPages* const relPages = relation->getPages(tdbb); WIN window(relPages->rel_pg_space_id, relPages->rel_index_root); index_root_page* const root = (index_root_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_root); CCH_MARK(tdbb, &window); From c41c2bd8ab662d8b1e5730dd19040227982d15df Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 15:30:34 +0300 Subject: [PATCH 36/97] Add TABLESPACE DEFAULT clause to CREATE INDEX If this clause is specified, the index uses relation tablespace. If TABLESPACE name/DEFAULT is omitted, the index uses DB_PAGE_SPACE. --- src/dsql/DdlNodes.epp | 7 +++++-- src/dsql/DdlNodes.h | 5 ++++- src/dsql/parse.y | 19 +++++++++++++------ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 93622b6ba46..430f47a829e 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -9652,10 +9652,12 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam IDX.RDB$TABLESPACE_NAME.NULL = FALSE; strcpy(IDX.RDB$TABLESPACE_NAME, definition.tableSpace.c_str()); } - else if (relationTablespace.hasData()) + else if (definition.tableSpaceDefault.specified && + definition.tableSpaceDefault.value && + relationTablespace.hasData()) { /** - * if tablespace for the index is not defined we use relation tablespace. + * If TABLESPACE DEFAULT clause is specified, the index uses relation tablespace. * It's necessary to write it explicitly since later we can move relation * into another tablespace. */ @@ -10000,6 +10002,7 @@ void CreateIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, } definition.tableSpace = tableSpace; + definition.tableSpaceDefault = tableSpaceDefault; store(tdbb, transaction, name, definition); diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index efc9641a5a8..dca47e277d7 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -1748,6 +1748,7 @@ class CreateIndexNode : public DdlNode MetaName refRelation; Firebird::ObjectsArray refColumns; MetaName tableSpace; + Nullable tableSpaceDefault; }; public: @@ -1758,7 +1759,8 @@ class CreateIndexNode : public DdlNode descending(false), relation(NULL), columns(NULL), - computed(NULL) + computed(NULL), + tableSpaceDefault(false) { } @@ -1785,6 +1787,7 @@ class CreateIndexNode : public DdlNode NestConst columns; NestConst computed; MetaName tableSpace; + bool tableSpaceDefault; }; diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 30fb667951d..03c221b2171 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -1522,12 +1522,8 @@ create_clause node->relation = $6; $$ = node; } - index_definition(static_cast($7)) tablespace_name_clause - { - $$ = $7; - if ($9) - static_cast($$)->tableSpace = *$9; - } + index_definition(static_cast($7)) index_tablespace_clause(static_cast($7)) + { $$ = $7; } | FUNCTION function_clause { $$ = $2; } | PROCEDURE procedure_clause { $$ = $2; } | TABLE table_clause { $$ = $2; } @@ -1660,6 +1656,17 @@ index_definition($createIndexNode) } ; +%type index_tablespace_clause() +index_tablespace_clause($createIndexNode) + : TABLESPACE DEFAULT + { $createIndexNode->tableSpaceDefault = true; } + | tablespace_name_clause + { + if ($1) + $createIndexNode->tableSpace = *$1; + } + ; + // CREATE SHADOW %type shadow_clause From 344a61074f24104aa51f770a2d44f8bd589e6d52 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 15:55:38 +0300 Subject: [PATCH 37/97] Restore const qualifiers. Use RWLock on page spaces only if SuperServer architecture is used --- src/jrd/Database.cpp | 2 +- src/jrd/Database.h | 2 +- src/jrd/pag.cpp | 31 ++++++++++++++++++++++++++----- src/jrd/pag.h | 30 +++++++++--------------------- src/jrd/validation.cpp | 2 +- 5 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/jrd/Database.cpp b/src/jrd/Database.cpp index 66a8f2b13e1..70107785f4c 100644 --- a/src/jrd/Database.cpp +++ b/src/jrd/Database.cpp @@ -49,7 +49,7 @@ using namespace Firebird; namespace Jrd { - bool Database::onRawDevice() + bool Database::onRawDevice() const { const PageSpace* const pageSpace = dbb_page_manager.findPageSpace(DB_PAGE_SPACE); return pageSpace->onRawDevice(); diff --git a/src/jrd/Database.h b/src/jrd/Database.h index 9f633ddbce2..64a46534ced 100644 --- a/src/jrd/Database.h +++ b/src/jrd/Database.h @@ -547,7 +547,7 @@ class Database : public pool_alloc Firebird::InitInstance dbb_keywords_map; // returns true if primary file is located on raw device - bool onRawDevice(); + bool onRawDevice() const; // returns an unique ID string for a database file const Firebird::string& getUniqueFileId(); diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index f71eba6dce7..1c0c9ed5ef5 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -2155,7 +2155,7 @@ ULONG PageSpace::actAlloc() return tot_pages; } -ULONG PageSpace::actAlloc(Database* dbb) +ULONG PageSpace::actAlloc(const Database* dbb) { PageSpace* pgSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); return pgSpace->actAlloc(); @@ -2187,7 +2187,7 @@ ULONG PageSpace::maxAlloc() return nPages; } -ULONG PageSpace::maxAlloc(Database* dbb) +ULONG PageSpace::maxAlloc(const Database* dbb) { PageSpace* pgSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); return pgSpace->maxAlloc(); @@ -2292,7 +2292,7 @@ ULONG PageSpace::lastUsedPage() return last_bit + (pipLast == pipFirst ? 0 : pipLast); } -ULONG PageSpace::lastUsedPage(Database* dbb) +ULONG PageSpace::lastUsedPage(const Database* dbb) { PageSpace* pgSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); return pgSpace->lastUsedPage(); @@ -2376,7 +2376,7 @@ ULONG PageSpace::usedPages() return used; } -ULONG PageSpace::usedPages(Database* dbb) +ULONG PageSpace::usedPages(const Database* dbb) { PageSpace* pgSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); return pgSpace->usedPages(); @@ -2469,6 +2469,27 @@ ULONG PageSpace::getSCNPageNum(ULONG sequence) const return sequence * dbb->dbb_page_manager.pagesPerSCN; } + +PageManager::PageManager(Database* aDbb, Firebird::MemoryPool& aPool) : + dbb(aDbb), + pageSpaces(aPool), + pageSpacesLock(NULL), + pool(aPool) +{ + pagesPerPIP = 0; + bytesBitPIP = 0; + transPerTIP = 0; + gensPerPage = 0; + pagesPerSCN = 0; + tempPageSpaceID = 0; + tempFileCreated = false; + + if (dbb->dbb_config->getServerMode() == MODE_SUPER) + pageSpacesLock = FB_NEW_POOL(pool) RWLock(); + + addPageSpace(DB_PAGE_SPACE); +} + PageSpace* PageManager::addPageSpace(const USHORT pageSpaceID) { WriteLockGuard guard(pageSpacesLock, FB_FUNCTION); @@ -2485,7 +2506,7 @@ PageSpace* PageManager::addPageSpace(const USHORT pageSpaceID) return newPageSpace; } -PageSpace* PageManager::findPageSpace(const USHORT pageSpace) +PageSpace* PageManager::findPageSpace(const USHORT pageSpace) const { ReadLockGuard guard(pageSpacesLock, FB_FUNCTION); diff --git a/src/jrd/pag.h b/src/jrd/pag.h index 1cdc2b2522b..5881b2d92c0 100644 --- a/src/jrd/pag.h +++ b/src/jrd/pag.h @@ -127,19 +127,19 @@ class PageSpace : public pool_alloc // how many pages allocated ULONG actAlloc(); - static ULONG actAlloc(Database* dbb); + static ULONG actAlloc(const Database* dbb); // number of last allocated page ULONG maxAlloc(); - static ULONG maxAlloc(Database* dbb); + static ULONG maxAlloc(const Database* dbb); // number of last used page ULONG lastUsedPage(); - static ULONG lastUsedPage(Database* dbb); + static ULONG lastUsedPage(const Database* dbb); // number of used pages ULONG usedPages(); - static ULONG usedPages(Database* dbb); + static ULONG usedPages(const Database* dbb); // extend page space bool extend(thread_db*, const ULONG, const bool); @@ -159,29 +159,17 @@ class PageSpace : public pool_alloc class PageManager : public pool_alloc { public: - explicit PageManager(Database* aDbb, Firebird::MemoryPool& aPool) : - dbb(aDbb), - pageSpaces(aPool), - pool(aPool) - { - pagesPerPIP = 0; - bytesBitPIP = 0; - transPerTIP = 0; - gensPerPage = 0; - pagesPerSCN = 0; - tempPageSpaceID = 0; - tempFileCreated = false; - - addPageSpace(DB_PAGE_SPACE); - } + explicit PageManager(Database* aDbb, Firebird::MemoryPool& aPool); ~PageManager() { while (pageSpaces.hasData()) delete pageSpaces.pop(); + + delete pageSpacesLock; } - PageSpace* findPageSpace(const USHORT pageSpaceID); + PageSpace* findPageSpace(const USHORT pageSpaceID) const; void initTempPageSpace(thread_db* tdbb); USHORT getTempPageSpaceID(thread_db* tdbb); @@ -205,7 +193,7 @@ class PageManager : public pool_alloc Database* dbb; PageSpaceArray pageSpaces; - Firebird::RWLock pageSpacesLock; + Firebird::RWLock* pageSpacesLock; Firebird::MemoryPool& pool; Firebird::Mutex initTmpMtx; USHORT tempPageSpaceID; diff --git a/src/jrd/validation.cpp b/src/jrd/validation.cpp index 0a712e63a10..39a083a3eb6 100644 --- a/src/jrd/validation.cpp +++ b/src/jrd/validation.cpp @@ -1232,7 +1232,7 @@ Validation::FETCH_CODE Validation::fetch_page(bool mark, PageNumber page_number, } const int pageSpaceId = page_number.getPageSpaceID(); - PageManager& pageMgr = dbb->dbb_page_manager; + const PageManager& pageMgr = dbb->dbb_page_manager; const PageSpace* pageSpace = pageMgr.findPageSpace(pageSpaceId); vdr_max_page[pageSpaceId] = MAX(vdr_max_page[pageSpaceId], page_number.getPageNum()); From 035b5040ab21fdd97fbb70c2ed3ffbc8d3089625 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 16:07:11 +0300 Subject: [PATCH 38/97] 1. If TABLESPACE clause is omitted in CREATE INDEX, an index will use a relation tablespace. TABLESPACE DEFAULT clause is removed. 2. PRIMARY keyword can be used in CREATE TABLE, ALTER TABLE, CREATE INDEX, ALTER INDEX as a tablespace name if it's needed to create/move a table/index in/to the primary database file. 3. SET TABLESPACE [TO] instead of ALTER TABLESPACE in ALTER TABLE and ALTER INDEX. 4. Optional IN can be used before a tablespace name in CREATE TABLE and CREATE INDEX. 5. SET FILE [TO] instead of FILE in ALTER TABLESPACE. --- src/common/keywords.cpp | 2 +- src/dsql/DdlNodes.epp | 43 +++++++++++++------------ src/dsql/DdlNodes.h | 16 +++++----- src/dsql/parse.y | 69 ++++++++++++++++++----------------------- src/jrd/constants.h | 3 ++ 5 files changed, 65 insertions(+), 68 deletions(-) diff --git a/src/common/keywords.cpp b/src/common/keywords.cpp index fa11172186d..e57f8b5f014 100644 --- a/src/common/keywords.cpp +++ b/src/common/keywords.cpp @@ -373,7 +373,7 @@ static const TOK tokens[] = {TOK_PRECEDING, "PRECEDING", true}, {TOK_PRECISION, "PRECISION", false}, {TOK_PRESERVE, "PRESERVE", true}, - {TOK_PRIMARY, "PRIMARY", false}, + {TOK_PRIMARY, "PRIMARY", true}, {TOK_PRIOR, "PRIOR", true}, {TOK_PRIVILEGE, "PRIVILEGE", true}, {TOK_PRIVILEGES, "PRIVILEGES", true}, diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 430f47a829e..c9c7735876c 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -7452,7 +7452,7 @@ void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat REL.RDB$VIEW_SOURCE.NULL = TRUE; REL.RDB$EXTERNAL_FILE.NULL = TRUE; - if (!tableSpace.isEmpty()) + if (tableSpace.hasData() && tableSpace != PRIMARY_TABLESPACE_NAME) { if (!checkObjectExist(tdbb, transaction, tableSpace, obj_tablespaces)) status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << tableSpace.c_str()); @@ -7844,12 +7844,14 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc break; } - case Clause::TYPE_ALTER_TABLESPACE: + case Clause::TYPE_SET_TABLESPACE: { const MetaName& tableSpaceName = - static_cast(i->getObject())->name; + static_cast(i->getObject())->name; - if (!tableSpaceName.isEmpty()) + fb_assert(tableSpaceName.hasData()); + + if (tableSpaceName != PRIMARY_TABLESPACE_NAME) { bool found = false; AutoRequest request; @@ -7886,9 +7888,9 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc } } - // Check if we are try to change tablespace name to the already set - if ( (REL.RDB$TABLESPACE_NAME.NULL && tableSpaceName.isEmpty()) || - (!REL.RDB$TABLESPACE_NAME.NULL && (tableSpaceName == REL.RDB$TABLESPACE_NAME) ) ) + // Check if we are trying to change tablespace name to the already set + if ( (REL.RDB$TABLESPACE_NAME.NULL && tableSpaceName == PRIMARY_TABLESPACE_NAME) || + (!REL.RDB$TABLESPACE_NAME.NULL && tableSpaceName == REL.RDB$TABLESPACE_NAME) ) { break; } @@ -7903,7 +7905,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc MODIFY REL { - if (tableSpaceName.hasData()) + if (tableSpaceName != PRIMARY_TABLESPACE_NAME) { REL.RDB$TABLESPACE_NAME.NULL = FALSE; strcpy(REL.RDB$TABLESPACE_NAME, tableSpaceName.c_str()); @@ -9646,18 +9648,19 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam if (definition.tableSpace.hasData()) { - if (!checkObjectExist(tdbb, transaction, definition.tableSpace, obj_tablespaces)) - status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << definition.tableSpace.c_str()); + if (definition.tableSpace != PRIMARY_TABLESPACE_NAME) + { + if (!checkObjectExist(tdbb, transaction, definition.tableSpace, obj_tablespaces)) + status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << definition.tableSpace.c_str()); - IDX.RDB$TABLESPACE_NAME.NULL = FALSE; - strcpy(IDX.RDB$TABLESPACE_NAME, definition.tableSpace.c_str()); + IDX.RDB$TABLESPACE_NAME.NULL = FALSE; + strcpy(IDX.RDB$TABLESPACE_NAME, definition.tableSpace.c_str()); + } } - else if (definition.tableSpaceDefault.specified && - definition.tableSpaceDefault.value && - relationTablespace.hasData()) + else if (relationTablespace.hasData()) { /** - * If TABLESPACE DEFAULT clause is specified, the index uses relation tablespace. + * If TABLESPACE clause is omitted, the index uses relation tablespace. * It's necessary to write it explicitly since later we can move relation * into another tablespace. */ @@ -10002,7 +10005,6 @@ void CreateIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, } definition.tableSpace = tableSpace; - definition.tableSpaceDefault = tableSpaceDefault; store(tdbb, transaction, name, definition); @@ -10064,9 +10066,11 @@ void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, } else { - fb_assert(op == OP_ALTER_TABLESPACE || op == OP_DROP_TABLESPACE); + fb_assert(op == OP_SET_TABLESPACE); + fb_assert(tableSpace.hasData()); + MODIFY IDX - if (op == OP_ALTER_TABLESPACE) + if (tableSpace != PRIMARY_TABLESPACE_NAME) { bool ts_found = false; AutoRequest request2; @@ -10090,7 +10094,6 @@ void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, } else { - fb_assert(op == OP_DROP_TABLESPACE); IDX.RDB$TABLESPACE_NAME.NULL = TRUE; IDX.RDB$TABLESPACE_NAME[0] = 0; } diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index dca47e277d7..e86329a7c0d 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -1314,7 +1314,7 @@ class RelationNode : public DdlNode TYPE_DROP_CONSTRAINT, TYPE_ALTER_SQL_SECURITY, TYPE_ALTER_PUBLICATION, - TYPE_ALTER_TABLESPACE + TYPE_SET_TABLESPACE }; explicit Clause(MemoryPool& p, Type aType) @@ -1502,10 +1502,11 @@ class RelationNode : public DdlNode MetaName name; }; - struct AlterTableSpaceClause : public Clause + struct SetTableSpaceClause : public Clause { - explicit AlterTableSpaceClause(MemoryPool& p) - : Clause(p, TYPE_ALTER_TABLESPACE) + explicit SetTableSpaceClause(MemoryPool& p) + : Clause(p, TYPE_SET_TABLESPACE), + name(p) { } @@ -1748,7 +1749,6 @@ class CreateIndexNode : public DdlNode MetaName refRelation; Firebird::ObjectsArray refColumns; MetaName tableSpace; - Nullable tableSpaceDefault; }; public: @@ -1759,8 +1759,7 @@ class CreateIndexNode : public DdlNode descending(false), relation(NULL), columns(NULL), - computed(NULL), - tableSpaceDefault(false) + computed(NULL) { } @@ -1787,14 +1786,13 @@ class CreateIndexNode : public DdlNode NestConst columns; NestConst computed; MetaName tableSpace; - bool tableSpaceDefault; }; class AlterIndexNode : public DdlNode { public: - enum OP {OP_ACTIVE, OP_INACTIVE, OP_ALTER_TABLESPACE, OP_DROP_TABLESPACE}; + enum OP {OP_ACTIVE, OP_INACTIVE, OP_SET_TABLESPACE}; AlterIndexNode(MemoryPool& p, const MetaName& aName, OP aOp) : DdlNode(p), diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 03c221b2171..7c524688140 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -1522,8 +1522,13 @@ create_clause node->relation = $6; $$ = node; } - index_definition(static_cast($7)) index_tablespace_clause(static_cast($7)) - { $$ = $7; } + index_definition(static_cast($7)) tablespace_name_clause + { + if ($9) + static_cast($7)->tableSpace = *$9; + + $$ = $7; + } | FUNCTION function_clause { $$ = $2; } | PROCEDURE procedure_clause { $$ = $2; } | TABLE table_clause { $$ = $2; } @@ -1656,17 +1661,6 @@ index_definition($createIndexNode) } ; -%type index_tablespace_clause() -index_tablespace_clause($createIndexNode) - : TABLESPACE DEFAULT - { $createIndexNode->tableSpaceDefault = true; } - | tablespace_name_clause - { - if ($1) - $createIndexNode->tableSpace = *$1; - } - ; - // CREATE SHADOW %type shadow_clause @@ -4230,17 +4224,11 @@ alter_op($relationNode) newNode(RelationNode::Clause::TYPE_ALTER_PUBLICATION); $relationNode->clauses.add(clause); } - | ALTER TABLESPACE symbol_tablespace_name + | SET TABLESPACE to_opt symbol_tablespace_name { - RelationNode::AlterTableSpaceClause* clause = - newNode(); - clause->name = *$3; - $relationNode->clauses.add(clause); - } - | DROP TABLESPACE - { - RelationNode::AlterTableSpaceClause* clause = - newNode(); + RelationNode::SetTableSpaceClause* clause = + newNode(); + clause->name = *$4; $relationNode->clauses.add(clause); } ; @@ -4412,13 +4400,12 @@ drop_behaviour alter_index_clause : symbol_index_name ACTIVE { $$ = newNode(*$1, AlterIndexNode::OP_ACTIVE); } | symbol_index_name INACTIVE { $$ = newNode(*$1, AlterIndexNode::OP_INACTIVE); } - | symbol_index_name ALTER TABLESPACE symbol_tablespace_name + | symbol_index_name SET TABLESPACE to_opt symbol_tablespace_name { - AlterIndexNode* node = newNode(*$1, AlterIndexNode::OP_ALTER_TABLESPACE); - node->tableSpace = *$4; + AlterIndexNode* node = newNode(*$1, AlterIndexNode::OP_SET_TABLESPACE); + node->tableSpace = *$5; $$ = node; } - | symbol_index_name DROP TABLESPACE { $$ = newNode(*$1, AlterIndexNode::OP_DROP_TABLESPACE); } ; %type alter_udf_clause @@ -7477,6 +7464,16 @@ tablespace_clause } ; +to_opt + : // nothing + | TO + ; + +in_opt + : // nothing + | IN + ; + %type symbol_tablespace_name symbol_tablespace_name : valid_symbol_name @@ -7498,14 +7495,14 @@ tablespace_readonly_clause %type alter_tablespace_clause alter_tablespace_clause - : symbol_tablespace_name FILE utf_string tablespace_offline_clause tablespace_readonly_clause + : symbol_tablespace_name SET FILE to_opt utf_string tablespace_offline_clause tablespace_readonly_clause { $$ = newNode(*$1); $$->create = false; $$->alter = true; - $$->fileName = *$3; - $$->offline = $4; - $$->readonly = $5; + $$->fileName = *$5; + $$->offline = $6; + $$->readonly = $7; } | symbol_tablespace_name tablespace_offline_clause tablespace_readonly_clause { @@ -7528,13 +7525,8 @@ replace_tablespace_clause %type tablespace_name_clause tablespace_name_clause - : { - $$ = NULL; - } - | TABLESPACE symbol_tablespace_name - { - $$ = $2; - } + : /* nothing */ { $$ = NULL; } + | in_opt TABLESPACE symbol_tablespace_name { $$ = $3; } ; %type drop_tablespace_clause @@ -9260,6 +9252,7 @@ non_reserved_word | OFFLINE | INCLUDING | CONTENTS + | PRIMARY ; %% diff --git a/src/jrd/constants.h b/src/jrd/constants.h index 8be855cd1d9..f1cd2ea66dd 100644 --- a/src/jrd/constants.h +++ b/src/jrd/constants.h @@ -488,4 +488,7 @@ const int WITH_ADMIN_OPTION = 2; // Max length of the string returned by ERROR_TEXT context variable const USHORT MAX_ERROR_MSG_LENGTH = 1024 * METADATA_BYTES_PER_CHAR; // 1024 UTF-8 characters +// Tablespaces +const char* const PRIMARY_TABLESPACE_NAME = "PRIMARY"; + #endif // JRD_CONSTANTS_H From d1ae05e8ad95deb58989c9ba2d21415850553223 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 16:07:42 +0300 Subject: [PATCH 39/97] Use checkObjectExist() function in appropriate places --- src/dsql/DdlNodes.epp | 38 +++++--------------------------------- 1 file changed, 5 insertions(+), 33 deletions(-) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index c9c7735876c..7118b87b12f 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -7851,24 +7851,10 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc fb_assert(tableSpaceName.hasData()); - if (tableSpaceName != PRIMARY_TABLESPACE_NAME) + if (tableSpaceName != PRIMARY_TABLESPACE_NAME && + !checkObjectExist(tdbb, transaction, tableSpaceName, obj_tablespaces)) { - bool found = false; - AutoRequest request; - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - X IN RDB$TABLESPACES - WITH X.RDB$TABLESPACE_NAME EQ tableSpaceName.c_str() - { - found = true; - } - END_FOR - - if (!found) - { - status_exception::raise( - Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(tableSpaceName)); - } + status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << tableSpaceName.c_str()); } AutoRequest request2; @@ -10072,22 +10058,8 @@ void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, MODIFY IDX if (tableSpace != PRIMARY_TABLESPACE_NAME) { - bool ts_found = false; - AutoRequest request2; - - FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) - X IN RDB$TABLESPACES - WITH X.RDB$TABLESPACE_NAME EQ tableSpace.c_str() - { - ts_found = true; - } - END_FOR - - if (!ts_found) - { - status_exception::raise( - Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(tableSpace)); - } + if (!checkObjectExist(tdbb, transaction, tableSpace, obj_tablespaces)) + status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << tableSpace.c_str()); IDX.RDB$TABLESPACE_NAME.NULL = FALSE; strcpy(IDX.RDB$TABLESPACE_NAME, tableSpace.c_str()); From 9741cffeeb6f821c962154953ab838e978b20eca Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 16:08:10 +0300 Subject: [PATCH 40/97] Do not recreate an index if ALTER INDEX specifies a tablespace which already contains this index --- src/dsql/DdlNodes.epp | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 7118b87b12f..65df6d24577 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -7851,11 +7851,10 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc fb_assert(tableSpaceName.hasData()); - if (tableSpaceName != PRIMARY_TABLESPACE_NAME && - !checkObjectExist(tdbb, transaction, tableSpaceName, obj_tablespaces)) - { + const bool primary_ts = (tableSpaceName == PRIMARY_TABLESPACE_NAME); + + if (!primary_ts && !checkObjectExist(tdbb, transaction, tableSpaceName, obj_tablespaces)) status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << tableSpaceName.c_str()); - } AutoRequest request2; @@ -7875,7 +7874,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc } // Check if we are trying to change tablespace name to the already set - if ( (REL.RDB$TABLESPACE_NAME.NULL && tableSpaceName == PRIMARY_TABLESPACE_NAME) || + if ( (REL.RDB$TABLESPACE_NAME.NULL && primary_ts) || (!REL.RDB$TABLESPACE_NAME.NULL && tableSpaceName == REL.RDB$TABLESPACE_NAME) ) { break; @@ -7891,7 +7890,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc MODIFY REL { - if (tableSpaceName != PRIMARY_TABLESPACE_NAME) + if (!primary_ts) { REL.RDB$TABLESPACE_NAME.NULL = FALSE; strcpy(REL.RDB$TABLESPACE_NAME, tableSpaceName.c_str()); @@ -10055,12 +10054,21 @@ void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, fb_assert(op == OP_SET_TABLESPACE); fb_assert(tableSpace.hasData()); + const bool primary_ts = (tableSpace == PRIMARY_TABLESPACE_NAME); + + if (!primary_ts && !checkObjectExist(tdbb, transaction, tableSpace, obj_tablespaces)) + status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << tableSpace.c_str()); + + // Check if we are trying to change tablespace name to the already set + if ( (IDX.RDB$TABLESPACE_NAME.NULL && primary_ts) || + (!IDX.RDB$TABLESPACE_NAME.NULL && tableSpace == IDX.RDB$TABLESPACE_NAME) ) + { + break; + } + MODIFY IDX - if (tableSpace != PRIMARY_TABLESPACE_NAME) + if (!primary_ts) { - if (!checkObjectExist(tdbb, transaction, tableSpace, obj_tablespaces)) - status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << tableSpace.c_str()); - IDX.RDB$TABLESPACE_NAME.NULL = FALSE; strcpy(IDX.RDB$TABLESPACE_NAME, tableSpace.c_str()); } From 095034f20b7d5b705fcdb56275e421f93b6e94ac Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 16:11:12 +0300 Subject: [PATCH 41/97] Add an ability to specify a tablespace for PK, FK, UNIQUE constraints in CREATE TABLE and ALTER TABLE --- src/dsql/DdlNodes.epp | 3 +++ src/dsql/DdlNodes.h | 8 ++++++-- src/dsql/parse.y | 30 ++++++++++++++++++++++++------ 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 65df6d24577..a5b843c4cd2 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -6568,6 +6568,7 @@ void RelationNode::makeConstraint(thread_db* /*tdbb*/, DsqlCompilerScratch* dsql if (constraint.create->index && constraint.create->index->name.isEmpty()) constraint.create->index->name = constraint.name; constraint.create->columns = clause->columns; + constraint.create->tableSpace = clause->tableSpace; break; } @@ -6686,6 +6687,7 @@ void RelationNode::makeConstraint(thread_db* /*tdbb*/, DsqlCompilerScratch* dsql } } + constraint.create->tableSpace = clause->tableSpace; break; } @@ -6764,6 +6766,7 @@ void RelationNode::defineConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlSc definition.columns = constraint.columns; definition.refRelation = constraint.refRelation; definition.refColumns = constraint.refColumns; + definition.tableSpace = constraint.tableSpace; CreateIndexNode::store(tdbb, transaction, constraint.index->name, definition, &referredIndexName); diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index e86329a7c0d..075f3939e23 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -1274,7 +1274,8 @@ class RelationNode : public DdlNode refUpdateAction(RI_RESTRICT), refDeleteAction(RI_RESTRICT), triggers(p), - blrWritersHolder(p) + blrWritersHolder(p), + tableSpace(p) { } @@ -1287,6 +1288,7 @@ class RelationNode : public DdlNode const char* refDeleteAction; Firebird::ObjectsArray triggers; Firebird::ObjectsArray blrWritersHolder; + MetaName tableSpace; }; struct CreateDropConstraint @@ -1362,7 +1364,8 @@ class RelationNode : public DdlNode refRelation(p), refColumns(p), refAction(NULL), - check(NULL) + check(NULL), + tableSpace(p) { } @@ -1374,6 +1377,7 @@ class RelationNode : public DdlNode Firebird::ObjectsArray refColumns; NestConst refAction; NestConst check; + MetaName tableSpace; }; struct IdentityOptions diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 7c524688140..f07052a3c94 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -2509,7 +2509,7 @@ column_constraint($addColumnClause) constraint.check = $1; } | REFERENCES symbol_table_name column_parens_opt - referential_trigger_action constraint_index_opt + referential_trigger_action constraint_index_opt tablespace_name_clause { RelationNode::AddConstraintClause& constraint = $addColumnClause->constraints.add(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_FK; @@ -2528,18 +2528,27 @@ column_constraint($addColumnClause) } constraint.index = $5; + + if ($6) + constraint.tableSpace = *$6; } - | UNIQUE constraint_index_opt + | UNIQUE constraint_index_opt tablespace_name_clause { RelationNode::AddConstraintClause& constraint = $addColumnClause->constraints.add(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_UNIQUE; constraint.index = $2; + + if ($3) + constraint.tableSpace = *$3; } - | PRIMARY KEY constraint_index_opt + | PRIMARY KEY constraint_index_opt tablespace_name_clause { RelationNode::AddConstraintClause& constraint = $addColumnClause->constraints.add(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_PK; constraint.index = $3; + + if ($4) + constraint.tableSpace = *$4; } ; @@ -2566,7 +2575,7 @@ constraint_name_opt %type table_constraint() table_constraint($relationNode) - : UNIQUE column_parens constraint_index_opt + : UNIQUE column_parens constraint_index_opt tablespace_name_clause { RelationNode::AddConstraintClause& constraint = *newNode(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_UNIQUE; @@ -2579,9 +2588,12 @@ table_constraint($relationNode) constraint.index = $3; + if ($4) + constraint.tableSpace = *$4; + $relationNode->clauses.add(&constraint); } - | PRIMARY KEY column_parens constraint_index_opt + | PRIMARY KEY column_parens constraint_index_opt tablespace_name_clause { RelationNode::AddConstraintClause& constraint = *newNode(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_PK; @@ -2594,10 +2606,13 @@ table_constraint($relationNode) constraint.index = $4; + if ($5) + constraint.tableSpace = *$5; + $relationNode->clauses.add(&constraint); } | FOREIGN KEY column_parens REFERENCES symbol_table_name column_parens_opt - referential_trigger_action constraint_index_opt + referential_trigger_action constraint_index_opt tablespace_name_clause { RelationNode::AddConstraintClause& constraint = *newNode(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_FK; @@ -2622,6 +2637,9 @@ table_constraint($relationNode) constraint.index = $8; + if ($9) + constraint.tableSpace = *$9; + $relationNode->clauses.add(&constraint); } | check_constraint From ac0990c5fddc1cd4818bb50b3cac036e55e1bc79 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 16:14:40 +0300 Subject: [PATCH 42/97] Add tablespace-related header files to VS projects --- builds/win32/msvc15/engine.vcxproj | 10 ++++++---- builds/win32/msvc15/engine.vcxproj.filters | 14 ++++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/builds/win32/msvc15/engine.vcxproj b/builds/win32/msvc15/engine.vcxproj index a0fc4aff67e..743d35862b4 100644 --- a/builds/win32/msvc15/engine.vcxproj +++ b/builds/win32/msvc15/engine.vcxproj @@ -22,7 +22,7 @@ - + @@ -159,7 +159,7 @@ - + @@ -207,6 +207,7 @@ + @@ -337,6 +338,7 @@ + @@ -364,7 +366,7 @@ - + Document @@ -578,4 +580,4 @@ - + \ No newline at end of file diff --git a/builds/win32/msvc15/engine.vcxproj.filters b/builds/win32/msvc15/engine.vcxproj.filters index 8af32f6605c..69f43983c45 100644 --- a/builds/win32/msvc15/engine.vcxproj.filters +++ b/builds/win32/msvc15/engine.vcxproj.filters @@ -444,7 +444,7 @@ DSQL\preprocesed - + DSQL\preprocesed @@ -465,7 +465,7 @@ JRD files - + JRD files @@ -1064,6 +1064,12 @@ Header files + + Header files + + + Header files + @@ -1075,7 +1081,7 @@ DSQL\GPRE files - + DSQL\GPRE files @@ -1118,4 +1124,4 @@ Resource files - + \ No newline at end of file From 80cb22eca05c5ea6603299db1fe54a1aa68ff83e Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 16:18:09 +0300 Subject: [PATCH 43/97] Temporarily disable tablespace-related clauses which are not fully implemented yet --- src/dsql/parse.y | 68 +++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/src/dsql/parse.y b/src/dsql/parse.y index f07052a3c94..52ef0d253b7 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -4905,7 +4905,7 @@ without_time_zone_opt %type blob_type blob_type - : BLOB { $$ = newNode(); } blob_subtype(NOTRIAL($2)) blob_segsize charset_clause tablespace_name_clause + : BLOB { $$ = newNode(); } blob_subtype(NOTRIAL($2)) blob_segsize charset_clause /*tablespace_name_clause*/ { $$ = $2; $$->dtype = dtype_blob; @@ -4916,20 +4916,22 @@ blob_type $$->charSet = *$5; $$->flags |= FLD_has_chset; } - if ($6) - $$->fld_ts_name = *$6; + + //if ($6) + // $$->fld_ts_name = *$6; } - | BLOB '(' unsigned_short_integer ')' tablespace_name_clause + | BLOB '(' unsigned_short_integer ')' /*tablespace_name_clause*/ { $$ = newNode(); $$->dtype = dtype_blob; $$->length = sizeof(ISC_QUAD); $$->segLength = (USHORT) $3; $$->subType = 0; - if ($5) - $$->fld_ts_name = *$5; + + //if ($5) + // $$->fld_ts_name = *$5; } - | BLOB '(' unsigned_short_integer ',' signed_short_integer ')' tablespace_name_clause + | BLOB '(' unsigned_short_integer ',' signed_short_integer ')' /*tablespace_name_clause*/ { $$ = newNode(); $$->dtype = dtype_blob; @@ -4938,10 +4940,10 @@ blob_type $$->subType = (USHORT) $5; $$->flags |= FLD_has_sub; - if ($7) - $$->fld_ts_name = *$7; + //if ($7) + // $$->fld_ts_name = *$7; } - | BLOB '(' ',' signed_short_integer ')' tablespace_name_clause + | BLOB '(' ',' signed_short_integer ')' /*tablespace_name_clause*/ { $$ = newNode(); $$->dtype = dtype_blob; @@ -4950,8 +4952,8 @@ blob_type $$->subType = (USHORT) $4; $$->flags |= FLD_has_sub; - if ($6) - $$->fld_ts_name = *$6; + //if ($6) + // $$->fld_ts_name = *$6; } ; @@ -7473,12 +7475,12 @@ map_role // TABLESPACE %type tablespace_clause tablespace_clause - : symbol_tablespace_name FILE utf_string tablespace_offline_clause tablespace_readonly_clause + : symbol_tablespace_name FILE utf_string /*tablespace_offline_clause tablespace_readonly_clause*/ { $$ = newNode(*$1); $$->fileName = *$3; - $$->offline = $4; - $$->readonly = $5; + //$$->offline = $4; + //$$->readonly = $5; } ; @@ -7497,38 +7499,38 @@ symbol_tablespace_name : valid_symbol_name ; -%type tablespace_offline_clause -tablespace_offline_clause - : { $$ = false; } - | OFFLINE { $$ = true; } - | ONLINE { $$ = false; } - ; +//%type tablespace_offline_clause +//tablespace_offline_clause +// : { $$ = false; } +// | OFFLINE { $$ = true; } +// | ONLINE { $$ = false; } +// ; -%type tablespace_readonly_clause -tablespace_readonly_clause - : { $$ = false; } - | READ ONLY { $$ = true; } - | READ WRITE { $$ = false; } - ; +//%type tablespace_readonly_clause +//tablespace_readonly_clause +// : { $$ = false; } +// | READ ONLY { $$ = true; } +// | READ WRITE { $$ = false; } +// ; %type alter_tablespace_clause alter_tablespace_clause - : symbol_tablespace_name SET FILE to_opt utf_string tablespace_offline_clause tablespace_readonly_clause + : symbol_tablespace_name SET FILE to_opt utf_string /*tablespace_offline_clause tablespace_readonly_clause*/ { $$ = newNode(*$1); $$->create = false; $$->alter = true; $$->fileName = *$5; - $$->offline = $6; - $$->readonly = $7; + //$$->offline = $6; + //$$->readonly = $7; } - | symbol_tablespace_name tablespace_offline_clause tablespace_readonly_clause + | symbol_tablespace_name /*tablespace_offline_clause tablespace_readonly_clause*/ { $$ = newNode(*$1); $$->create = false; $$->alter = true; - $$->offline = $2; - $$->readonly = $3; + //$$->offline = $2; + //$$->readonly = $3; } ; From 16f659369c9ceec3d1bfb4537fa0980f29df9a8d Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 16:19:07 +0300 Subject: [PATCH 44/97] Do not allow to use SET TABLESPACE clause in ALTER TABLE more than once --- src/dsql/DdlNodes.epp | 15 ++++++--------- src/dsql/DdlNodes.h | 11 ----------- src/dsql/parse.y | 6 +++--- 3 files changed, 9 insertions(+), 23 deletions(-) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index a5b843c4cd2..6ba776d3086 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -7849,15 +7849,12 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc case Clause::TYPE_SET_TABLESPACE: { - const MetaName& tableSpaceName = - static_cast(i->getObject())->name; + fb_assert(tableSpace.hasData()); - fb_assert(tableSpaceName.hasData()); + const bool primary_ts = (tableSpace == PRIMARY_TABLESPACE_NAME); - const bool primary_ts = (tableSpaceName == PRIMARY_TABLESPACE_NAME); - - if (!primary_ts && !checkObjectExist(tdbb, transaction, tableSpaceName, obj_tablespaces)) - status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << tableSpaceName.c_str()); + if (!primary_ts && !checkObjectExist(tdbb, transaction, tableSpace, obj_tablespaces)) + status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << tableSpace.c_str()); AutoRequest request2; @@ -7878,7 +7875,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc // Check if we are trying to change tablespace name to the already set if ( (REL.RDB$TABLESPACE_NAME.NULL && primary_ts) || - (!REL.RDB$TABLESPACE_NAME.NULL && tableSpaceName == REL.RDB$TABLESPACE_NAME) ) + (!REL.RDB$TABLESPACE_NAME.NULL && tableSpace == REL.RDB$TABLESPACE_NAME) ) { break; } @@ -7896,7 +7893,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc if (!primary_ts) { REL.RDB$TABLESPACE_NAME.NULL = FALSE; - strcpy(REL.RDB$TABLESPACE_NAME, tableSpaceName.c_str()); + strcpy(REL.RDB$TABLESPACE_NAME, tableSpace.c_str()); } else { diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index 075f3939e23..5e1f3054fcd 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -1506,17 +1506,6 @@ class RelationNode : public DdlNode MetaName name; }; - struct SetTableSpaceClause : public Clause - { - explicit SetTableSpaceClause(MemoryPool& p) - : Clause(p, TYPE_SET_TABLESPACE), - name(p) - { - } - - MetaName name; - }; - RelationNode(MemoryPool& p, RelationSourceNode* aDsqlNode); static void deleteLocalField(thread_db* tdbb, jrd_tra* transaction, diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 52ef0d253b7..521ec0a5540 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -4244,9 +4244,9 @@ alter_op($relationNode) } | SET TABLESPACE to_opt symbol_tablespace_name { - RelationNode::SetTableSpaceClause* clause = - newNode(); - clause->name = *$4; + setClause($relationNode->tableSpace, "TABLESPACE", *$4); + RelationNode::Clause* clause = + newNode(RelationNode::Clause::TYPE_SET_TABLESPACE); $relationNode->clauses.add(clause); } ; From 039e3efdfd74b11f59a6b6d708e8bd332f948fd6 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 16:37:11 +0300 Subject: [PATCH 45/97] Fix typos in the error message and comments --- src/jrd/dfw.epp | 2 +- src/jrd/dpm.epp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index de1204ff83a..53e3b231dda 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -6708,7 +6708,7 @@ static bool move_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd RelationPages* relationPages = relation->getPages(tdbb); // Copy index root page to a new relation tablespace - // And free previos one + // And free previous one WIN oldWindow(relationPages->rel_pg_space_id, relationPages->rel_index_root); Ods::pag* oldPage = CCH_FETCH(tdbb, &oldWindow, LCK_read, pag_root); diff --git a/src/jrd/dpm.epp b/src/jrd/dpm.epp index 46bff7e0917..ac91ce8f0c8 100644 --- a/src/jrd/dpm.epp +++ b/src/jrd/dpm.epp @@ -852,7 +852,7 @@ void DPM_delete( thread_db* tdbb, record_param* rpb, ULONG prior_page) DECOMPOSE(sequence, dbb->dbb_dp_per_pp, pp_sequence, slot); RelationPages* relPages = NULL; - WIN pwindow(DB_PAGE_SPACE, -1); // Will be initialized by pagespace of relation leter + WIN pwindow(DB_PAGE_SPACE, -1); // Will be initialized by pagespace of relation later for (;;) { From d9e66fcf09d81b1d76ec517a91cfdd7518f54b49 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 16:40:37 +0300 Subject: [PATCH 46/97] Change the data type of RDB$OFFLINE and RDB$READ_ONLY to BOOLEAN --- src/burp/backup.epp | 4 ++-- src/burp/restore.epp | 4 ++-- src/jrd/relations.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/burp/backup.epp b/src/burp/backup.epp index 2dba1cfbeb3..d5226a6f997 100644 --- a/src/burp/backup.epp +++ b/src/burp/backup.epp @@ -4285,10 +4285,10 @@ void write_tablespaces() PUT_TEXT(att_ts_file, X.RDB$FILE_NAME); if (!X.RDB$OFFLINE.NULL) - put_int32(att_ts_offline, X.RDB$OFFLINE); + put_boolean(att_ts_offline, X.RDB$OFFLINE); if (!X.RDB$READ_ONLY.NULL) - put_int32(att_ts_readonly, X.RDB$READ_ONLY); + put_boolean(att_ts_readonly, X.RDB$READ_ONLY); put(tdgbl, att_end); } diff --git a/src/burp/restore.epp b/src/burp/restore.epp index 9c68ee5cf49..694073bf51a 100644 --- a/src/burp/restore.epp +++ b/src/burp/restore.epp @@ -7533,12 +7533,12 @@ bool get_tablespace(BurpGlobals* tdgbl) break; case att_ts_offline: - X.RDB$OFFLINE = (USHORT) get_int32(tdgbl); + X.RDB$OFFLINE = (USHORT) get_boolean(tdgbl); X.RDB$OFFLINE.NULL = FALSE; break; case att_ts_readonly: - X.RDB$READ_ONLY = (USHORT) get_int32(tdgbl); + X.RDB$READ_ONLY = (USHORT) get_boolean(tdgbl); X.RDB$READ_ONLY.NULL = FALSE; break; diff --git a/src/jrd/relations.h b/src/jrd/relations.h index 87c3d3bd7dd..27bbd61da96 100644 --- a/src/jrd/relations.h +++ b/src/jrd/relations.h @@ -769,6 +769,6 @@ RELATION(nam_tablespaces, rel_tablespaces, ODS_13_1, rel_persistent) FIELD(f_ts_desc, nam_description, fld_description, 1, ODS_13_1) FIELD(f_ts_owner, nam_owner, fld_user, 1, ODS_13_1) FIELD(f_ts_file, nam_file_name, fld_file_name, 1, ODS_13_1) - FIELD(f_ts_offline, nam_ts_offline, fld_flag, 1, ODS_13_1) - FIELD(f_ts_readonly, nam_ts_readonly, fld_flag, 1, ODS_13_1) + FIELD(f_ts_offline, nam_ts_offline, fld_bool, 1, ODS_13_1) + FIELD(f_ts_readonly, nam_ts_readonly, fld_bool, 1, ODS_13_1) END_RELATION From cf021e6a12d80bb8a849cbd4b9cd3bc3a805693f Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 17:04:24 +0300 Subject: [PATCH 47/97] Always store an absolute path to a tablespace file in RDB$TABLESPACES If a relative path is specified in CREATE TABLESPACE, ALTER TABLESPACE, and in a tablespace mapping file, it will be combined with a path to a database. --- src/burp/restore.epp | 21 ++++++++++++++++++++- src/dsql/TablespaceNodes.epp | 17 +++++++++++++++++ src/dsql/TablespaceNodes.h | 2 +- src/dsql/parse.y | 4 ++-- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/burp/restore.epp b/src/burp/restore.epp index 694073bf51a..bd6151928b9 100644 --- a/src/burp/restore.epp +++ b/src/burp/restore.epp @@ -61,6 +61,7 @@ #include "../auth/trusted/AuthSspi.h" #include "../common/dsc_proto.h" #include "../common/ThreadStart.h" +#include "../common/db_alias.h" using MsgFormat::SafeArg; using Firebird::FbLocalStatus; @@ -7551,8 +7552,26 @@ bool get_tablespace(BurpGlobals* tdgbl) Firebird::string newFile; if (tdgbl->tablespace_mapping.get(X.RDB$TABLESPACE_NAME, newFile)) { + PathUtils::fixupSeparators(newFile.begin()); + Firebird::PathName ts_file_name; + + if (PathUtils::isRelative(newFile.c_str())) + { + Firebird::PathName expanded_db; + expandDatabaseName(tdgbl->gbl_database_file_name, expanded_db, NULL); + + Firebird::PathName db_path, db_file; + PathUtils::splitLastComponent(db_path, db_file, expanded_db); + PathUtils::concatPath(ts_file_name, db_path, newFile.c_str()); + } + else + ts_file_name = newFile.c_str(); + + if (ts_file_name.length() >= sizeof(X.RDB$FILE_NAME)) + BURP_error(46, true); // msg 46 string truncated + X.RDB$FILE_NAME.NULL = FALSE; - strcpy(X.RDB$FILE_NAME, newFile.c_str()); + strcpy(X.RDB$FILE_NAME, ts_file_name.c_str()); } } diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index 935e741283f..399353c3e5f 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -33,6 +33,7 @@ #include "../dsql/make_proto.h" #include "../dsql/pass1_proto.h" #include "../common/StatusArg.h" +#include "../common/os/path_utils.h" #include "../jrd/Attachment.h" #include "../jrd/scl_proto.h" #include "../jrd/dyn_ut_proto.h" @@ -82,6 +83,16 @@ void CreateAlterTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* ds { fb_assert(create || alter); + PathUtils::fixupSeparators(fileName); + + if (PathUtils::isRelative(fileName)) + { + PathName temp = fileName; + PathName db_path, db_file; + PathUtils::splitLastComponent(db_path, db_file, tdbb->getDatabase()->dbb_filename); + PathUtils::concatPath(fileName, db_path, temp); + } + // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); @@ -142,6 +153,9 @@ void CreateAlterTablespaceNode::executeCreate(thread_db* tdbb, DsqlCompilerScrat X.RDB$OWNER_NAME.NULL = FALSE; strcpy(X.RDB$OWNER_NAME, userName.c_str()); + if (fileName.length() >= sizeof(X.RDB$FILE_NAME)) + status_exception::raise(Arg::Gds(isc_dyn_name_longer)); + X.RDB$FILE_NAME.NULL = FALSE; strcpy(X.RDB$FILE_NAME, fileName.c_str()); @@ -212,6 +226,9 @@ bool CreateAlterTablespaceNode::executeAlter(thread_db* tdbb, DsqlCompilerScratc MODIFY X if (fileName.hasData()) { + if (fileName.length() >= sizeof(X.RDB$FILE_NAME)) + status_exception::raise(Arg::Gds(isc_dyn_name_longer)); + fb_assert(X.RDB$FILE_NAME.NULL == FALSE); if (!PIO_file_exists(fileName.c_str())) ERR_post(Arg::Gds(isc_ts_file_not_exists) << Arg::Str(name) << Arg::Str(fileName)); diff --git a/src/dsql/TablespaceNodes.h b/src/dsql/TablespaceNodes.h index 693a9b39192..a624cade07c 100644 --- a/src/dsql/TablespaceNodes.h +++ b/src/dsql/TablespaceNodes.h @@ -64,7 +64,7 @@ class CreateAlterTablespaceNode : public DdlNode public: MetaName name; - Firebird::string fileName; + Firebird::PathName fileName; bool create; bool alter; bool offline; diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 521ec0a5540..d2a8aa5d773 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -7478,7 +7478,7 @@ tablespace_clause : symbol_tablespace_name FILE utf_string /*tablespace_offline_clause tablespace_readonly_clause*/ { $$ = newNode(*$1); - $$->fileName = *$3; + $$->fileName = $3->c_str(); //$$->offline = $4; //$$->readonly = $5; } @@ -7520,7 +7520,7 @@ alter_tablespace_clause $$ = newNode(*$1); $$->create = false; $$->alter = true; - $$->fileName = *$5; + $$->fileName = $5->c_str(); //$$->offline = $6; //$$->readonly = $7; } From a2066fac5e0433bab2fe0fd79280d9fb39ca62f3 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 17:05:37 +0300 Subject: [PATCH 48/97] Do not allow to restore a database if paths for some tablespaces are not specified It prevents creation of files in unexpected places. gbak will print names of tablespaces and their original paths. --- src/burp/burp.h | 1 + src/burp/restore.epp | 42 +++++++++++++++++++++++++++++++++++++----- src/jrd/dfw.epp | 23 +++-------------------- src/jrd/vio.cpp | 4 +++- 4 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/burp/burp.h b/src/burp/burp.h index 4267c19d5d0..fb12837ad39 100644 --- a/src/burp/burp.h +++ b/src/burp/burp.h @@ -1155,6 +1155,7 @@ class BurpGlobals : public Firebird::ThreadData, public GblPool Firebird::IRequest* handles_get_user_privilege_req_handle1; Firebird::IRequest* handles_get_view_req_handle1; Firebird::IRequest* handles_get_ts_req_handle1; + Firebird::IRequest* handles_get_ts_req_handle2; // The handles_put.. are for backup. Firebird::IRequest* handles_put_index_req_handle1; diff --git a/src/burp/restore.epp b/src/burp/restore.epp index bd6151928b9..9db53b62b05 100644 --- a/src/burp/restore.epp +++ b/src/burp/restore.epp @@ -7568,16 +7568,25 @@ bool get_tablespace(BurpGlobals* tdgbl) ts_file_name = newFile.c_str(); if (ts_file_name.length() >= sizeof(X.RDB$FILE_NAME)) - BURP_error(46, true); // msg 46 string truncated + { + BURP_error(46, false); // msg 46 string truncated + return false; + } X.RDB$FILE_NAME.NULL = FALSE; strcpy(X.RDB$FILE_NAME, ts_file_name.c_str()); } - + else + { + BURP_error(1022, false, SafeArg() << X.RDB$TABLESPACE_NAME << X.RDB$FILE_NAME); + // msg 1022 path to tablespace @1 is not specified (original path: "@2") + return false; + } } END_STORE ON_ERROR - general_on_error(); + BURP_print_status(true, &tdgbl->status_vector); + return false; END_ERROR return true; @@ -11272,10 +11281,33 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file bool flag_norel = true; // To fix bug 10098 bool flag = false; + bool ts_error = false; rec_type record; - while (get_record(&record, tdgbl) != rec_end) + while (true) { + get_record(&record, tdgbl); + + if (ts_error && record != rec_tablespace) + { + // Clean up RDB$TABLESPACES to prevent creation of files during DFW + FOR (REQUEST_HANDLE tdgbl->handles_get_ts_req_handle2) + X IN RDB$TABLESPACES + ERASE X; + ON_ERROR + general_on_error(); + END_ERROR; + END_FOR; + ON_ERROR + general_on_error(); + END_ERROR; + + return false; + } + + if (record == rec_end) + break; + switch (record) { case rec_charset: @@ -11341,7 +11373,7 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file case rec_tablespace: if (!get_tablespace(tdgbl)) - return false; + ts_error = true; flag = true; break; diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 53e3b231dda..78c93459254 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -6487,22 +6487,13 @@ static bool create_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, AutoCacheRequest request(tdbb, irq_find_ts_dfw0, IRQ_REQUESTS); - bool found = false; - PathName file; - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) TS IN RDB$TABLESPACES WITH TS.RDB$TABLESPACE_ID EQ work->dfw_id { - found = true; - file = TS.RDB$FILE_NAME; + unlink(TS.RDB$FILE_NAME); } END_FOR - - if (!found) - return false; - - unlink(file.c_str()); } return false; @@ -6515,22 +6506,14 @@ static bool create_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, AutoCacheRequest request(tdbb, irq_find_ts_dfw, IRQ_REQUESTS); - bool found = false; - PathName file; - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) TS IN RDB$TABLESPACES WITH TS.RDB$TABLESPACE_ID EQ work->dfw_id { - found = true; - file = TS.RDB$FILE_NAME; + PathName file = TS.RDB$FILE_NAME; + dbb->dbb_page_manager.allocTableSpace(tdbb, work->dfw_id, true, file); } END_FOR - - if (!found) - status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(work->dfw_name)); - - dbb->dbb_page_manager.allocTableSpace(tdbb, work->dfw_id, true, file); } return true; diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index 09a50b9e5b5..d1424fbd472 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -247,13 +247,15 @@ inline void check_gbak_cheating_delete(thread_db* tdbb, const jrd_rel* relation) if (tdbb->tdbb_flags & TDBB_dont_post_dfw) return; - // There are 2 tables whose contents gbak might delete: + // There are 3 tables whose contents gbak might delete: // - RDB$INDEX_SEGMENTS if it detects inconsistencies while restoring // - RDB$FILES if switch -k is set + // - RDB$TABLESPACES if errors occur while restoring tablespaces switch(relation->rel_id) { case rel_segments: case rel_files: + case rel_tablespaces: return; } } From cbe164e1cee3115ee71c58f4e98023a328074dc3 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 17:06:05 +0300 Subject: [PATCH 49/97] Restrict access to tablespace files by DatabaseAccess entry of firebird.conf --- src/jrd/pag.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index 1c0c9ed5ef5..a9b172f2989 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -2627,6 +2627,13 @@ void PageManager::allocTableSpace(thread_db* tdbb, USHORT tableSpaceID, bool cre if (findPageSpace(tableSpaceID)) return; + // Verify tablespace file path against DatabaseAccess entry of firebird.conf + if (!JRD_verify_database_access(fileName)) + { + ERR_post(Arg::Gds(isc_conf_access_denied) << Arg::Str("tablespace") << + Arg::Str(fileName)); + } + PageSpace* newPageSpace = FB_NEW_POOL(pool) PageSpace(dbb, tableSpaceID); try From a480ce29af023a75484da0df9a69f7cbb518d2d7 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 17:13:34 +0300 Subject: [PATCH 50/97] Add -TABLESPACE_ORIG(INAL_PATHS) option to gbak which allows to restore tablespaces to their original paths -TABLESPACE_MAP can be used with this option to specify new paths for some tablespaces. --- src/burp/burp.cpp | 6 ++++++ src/burp/burp.h | 1 + src/burp/burpswi.h | 2 ++ src/burp/restore.epp | 2 +- 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/burp/burp.cpp b/src/burp/burp.cpp index 00824c1832d..ee03bb297ed 100644 --- a/src/burp/burp.cpp +++ b/src/burp/burp.cpp @@ -596,6 +596,7 @@ int gbak(Firebird::UtilSvc* uSvc) tdgbl->gbl_sw_old_descriptions = false; tdgbl->gbl_sw_mode = false; tdgbl->gbl_sw_skip_count = 0; + tdgbl->gbl_sw_ts_orig_paths = false; tdgbl->action = NULL; burp_fil* file = NULL; @@ -1080,6 +1081,11 @@ int gbak(Firebird::UtilSvc* uSvc) } tdgbl->loadMapping(argv[itr], tdgbl->tablespace_mapping, false); break; + case IN_SW_BURP_TS_ORIGINAL_PATHS: + if (tdgbl->gbl_sw_ts_orig_paths) + BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name); + tdgbl->gbl_sw_ts_orig_paths = true; + break; } } // for diff --git a/src/burp/burp.h b/src/burp/burp.h index fb12837ad39..eed9659f3dd 100644 --- a/src/burp/burp.h +++ b/src/burp/burp.h @@ -1040,6 +1040,7 @@ class BurpGlobals : public Firebird::ThreadData, public GblPool redirect_vals sw_redirect; bool burp_throw; Nullable gbl_sw_replica; + bool gbl_sw_ts_orig_paths; UCHAR* blk_io_ptr; int blk_io_cnt; diff --git a/src/burp/burpswi.h b/src/burp/burpswi.h index 68b983846a9..9cdcadf9184 100644 --- a/src/burp/burpswi.h +++ b/src/burp/burpswi.h @@ -99,6 +99,7 @@ const int IN_SW_BURP_CRYPT = 51; // name of crypt plugin const int IN_SW_BURP_INCLUDE_DATA = 52; // backup data from tables const int IN_SW_BURP_REPLICA = 53; // replica mode const int IN_SW_BURP_TS_MAPPING_FILE = 54; // mapping file for tablespaces +const int IN_SW_BURP_TS_ORIGINAL_PATHS = 55; // restore tablespaces to their original paths /**************************************************************************/ @@ -226,6 +227,7 @@ static const Switches::in_sw_tab_t reference_burp_in_sw_table[] = {IN_SW_BURP_HIDDEN_RDWRITE, isc_spb_res_am_readwrite, "MODE READ_WRITE", 0, 0, 0, false, false, 0, 15, NULL, boRestore}, /**************************************************************************/ {IN_SW_BURP_TS_MAPPING_FILE, 0, "TABLESPACE_MAPPING_FILE", 0, 0, 0, false, false, 410, 14, NULL, boRestore}, + {IN_SW_BURP_TS_ORIGINAL_PATHS, 0, "TABLESPACE_ORIGINAL_PATHS", 0, 0, 0, false, false, 412, 15, NULL, boRestore}, {IN_SW_BURP_0, 0, NULL, 0, 0, 0, false, false, 0, 0, NULL, boGeneral} }; diff --git a/src/burp/restore.epp b/src/burp/restore.epp index 9db53b62b05..f9083ca1edd 100644 --- a/src/burp/restore.epp +++ b/src/burp/restore.epp @@ -7576,7 +7576,7 @@ bool get_tablespace(BurpGlobals* tdgbl) X.RDB$FILE_NAME.NULL = FALSE; strcpy(X.RDB$FILE_NAME, ts_file_name.c_str()); } - else + else if (!tdgbl->gbl_sw_ts_orig_paths) { BURP_error(1022, false, SafeArg() << X.RDB$TABLESPACE_NAME << X.RDB$FILE_NAME); // msg 1022 path to tablespace @1 is not specified (original path: "@2") From 115981355198cb20f4520b61244c41397cd94007 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 17:20:43 +0300 Subject: [PATCH 51/97] Add -TS option to gbak which allows to set a path for a tablespace --- src/burp/burp.cpp | 16 ++++++++++++++++ src/burp/burpswi.h | 2 ++ 2 files changed, 18 insertions(+) diff --git a/src/burp/burp.cpp b/src/burp/burp.cpp index ee03bb297ed..0d31ebffc87 100644 --- a/src/burp/burp.cpp +++ b/src/burp/burp.cpp @@ -1085,6 +1085,22 @@ int gbak(Firebird::UtilSvc* uSvc) if (tdgbl->gbl_sw_ts_orig_paths) BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name); tdgbl->gbl_sw_ts_orig_paths = true; + break; + case IN_SW_BURP_TS_PATH: + if (itr + 2 >= argc) + { + BURP_error(1025, true, SafeArg() << "TS"); + // parameter for option -@1 is missing + } + + { + string ts_name = argv[++itr]; + string ts_path = argv[++itr]; + + if (ts_name.length() && ts_path.length()) + tdgbl->tablespace_mapping.put(ts_name, ts_path); + } + break; } } // for diff --git a/src/burp/burpswi.h b/src/burp/burpswi.h index 9cdcadf9184..615824d933c 100644 --- a/src/burp/burpswi.h +++ b/src/burp/burpswi.h @@ -100,6 +100,7 @@ const int IN_SW_BURP_INCLUDE_DATA = 52; // backup data from tables const int IN_SW_BURP_REPLICA = 53; // replica mode const int IN_SW_BURP_TS_MAPPING_FILE = 54; // mapping file for tablespaces const int IN_SW_BURP_TS_ORIGINAL_PATHS = 55; // restore tablespaces to their original paths +const int IN_SW_BURP_TS_PATH = 56; // set a path for a tablespace /**************************************************************************/ @@ -227,6 +228,7 @@ static const Switches::in_sw_tab_t reference_burp_in_sw_table[] = {IN_SW_BURP_HIDDEN_RDWRITE, isc_spb_res_am_readwrite, "MODE READ_WRITE", 0, 0, 0, false, false, 0, 15, NULL, boRestore}, /**************************************************************************/ {IN_SW_BURP_TS_MAPPING_FILE, 0, "TABLESPACE_MAPPING_FILE", 0, 0, 0, false, false, 410, 14, NULL, boRestore}, + {IN_SW_BURP_TS_PATH, 0, "TS", 0, 0, 0, false, false, 413, 2, NULL, boRestore}, {IN_SW_BURP_TS_ORIGINAL_PATHS, 0, "TABLESPACE_ORIGINAL_PATHS", 0, 0, 0, false, false, 412, 15, NULL, boRestore}, {IN_SW_BURP_0, 0, NULL, 0, 0, 0, false, false, 0, 0, NULL, boGeneral} }; From 66c7fde311a4205de7e7559d27fb4642274f2d15 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 17:24:16 +0300 Subject: [PATCH 52/97] 1. Read tablespace names from a mapping file as case sensitive. 2. Don't clear the tablespace mapping while processing -TABLESPACE_MAP option to make it possible to use it in combination with -TS option. --- src/burp/burp.cpp | 7 ++++--- src/burp/burp.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/burp/burp.cpp b/src/burp/burp.cpp index 0d31ebffc87..86b075b9e83 100644 --- a/src/burp/burp.cpp +++ b/src/burp/burp.cpp @@ -2859,8 +2859,7 @@ void BurpGlobals::print_stats_header() burp_output(false, "\n"); } - -void BurpGlobals::loadMapping(const char* mapping_file, StringMap& map, bool caseSensitive) +void BurpGlobals::loadMapping(const char* mapping_file, StringMap& map, bool clearMap, bool caseSensitive) { FILE* f = os_utils::fopen(mapping_file, fopen_read_type); if (!f) @@ -2869,7 +2868,9 @@ void BurpGlobals::loadMapping(const char* mapping_file, StringMap& map, bool cas } //Read lines from file, split by space and add to mapping - map.clear(); + if (clearMap) + map.clear(); + bool end = false; do { diff --git a/src/burp/burp.h b/src/burp/burp.h index eed9659f3dd..7890f1d336f 100644 --- a/src/burp/burp.h +++ b/src/burp/burp.h @@ -1196,7 +1196,7 @@ class BurpGlobals : public Firebird::ThreadData, public GblPool void setupSkipData(const Firebird::string& regexp); void setupIncludeData(const Firebird::string& regexp); bool skipRelation(const char* name); - void loadMapping(const char* mapping_file, StringMap& map, bool caseSensitive = true); + void loadMapping(const char* mapping_file, StringMap& map, bool clearMap = true, bool caseSensitive = true); char veryEnd; //starting after this members must be initialized in constructor explicitly From 112012be4a3916cfbe61ca8ba41f58ef4b83aae3 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 17:29:08 +0300 Subject: [PATCH 53/97] Rename gbak options -TABLESPACE_* to -TS_* --- src/burp/burpswi.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/burp/burpswi.h b/src/burp/burpswi.h index 615824d933c..f1c128816b5 100644 --- a/src/burp/burpswi.h +++ b/src/burp/burpswi.h @@ -227,9 +227,9 @@ static const Switches::in_sw_tab_t reference_burp_in_sw_table[] = {IN_SW_BURP_HIDDEN_RDONLY, isc_spb_res_am_readonly, "MODE READ_ONLY", 0, 0, 0, false, false, 0, 14, NULL, boRestore}, {IN_SW_BURP_HIDDEN_RDWRITE, isc_spb_res_am_readwrite, "MODE READ_WRITE", 0, 0, 0, false, false, 0, 15, NULL, boRestore}, /**************************************************************************/ - {IN_SW_BURP_TS_MAPPING_FILE, 0, "TABLESPACE_MAPPING_FILE", 0, 0, 0, false, false, 410, 14, NULL, boRestore}, + {IN_SW_BURP_TS_MAPPING_FILE, 0, "TS_MAPPING_FILE", 0, 0, 0, false, false, 410, 6, NULL, boRestore}, {IN_SW_BURP_TS_PATH, 0, "TS", 0, 0, 0, false, false, 413, 2, NULL, boRestore}, - {IN_SW_BURP_TS_ORIGINAL_PATHS, 0, "TABLESPACE_ORIGINAL_PATHS", 0, 0, 0, false, false, 412, 15, NULL, boRestore}, + {IN_SW_BURP_TS_ORIGINAL_PATHS, 0, "TS_ORIGINAL_PATHS", 0, 0, 0, false, false, 412, 7, NULL, boRestore}, {IN_SW_BURP_0, 0, NULL, 0, 0, 0, false, false, 0, 0, NULL, boGeneral} }; From eb097ad5bbcca85f6770df1dbcca76790d532b53 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 17:29:52 +0300 Subject: [PATCH 54/97] Correct the argument of the error message --- src/burp/burp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/burp/burp.cpp b/src/burp/burp.cpp index 86b075b9e83..da9ed3ad3cd 100644 --- a/src/burp/burp.cpp +++ b/src/burp/burp.cpp @@ -1089,7 +1089,7 @@ int gbak(Firebird::UtilSvc* uSvc) case IN_SW_BURP_TS_PATH: if (itr + 2 >= argc) { - BURP_error(1025, true, SafeArg() << "TS"); + BURP_error(1025, true, SafeArg() << in_sw_tab->in_sw_name); // parameter for option -@1 is missing } From a9430d419cac0930818457de16f863095f9c7b45 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 17:30:51 +0300 Subject: [PATCH 55/97] Fix the phase 0 of create_tablespace DFW A page space should be closed before deleting a tablespace file, and a tablespace should be removed from the cache. --- src/jrd/dfw.epp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 78c93459254..4af84d122ca 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -6491,7 +6491,21 @@ static bool create_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, TS IN RDB$TABLESPACES WITH TS.RDB$TABLESPACE_ID EQ work->dfw_id { - unlink(TS.RDB$FILE_NAME); + if (dbb->dbb_page_manager.findPageSpace(work->dfw_id)) + { + CCH_flush(tdbb, FLUSH_ALL, 0); + dbb->dbb_page_manager.delPageSpace(work->dfw_id); + unlink(TS.RDB$FILE_NAME); + } + + Attachment* attachment = tdbb->getAttachment(); + Tablespace* tablespace = attachment->getTablespace(work->dfw_id); + + if (tablespace) + { + LCK_release(tdbb, tablespace->existenceLock); + attachment->delTablespace(work->dfw_id); + } } END_FOR } From 282a198d9134c52eb8ccdd89702b609b24be571c Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 17:32:38 +0300 Subject: [PATCH 56/97] Do not allow to set a tablespace for GTT's indexes --- src/dsql/DdlNodes.epp | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 6ba776d3086..affe17e2c9f 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -7867,10 +7867,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc ULONG flags = MET_get_rel_flags_from_TYPE(REL.RDB$RELATION_TYPE); if (flags & (REL_temp_tran | REL_temp_conn)) - { - // msg 311: "Cannot alter tablespace for temporary table @1" - status_exception::raise(Arg::PrivateDyn(311) << name); - } + status_exception::raise(Arg::Gds(isc_dyn_cant_set_ts_table) << name); } // Check if we are trying to change tablespace name to the already set @@ -9594,6 +9591,7 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam IDX.RDB$TABLESPACE_NAME.NULL = TRUE; MetaName relationTablespace; + bool temporary = false; // Check if the table is actually a view. @@ -9608,8 +9606,15 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam // msg 181: "attempt to index a view" status_exception::raise(Arg::PrivateDyn(181)); } + if (!VREL.RDB$TABLESPACE_NAME.NULL) relationTablespace = VREL.RDB$TABLESPACE_NAME; + + if (!VREL.RDB$RELATION_TYPE.NULL) + { + ULONG flags = MET_get_rel_flags_from_TYPE(VREL.RDB$RELATION_TYPE); + temporary = flags & (REL_temp_tran | REL_temp_conn); + } } END_FOR @@ -9633,6 +9638,9 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam if (definition.tableSpace.hasData()) { + if (temporary) + status_exception::raise(Arg::Gds(isc_dyn_cant_set_ts_index) << IDX.RDB$INDEX_NAME); + if (definition.tableSpace != PRIMARY_TABLESPACE_NAME) { if (!checkObjectExist(tdbb, transaction, definition.tableSpace, obj_tablespaces)) @@ -10059,6 +10067,22 @@ void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, if (!primary_ts && !checkObjectExist(tdbb, transaction, tableSpace, obj_tablespaces)) status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << tableSpace.c_str()); + AutoRequest request2; + + FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) + REL IN RDB$RELATIONS + WITH REL.RDB$RELATION_NAME EQ IDX.RDB$RELATION_NAME + { + if (!REL.RDB$RELATION_TYPE.NULL) + { + ULONG flags = MET_get_rel_flags_from_TYPE(REL.RDB$RELATION_TYPE); + + if (flags & (REL_temp_tran | REL_temp_conn)) + status_exception::raise(Arg::Gds(isc_dyn_cant_set_ts_index) << name); + } + } + END_FOR + // Check if we are trying to change tablespace name to the already set if ( (IDX.RDB$TABLESPACE_NAME.NULL && primary_ts) || (!IDX.RDB$TABLESPACE_NAME.NULL && tableSpace == IDX.RDB$TABLESPACE_NAME) ) From 49c6fbf44ad9a38d3a0f3b38ec375ecf754e7b01 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Apr 2022 17:35:02 +0300 Subject: [PATCH 57/97] Release the exclusive lock on a database after moving a relation or an index to another tablespace --- src/jrd/dfw.epp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 4af84d122ca..5a2f9103cbd 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -1647,7 +1647,10 @@ void DFW_perform_post_commit_work(thread_db* tdbb, jrd_tra* transaction) // A relation may already be deleted by dfw_delete_relation in the same transaction if (!relation) + { + CCH_release_exclusive(tdbb); break; + } RelationPages* relationPages = relation->getPages(tdbb); DPM_delete_relation_pages(tdbb, relation, relationPages); @@ -1667,6 +1670,8 @@ void DFW_perform_post_commit_work(thread_db* tdbb, jrd_tra* transaction) CCH_flush(tdbb, FLUSH_SYSTEM, 0); *relationPages = *newRelationPages; + + CCH_release_exclusive(tdbb); } break; case dfw_clear_indexpages: @@ -6812,7 +6817,10 @@ static bool move_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tr // An index may be deleted in the same transaction. // Don't move index pages in this case. if (!relation) + { + CCH_release_exclusive(tdbb); break; + } const USHORT newPageSpaceId = MET_tablespace(tdbb, tableSpace)->id; @@ -6828,6 +6836,8 @@ static bool move_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tr ids[1] = oldRootPage.getPageSpaceID(); ids[2] = oldRootPage.getPageNum(); } + + CCH_release_exclusive(tdbb); } break; From 503ab38362fb486f87415851fcab468d74c4379b Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Tue, 12 Apr 2022 14:38:00 +0300 Subject: [PATCH 58/97] Add missing tablespaces-related messages --- src/include/firebird/impl/msg/dyn.h | 3 +++ src/include/firebird/impl/msg/gbak.h | 9 +++++++++ src/include/firebird/impl/msg/isql.h | 3 +++ src/include/firebird/impl/msg/jrd.h | 3 +++ src/include/firebird/impl/msg/jrd_bugchk.h | 1 + src/include/firebird/impl/msg/sqlerr.h | 5 +++++ src/include/gen/Firebird.pas | 11 +++++++++++ 7 files changed, 35 insertions(+) diff --git a/src/include/firebird/impl/msg/dyn.h b/src/include/firebird/impl/msg/dyn.h index 058b2176a0b..604d88cabbd 100644 --- a/src/include/firebird/impl/msg/dyn.h +++ b/src/include/firebird/impl/msg/dyn.h @@ -299,3 +299,6 @@ FB_IMPL_MSG(DYN, 306, dyn_rel_not_exist, -901, "42", "000", "Table @1 does not e FB_IMPL_MSG(DYN, 307, dyn_exc_not_exist, -901, "42", "000", "Exception @1 does not exist") FB_IMPL_MSG(DYN, 308, dyn_gen_not_exist, -901, "42", "000", "Generator/Sequence @1 does not exist") FB_IMPL_MSG(DYN, 309, dyn_fld_not_exist, -901, "42", "000", "Field @1 of table @2 does not exist") +FB_IMPL_MSG(DYN, 310, dyn_ts_not_found, -901, "42", "000", "Tablespace @1 not found") +FB_IMPL_MSG(DYN, 311, dyn_cant_set_ts_table, -901, "42", "000", "Cannot set tablespace for temporary table @1") +FB_IMPL_MSG(DYN, 312, dyn_cant_set_ts_index, -901, "42", "000", "Cannot set tablespace for temporary index @1") diff --git a/src/include/firebird/impl/msg/gbak.h b/src/include/firebird/impl/msg/gbak.h index 60482441831..f3178b9c684 100644 --- a/src/include/firebird/impl/msg/gbak.h +++ b/src/include/firebird/impl/msg/gbak.h @@ -401,3 +401,12 @@ FB_IMPL_MSG_NO_SYMBOL(GBAK, 402, "publication for table") FB_IMPL_MSG_SYMBOL(GBAK, 403, gbak_opt_replica, " @1REPLICA \"none\", \"read_only\" or \"read_write\" replica mode") FB_IMPL_MSG_SYMBOL(GBAK, 404, gbak_replica_req, "\"none\", \"read_only\" or \"read_write\" required") FB_IMPL_MSG_NO_SYMBOL(GBAK, 405, "could not access batch parameters") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 406, "writing tablespaces") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 407, "writing tablespace @1") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 408, "restoring tablespace @1") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 409, "tablespace") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 410, " @1TS_MAP(PING_FILE) mapping file for tablespaces") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 411, "path to tablespace @1 is not specified (original path: \"@2\")") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 412, " @1TS_ORIG(INAL_PATHS) restore tablespaces to their original paths") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 413, " @1TS set a path for a tablespace") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 414, "parameter for option -@1 is missing") diff --git a/src/include/firebird/impl/msg/isql.h b/src/include/firebird/impl/msg/isql.h index 9d45b3a1aaa..59124f191ec 100644 --- a/src/include/firebird/impl/msg/isql.h +++ b/src/include/firebird/impl/msg/isql.h @@ -193,3 +193,6 @@ FB_IMPL_MSG_SYMBOL(ISQL, 193, DATABASE_NOT_CRYPTED, "Database not encrypted") FB_IMPL_MSG_SYMBOL(ISQL, 194, DATABASE_CRYPT_PROCESS, "crypt thread not complete") FB_IMPL_MSG_SYMBOL(ISQL, 195, MSG_ROLES, "Roles:") FB_IMPL_MSG_SYMBOL(ISQL, 196, NO_TIMEOUTS, "Timeouts are not supported by server") +FB_IMPL_MSG_SYMBOL(ISQL, 197, NO_TABLESPACE, "There is no tablespace @1 in this database") +FB_IMPL_MSG_SYMBOL(ISQL, 198, NO_TABLESPACES, "There are no tablespaces in this database") +FB_IMPL_MSG_SYMBOL(ISQL, 199, MSG_TABLESPACES, "Tablespaces:") diff --git a/src/include/firebird/impl/msg/jrd.h b/src/include/firebird/impl/msg/jrd.h index 808e2d6f56d..acdf7ab4619 100644 --- a/src/include/firebird/impl/msg/jrd.h +++ b/src/include/firebird/impl/msg/jrd.h @@ -958,3 +958,6 @@ FB_IMPL_MSG(JRD, 956, sysf_invalid_null_empty, -901, "22", "023", "Empty or NULL FB_IMPL_MSG(JRD, 957, bad_loctab_num, -901, "HY", "000", "Undefined local table number @1") FB_IMPL_MSG(JRD, 958, quoted_str_bad, -901, "22", "024", "Invalid text <@1> after quoted string") FB_IMPL_MSG(JRD, 959, quoted_str_miss, -901, "22", "024", "Missing terminating quote <@1> in the end of quoted string") +FB_IMPL_MSG(JRD, 960, ts_file_exists, -902, "08", "001", "Tablespace \"@1\" creation error. File \"@2\" exists.") +FB_IMPL_MSG(JRD, 961, tablespace_name, -901, "42", "000", "TABLESPACE @1") +FB_IMPL_MSG(JRD, 962, ts_file_not_exists, -902, "08", "001", "Tablespace \"@1\" alteration error. File \"@2\" does not exist.") diff --git a/src/include/firebird/impl/msg/jrd_bugchk.h b/src/include/firebird/impl/msg/jrd_bugchk.h index 48bee23cd43..f3d0ffe7be8 100644 --- a/src/include/firebird/impl/msg/jrd_bugchk.h +++ b/src/include/firebird/impl/msg/jrd_bugchk.h @@ -158,3 +158,4 @@ FB_IMPL_MSG_NO_SYMBOL(JRD_BUGCHK, 303, "Invalid expression for evaluation") FB_IMPL_MSG_SYMBOL(JRD_BUGCHK, 304, rdb$triggers_rdb$flags_corrupt, "RDB$FLAGS for trigger @1 in RDB$TRIGGERS is corrupted") FB_IMPL_MSG_NO_SYMBOL(JRD_BUGCHK, 305, "Blobs accounting is inconsistent") FB_IMPL_MSG_NO_SYMBOL(JRD_BUGCHK, 306, "Found array data type with more than 16 dimensions") +FB_IMPL_MSG_NO_SYMBOL(JRD_BUGCHK, 307, "Tablespace not found") diff --git a/src/include/firebird/impl/msg/sqlerr.h b/src/include/firebird/impl/msg/sqlerr.h index 25a7014b0c4..a33e515a46c 100644 --- a/src/include/firebird/impl/msg/sqlerr.h +++ b/src/include/firebird/impl/msg/sqlerr.h @@ -283,3 +283,8 @@ FB_IMPL_MSG(SQLERR, 1043, dsql_string_byte_length, -901, "42", "000", "String li FB_IMPL_MSG(SQLERR, 1044, dsql_string_char_length, -901, "42", "000", "String literal with @1 characters exceeds the maximum length of @2 characters for the @3 character set") FB_IMPL_MSG(SQLERR, 1045, dsql_max_nesting, -901, "07", "002", "Too many BEGIN...END nesting. Maximum level is @1") FB_IMPL_MSG(SQLERR, 1046, dsql_recreate_user_failed, -901, "42", "000", "RECREATE USER @1 failed") +FB_IMPL_MSG(SQLERR, 1047, dsql_create_ts_failed, -901, "42", "000", "CREATE TABLESPACE @1 failed") +FB_IMPL_MSG(SQLERR, 1048, dsql_alter_ts_failed, -901, "42", "000", "ALTER TABLESPACE @1 failed") +FB_IMPL_MSG(SQLERR, 1049, dsql_create_alter_ts_failed, -901, "42", "000", "CREATE OR ALTER TABLESPACE @1 failed") +FB_IMPL_MSG(SQLERR, 1050, dsql_drop_ts_failed, -901, "42", "000", "DROP TABLESPACE @1 failed") +FB_IMPL_MSG(SQLERR, 1051, dsql_recreate_ts_failed, -901, "42", "000", "RECREATE TABLESPACE @1 failed") diff --git a/src/include/gen/Firebird.pas b/src/include/gen/Firebird.pas index 7f9f615e1d2..169a8d78bec 100644 --- a/src/include/gen/Firebird.pas +++ b/src/include/gen/Firebird.pas @@ -5154,6 +5154,9 @@ IReplicatedSessionImpl = class(IReplicatedSession) isc_bad_loctab_num = 335545277; isc_quoted_str_bad = 335545278; isc_quoted_str_miss = 335545279; + isc_ts_file_exists = 335545280; + isc_tablespace_name = 335545281; + isc_ts_file_not_exists = 335545282; isc_gfix_db_name = 335740929; isc_gfix_invalid_sw = 335740930; isc_gfix_incmp_sw = 335740932; @@ -5310,6 +5313,9 @@ IReplicatedSessionImpl = class(IReplicatedSession) isc_dyn_exc_not_exist = 336068915; isc_dyn_gen_not_exist = 336068916; isc_dyn_fld_not_exist = 336068917; + isc_dyn_ts_not_found = 336068918; + isc_dyn_cant_set_ts_table = 336068919; + isc_dyn_cant_set_ts_index = 336068920; isc_gbak_unknown_switch = 336330753; isc_gbak_page_size_missing = 336330754; isc_gbak_page_size_toobig = 336330755; @@ -5538,6 +5544,11 @@ IReplicatedSessionImpl = class(IReplicatedSession) isc_dsql_string_char_length = 336397332; isc_dsql_max_nesting = 336397333; isc_dsql_recreate_user_failed = 336397334; + isc_dsql_create_ts_failed = 336397335; + isc_dsql_alter_ts_failed = 336397336; + isc_dsql_create_alter_ts_failed = 336397337; + isc_dsql_drop_ts_failed = 336397338; + isc_dsql_recreate_ts_failed = 336397339; isc_gsec_cant_open_db = 336723983; isc_gsec_switches_error = 336723984; isc_gsec_no_op_spec = 336723985; From 9ff293de46afbe9688c154b5ee4edfbbc1192c3d Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Tue, 12 Apr 2022 14:39:03 +0300 Subject: [PATCH 59/97] Fix build --- src/burp/burp.cpp | 4 ++-- src/burp/restore.epp | 5 +++-- src/dsql/DdlNodes.epp | 4 ++-- src/dsql/TablespaceNodes.epp | 2 +- src/dsql/parse-conflicts.txt | 2 +- src/isql/isql.h | 4 ---- src/jrd/scl.epp | 2 +- 7 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/burp/burp.cpp b/src/burp/burp.cpp index da9ed3ad3cd..a8516809a39 100644 --- a/src/burp/burp.cpp +++ b/src/burp/burp.cpp @@ -1094,8 +1094,8 @@ int gbak(Firebird::UtilSvc* uSvc) } { - string ts_name = argv[++itr]; - string ts_path = argv[++itr]; + Firebird::string ts_name = argv[++itr]; + Firebird::string ts_path = argv[++itr]; if (ts_name.length() && ts_path.length()) tdgbl->tablespace_mapping.put(ts_name, ts_path); diff --git a/src/burp/restore.epp b/src/burp/restore.epp index f9083ca1edd..b7639ac5d5a 100644 --- a/src/burp/restore.epp +++ b/src/burp/restore.epp @@ -59,6 +59,7 @@ #include "memory_routines.h" #include "../burp/OdsDetection.h" #include "../auth/trusted/AuthSspi.h" +#include "../common/os/path_utils.h" #include "../common/dsc_proto.h" #include "../common/ThreadStart.h" #include "../common/db_alias.h" @@ -7534,12 +7535,12 @@ bool get_tablespace(BurpGlobals* tdgbl) break; case att_ts_offline: - X.RDB$OFFLINE = (USHORT) get_boolean(tdgbl); + X.RDB$OFFLINE = (USHORT) get_boolean(tdgbl, false); X.RDB$OFFLINE.NULL = FALSE; break; case att_ts_readonly: - X.RDB$READ_ONLY = (USHORT) get_boolean(tdgbl); + X.RDB$READ_ONLY = (USHORT) get_boolean(tdgbl, false); X.RDB$READ_ONLY.NULL = FALSE; break; diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index affe17e2c9f..3d7dcc384a2 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -8506,7 +8506,7 @@ void DropRelationNode::dropRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlSc R IN RDB$RELATIONS WITH R.RDB$RELATION_NAME EQ name.c_str() { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, ddlTriggerAction, name, NULL); + executeDdlTrigger(tdbb, transaction, DTW_BEFORE, ddlTriggerAction, name, NULL, *dsqlScratch->getDsqlStatement()->getSqlText()); found = true; } END_FOR @@ -8668,7 +8668,7 @@ void DropRelationNode::dropRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlSc END_FOR if (found) - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, ddlTriggerAction, name, NULL); + executeDdlTrigger(tdbb, transaction, DTW_AFTER, ddlTriggerAction, name, NULL, *dsqlScratch->getDsqlStatement()->getSqlText()); else { // msg 61: "Relation not found" diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index 399353c3e5f..778d7639c98 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -74,7 +74,7 @@ void CreateAlterTablespaceNode::checkPermission(thread_db* tdbb, jrd_tra* transa if (alter) SCL_check_tablespace(tdbb, &dscName, SCL_alter); else - SCL_check_create_access(tdbb, SCL_object_tablespace); + SCL_check_create_access(tdbb, obj_tablespaces); } diff --git a/src/dsql/parse-conflicts.txt b/src/dsql/parse-conflicts.txt index 4f6d64b6ca2..3aa1a7da911 100644 --- a/src/dsql/parse-conflicts.txt +++ b/src/dsql/parse-conflicts.txt @@ -1 +1 @@ -73 shift/reduce conflicts, 25 reduce/reduce conflicts. +74 shift/reduce conflicts, 23 reduce/reduce conflicts. diff --git a/src/isql/isql.h b/src/isql/isql.h index dc8623c4d1c..4c400401380 100644 --- a/src/isql/isql.h +++ b/src/isql/isql.h @@ -121,10 +121,6 @@ const int ISQL_MSG_FAC = FB_IMPL_MSG_FACILITY_ISQL; #undef FB_IMPL_MSG_SYMBOL #undef FB_IMPL_MSG -//TODO: Fix message numbers here and in messages2.sql -const int NO_TABLESPACE = 1022; // There is no tablespace @1 in this database -const int NO_TABLESPACES = 1023; // There are no tablespaces in this database -const int MSG_TABLESPACES = 1024; // Tablespaces: // Initialize types diff --git a/src/jrd/scl.epp b/src/jrd/scl.epp index 5ee976d387a..53dcd7757f9 100644 --- a/src/jrd/scl.epp +++ b/src/jrd/scl.epp @@ -864,7 +864,7 @@ void SCL_check_tablespace(thread_db* tdbb, const dsc* dsc_name, SecurityClass::f } END_FOR - SCL_check_access(tdbb, s_class, 0, name, mask, SCL_object_tablespace, false, name); + SCL_check_access(tdbb, s_class, 0, name, mask, obj_tablespaces, false, name); } From bb40f20ad9bf78539af0eaebe7518054d1de33af Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Tue, 12 Apr 2022 14:41:00 +0300 Subject: [PATCH 60/97] Fix assertion at TipCache::generateStatementId() --- src/jrd/Database.cpp | 8 ++++---- src/jrd/tpc_proto.h | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/jrd/Database.cpp b/src/jrd/Database.cpp index 70107785f4c..f5bdfcad2c0 100644 --- a/src/jrd/Database.cpp +++ b/src/jrd/Database.cpp @@ -77,27 +77,27 @@ namespace Jrd void Database::assignLatestAttachmentId(AttNumber number) { - if (dbb_tip_cache) + if (dbb_tip_cache && dbb_tip_cache->isInitialized()) dbb_tip_cache->assignLatestAttachmentId(number); } StmtNumber Database::generateStatementId() { - if (!dbb_tip_cache) + if (!dbb_tip_cache || !dbb_tip_cache->isInitialized()) return 0; return dbb_tip_cache->generateStatementId(); } AttNumber Database::getLatestAttachmentId() const { - if (!dbb_tip_cache) + if (!dbb_tip_cache || !dbb_tip_cache->isInitialized()) return 0; return dbb_tip_cache->getLatestAttachmentId(); } StmtNumber Database::getLatestStatementId() const { - if (!dbb_tip_cache) + if (!dbb_tip_cache || !dbb_tip_cache->isInitialized()) return 0; return dbb_tip_cache->getLatestStatementId(); } diff --git a/src/jrd/tpc_proto.h b/src/jrd/tpc_proto.h index ff0c01471b8..4a4e38bcddb 100644 --- a/src/jrd/tpc_proto.h +++ b/src/jrd/tpc_proto.h @@ -147,6 +147,11 @@ class TipCache return m_tpcHeader->getHeader()->latest_commit_number.load(std::memory_order_acquire); } + bool isInitialized() + { + return m_tpcHeader; + } + private: class GlobalTpcHeader : public Firebird::MemoryHeader { From 9e07d5c7a2bc88f86a04ba6b195df0d0baaa45d8 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 15 Apr 2022 14:45:49 +0300 Subject: [PATCH 61/97] Fix usage of tablespaces-related messages --- src/burp/backup.epp | 6 +++--- src/burp/burp.cpp | 7 ++++--- src/burp/restore.epp | 8 ++++---- src/include/firebird/impl/msg/gbak.h | 1 + 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/burp/backup.epp b/src/burp/backup.epp index d5226a6f997..a545f76e1ef 100644 --- a/src/burp/backup.epp +++ b/src/burp/backup.epp @@ -347,7 +347,7 @@ int BACKUP_backup(const TEXT* dbb_file, const TEXT* file_name) if (tdgbl->runtimeODS >= DB_VERSION_DDL13) // TODO: fix version { // Write tablespaces - BURP_verbose(403); // msg 403 writing tablespaces + BURP_verbose(406); // msg 406 writing tablespaces write_tablespaces(); } // Now go back and write all data @@ -422,7 +422,7 @@ int BACKUP_backup(const TEXT* dbb_file, const TEXT* file_name) if (tdgbl->runtimeODS >= DB_VERSION_DDL13) { // Write publications - BURP_verbose(403); // msg 403 writing publications + BURP_verbose(396); // msg 396 writing publications write_publications(); write_pub_tables(); @@ -4270,7 +4270,7 @@ void write_tablespaces() const SSHORT l = PUT_TEXT(att_ts_name, X.RDB$TABLESPACE_NAME); MISC_terminate(X.RDB$TABLESPACE_NAME, temp, l, sizeof(temp)); - BURP_verbose(404, temp); // msg 404 writing tablespace @1 + BURP_verbose(407, temp); // msg 407 writing tablespace @1 if (!X.RDB$SECURITY_CLASS.NULL) PUT_TEXT(att_ts_security_class, X.RDB$SECURITY_CLASS); diff --git a/src/burp/burp.cpp b/src/burp/burp.cpp index a8516809a39..cb990c87742 100644 --- a/src/burp/burp.cpp +++ b/src/burp/burp.cpp @@ -1077,7 +1077,8 @@ int gbak(Firebird::UtilSvc* uSvc) case IN_SW_BURP_TS_MAPPING_FILE: if (++itr >= argc) { - BURP_error(408, true); // msg 408 tablespace mapping file parameter missing + BURP_error(414, true, SafeArg() << in_sw_tab->in_sw_name); + // parameter for option -@1 is missing } tdgbl->loadMapping(argv[itr], tdgbl->tablespace_mapping, false); break; @@ -1089,7 +1090,7 @@ int gbak(Firebird::UtilSvc* uSvc) case IN_SW_BURP_TS_PATH: if (itr + 2 >= argc) { - BURP_error(1025, true, SafeArg() << in_sw_tab->in_sw_name); + BURP_error(414, true, SafeArg() << in_sw_tab->in_sw_name); // parameter for option -@1 is missing } @@ -2864,7 +2865,7 @@ void BurpGlobals::loadMapping(const char* mapping_file, StringMap& map, bool cle FILE* f = os_utils::fopen(mapping_file, fopen_read_type); if (!f) { - BURP_error(409, true, SafeArg() << mapping_file); // msg 409 cannot open mapping file @1 + BURP_error(415, true, SafeArg() << mapping_file); // msg 415 cannot open mapping file @1 } //Read lines from file, split by space and add to mapping diff --git a/src/burp/restore.epp b/src/burp/restore.epp index b7639ac5d5a..eaa8bd57628 100644 --- a/src/burp/restore.epp +++ b/src/burp/restore.epp @@ -7510,7 +7510,7 @@ bool get_tablespace(BurpGlobals* tdgbl) len = GET_TEXT(X.RDB$TABLESPACE_NAME); X.RDB$TABLESPACE_NAME.NULL = FALSE; MISC_terminate(X.RDB$TABLESPACE_NAME, temp, len, sizeof(temp)); - BURP_verbose(398, temp); // msg 398 restoring tablespace %s + BURP_verbose(408, temp); // msg 408 restoring tablespace %s break; case att_ts_security_class: @@ -7545,7 +7545,7 @@ bool get_tablespace(BurpGlobals* tdgbl) break; default: - bad_attribute(scan_next_attr, attribute, 399); // msg 399 tablespace + bad_attribute(scan_next_attr, attribute, 409); // msg 409 tablespace break; } } @@ -7579,8 +7579,8 @@ bool get_tablespace(BurpGlobals* tdgbl) } else if (!tdgbl->gbl_sw_ts_orig_paths) { - BURP_error(1022, false, SafeArg() << X.RDB$TABLESPACE_NAME << X.RDB$FILE_NAME); - // msg 1022 path to tablespace @1 is not specified (original path: "@2") + BURP_error(411, false, SafeArg() << X.RDB$TABLESPACE_NAME << X.RDB$FILE_NAME); + // msg 411 path to tablespace @1 is not specified (original path: "@2") return false; } } diff --git a/src/include/firebird/impl/msg/gbak.h b/src/include/firebird/impl/msg/gbak.h index f3178b9c684..52d26aa7ec7 100644 --- a/src/include/firebird/impl/msg/gbak.h +++ b/src/include/firebird/impl/msg/gbak.h @@ -410,3 +410,4 @@ FB_IMPL_MSG_NO_SYMBOL(GBAK, 411, "path to tablespace @1 is not specified (origin FB_IMPL_MSG_NO_SYMBOL(GBAK, 412, " @1TS_ORIG(INAL_PATHS) restore tablespaces to their original paths") FB_IMPL_MSG_NO_SYMBOL(GBAK, 413, " @1TS set a path for a tablespace") FB_IMPL_MSG_NO_SYMBOL(GBAK, 414, "parameter for option -@1 is missing") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 415, "cannot open mapping file \"@1\"") From 00cd26027c10816b692327910c4948284d00b882 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 15 Apr 2022 18:20:36 +0300 Subject: [PATCH 62/97] Increase ODS version to 14.0 and backup version to 12 --- src/burp/OdsDetection.epp | 2 +- src/burp/OdsDetection.h | 1 + src/burp/backup.epp | 13 +++++++++---- src/burp/burp.h | 4 +--- src/burp/restore.epp | 14 ++++++++++---- src/isql/extract.epp | 2 +- src/isql/show.epp | 2 +- src/jrd/ods.h | 15 +++++++++++---- src/jrd/relations.h | 31 +++++++++++++++---------------- 9 files changed, 50 insertions(+), 34 deletions(-) diff --git a/src/burp/OdsDetection.epp b/src/burp/OdsDetection.epp index deb3a3aec43..68d1d317e2d 100644 --- a/src/burp/OdsDetection.epp +++ b/src/burp/OdsDetection.epp @@ -45,7 +45,7 @@ namespace {"RDB$ROLES", 0, DB_VERSION_DDL9}, // IB5 {"RDB$PACKAGES", 0, DB_VERSION_DDL12}, // FB3 {"RDB$PUBLICATIONS", 0, DB_VERSION_DDL13}, // FB4 - {"RDB$TABLESPACES", 0, DB_VERSION_DDL13}, // TODO: fix version + {"RDB$TABLESPACES", 0, DB_VERSION_DDL14}, {0, 0, 0} }; diff --git a/src/burp/OdsDetection.h b/src/burp/OdsDetection.h index 830e459b03f..bd00fef2527 100644 --- a/src/burp/OdsDetection.h +++ b/src/burp/OdsDetection.h @@ -69,6 +69,7 @@ const int DB_VERSION_DDL11_1 = 111; // ods11.1 db, FB2.1 const int DB_VERSION_DDL11_2 = 112; // ods11.2 db, FB2.5 const int DB_VERSION_DDL12 = 120; // ods12.0 db, FB3.0 const int DB_VERSION_DDL13 = 130; // ods13.0 db, FB4.0 +const int DB_VERSION_DDL14 = 140; const int DB_VERSION_OLDEST_SUPPORTED = DB_VERSION_DDL8; // IB4.0 is ods8 diff --git a/src/burp/backup.epp b/src/burp/backup.epp index a545f76e1ef..8b1f91cc3f4 100644 --- a/src/burp/backup.epp +++ b/src/burp/backup.epp @@ -344,7 +344,7 @@ int BACKUP_backup(const TEXT* dbb_file, const TEXT* file_name) write_packages(); } - if (tdgbl->runtimeODS >= DB_VERSION_DDL13) // TODO: fix version + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) { // Write tablespaces BURP_verbose(406); // msg 406 writing tablespaces @@ -701,7 +701,8 @@ burp_fld* get_fields( burp_rel* relation) field->fld_identity_type = X.RDB$IDENTITY_TYPE; } - if (!X.RDB$TABLESPACE_NAME.NULL) + // ODS 14 + if (!X.RDB$TABLESPACE_NAME.NULL) // For older ODS NULL is expected here COPY(X.RDB$TABLESPACE_NAME, field->fld_tablespace); field_list.add(field); @@ -1845,8 +1846,11 @@ void put_index( burp_rel* relation) put_blr_blob (att_index_expression_blr, X.RDB$EXPRESSION_BLR); if (!X.RDB$FOREIGN_KEY.NULL) PUT_TEXT (att_index_foreign_key, X.RDB$FOREIGN_KEY); - if (!X.RDB$TABLESPACE_NAME.NULL) // For old versions I expect it will be NULL here. Right? + + // ODS 14 + if (!X.RDB$TABLESPACE_NAME.NULL) // For older ODS NULL is expected here PUT_TEXT(att_index_tablespace_name, X.RDB$TABLESPACE_NAME); + put(tdgbl, att_end); END_FOR; @@ -3955,7 +3959,8 @@ void write_relations() if (!X.RDB$SQL_SECURITY.NULL) put_boolean(att_relation_sql_security, X.RDB$SQL_SECURITY); - if (!X.RDB$TABLESPACE_NAME.NULL) // For old versions I expect it will be NULL here. Right? + // ODS 14 + if (!X.RDB$TABLESPACE_NAME.NULL) // For older ODS NULL is expected here PUT_TEXT(att_relation_tablespace_name, X.RDB$TABLESPACE_NAME); put(tdgbl, att_end); diff --git a/src/burp/burp.h b/src/burp/burp.h index 7890f1d336f..93dec7d3cf2 100644 --- a/src/burp/burp.h +++ b/src/burp/burp.h @@ -207,7 +207,7 @@ Version 11: FB4.0. SQL SECURITY feature, tables RDB$PUBLICATIONS/RDB$PUBLICATION_TABLES. */ -const int ATT_BACKUP_FORMAT = 11; +const int ATT_BACKUP_FORMAT = 12; // max array dimension @@ -340,8 +340,6 @@ enum att_type { att_field_owner_name, // FB3.0, ODS12_0, att_field_generator_name, att_field_identity_type, - - //TODO: FB???.???, ODS???_??? att_field_tablespace_name, // Index attributes diff --git a/src/burp/restore.epp b/src/burp/restore.epp index eaa8bd57628..48094810ec9 100644 --- a/src/burp/restore.epp +++ b/src/burp/restore.epp @@ -4360,6 +4360,7 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation) // ODS 12 X.RDB$GENERATOR_NAME.NULL = TRUE; X.RDB$IDENTITY_TYPE.NULL = TRUE; + // ODS 14 X.RDB$TABLESPACE_NAME.NULL = TRUE; skip_init(&scan_next_attr); @@ -4530,6 +4531,8 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation) X.RDB$IDENTITY_TYPE = field->fld_identity_type; break; + // ODS 14 + case att_field_tablespace_name: GET_TEXT(X.RDB$TABLESPACE_NAME); X.RDB$TABLESPACE_NAME.NULL = FALSE; @@ -7122,6 +7125,7 @@ bool get_index(BurpGlobals* tdgbl, const burp_rel* relation) X.RDB$EXPRESSION_BLR.NULL = TRUE; X.RDB$SYSTEM_FLAG = 0; X.RDB$SYSTEM_FLAG.NULL = FALSE; + // ODS 14 X.RDB$TABLESPACE_NAME.NULL = TRUE; skip_init(&scan_next_attr); @@ -7215,6 +7219,8 @@ bool get_index(BurpGlobals* tdgbl, const burp_rel* relation) GET_TEXT(X.RDB$FOREIGN_KEY); break; + // ODS 14 + case att_index_tablespace_name: GET_TEXT(X.RDB$TABLESPACE_NAME); X.RDB$TABLESPACE_NAME.NULL = FALSE; @@ -7481,9 +7487,7 @@ bool get_tablespace(BurpGlobals* tdgbl) SSHORT len; scan_attr_t scan_next_attr; - // TODO: Fix format version for the current version after merge. - // Check other places of RDB$TABLESPACE_NAME usage - if (tdgbl->RESTORE_format < 11) + if (tdgbl->RESTORE_format < 12) // Probably this check is not needed return false; // Firebird::ITransaction* local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans; @@ -8643,7 +8647,6 @@ bool get_relation(BurpGlobals* tdgbl) X.RDB$EXTERNAL_FILE.NULL = ext_file_name_null; X.RDB$RELATION_TYPE.NULL = FALSE; X.RDB$SQL_SECURITY.NULL = sql_security_null; - X.RDB$TABLESPACE_NAME.NULL = tableSpaceNull; X.RDB$SYSTEM_FLAG = (USHORT) sys_flag; X.RDB$FLAGS = (USHORT) rel_flags; @@ -8658,6 +8661,9 @@ bool get_relation(BurpGlobals* tdgbl) X.RDB$RELATION_TYPE = (USHORT) type; X.RDB$SQL_SECURITY = (FB_BOOLEAN) sql_security; + + // ODS 14 + X.RDB$TABLESPACE_NAME.NULL = tableSpaceNull; strcpy(X.RDB$TABLESPACE_NAME, tableSpace); END_STORE; diff --git a/src/isql/extract.epp b/src/isql/extract.epp index 94040fc8091..42066b5dccb 100644 --- a/src/isql/extract.epp +++ b/src/isql/extract.epp @@ -3614,7 +3614,7 @@ static void list_tablespaces() * **************************************/ - if (isqlGlob.major_ods < ODS_VERSION13) + if (isqlGlob.major_ods < ODS_VERSION14) return; bool first = true; diff --git a/src/isql/show.epp b/src/isql/show.epp index 9d53210c728..c9a3af04978 100644 --- a/src/isql/show.epp +++ b/src/isql/show.epp @@ -4970,7 +4970,7 @@ static processing_state show_tablespaces(const SCHAR* tablespace_name) * Functional description * Show all tablespaces or the named tablespace ************************************/ - if (isqlGlob.major_ods < ODS_VERSION12) //TODO: fix ODS version + if (isqlGlob.major_ods < ODS_VERSION14) return OBJECT_NOT_FOUND; bool first = true; diff --git a/src/jrd/ods.h b/src/jrd/ods.h index 4dd7b082a6b..9a758733a9c 100644 --- a/src/jrd/ods.h +++ b/src/jrd/ods.h @@ -70,6 +70,7 @@ const USHORT ODS_VERSION10 = 10; // V6.0 features. SQL delimited idetifier, const USHORT ODS_VERSION11 = 11; // Firebird 2.x features const USHORT ODS_VERSION12 = 12; // Firebird 3.x features const USHORT ODS_VERSION13 = 13; // Firebird 4.x features +const USHORT ODS_VERSION14 = 14; // ODS minor version -- minor versions ARE compatible, but may be // increasingly functional. Add new minor versions, but leave previous @@ -126,6 +127,11 @@ const USHORT ODS_CURRENT13_0 = 0; // Firebird 4.0 features const USHORT ODS_CURRENT13_1 = 1; // Firebird 4.1 features const USHORT ODS_CURRENT13 = 1; +// Minor versions for ODS 14 + +const USHORT ODS_CURRENT14_0 = 0; +const USHORT ODS_CURRENT14 = 0; + // useful ODS macros. These are currently used to flag the version of the // system triggers and system indices in ini.e @@ -146,6 +152,7 @@ const USHORT ODS_11_2 = ENCODE_ODS(ODS_VERSION11, 2); const USHORT ODS_12_0 = ENCODE_ODS(ODS_VERSION12, 0); const USHORT ODS_13_0 = ENCODE_ODS(ODS_VERSION13, 0); const USHORT ODS_13_1 = ENCODE_ODS(ODS_VERSION13, 1); +const USHORT ODS_14_0 = ENCODE_ODS(ODS_VERSION14, 0); const USHORT ODS_FIREBIRD_FLAG = 0x8000; @@ -164,16 +171,16 @@ inline USHORT DECODE_ODS_MINOR(USHORT ods_version) // Set current ODS major and minor version -const USHORT ODS_VERSION = ODS_VERSION13; // Current ODS major version -- always +const USHORT ODS_VERSION = ODS_VERSION14; // Current ODS major version -- always // the highest. -const USHORT ODS_RELEASED = ODS_CURRENT13_0; // The lowest stable minor version +const USHORT ODS_RELEASED = ODS_CURRENT14_0; // The lowest stable minor version // number for this ODS_VERSION! -const USHORT ODS_CURRENT = ODS_CURRENT13; // The highest defined minor version +const USHORT ODS_CURRENT = ODS_CURRENT14; // The highest defined minor version // number for this ODS_VERSION! -const USHORT ODS_CURRENT_VERSION = ODS_13_1; // Current ODS version in use which includes +const USHORT ODS_CURRENT_VERSION = ODS_14_0; // Current ODS version in use which includes // both major and minor ODS versions! diff --git a/src/jrd/relations.h b/src/jrd/relations.h index 27bbd61da96..d8e9bb22691 100644 --- a/src/jrd/relations.h +++ b/src/jrd/relations.h @@ -99,7 +99,7 @@ RELATION(nam_indices, rel_indices, ODS_8_0, rel_persistent) FIELD(f_idx_exp_blr, nam_exp_blr, fld_value, 1, ODS_8_0) FIELD(f_idx_exp_source, nam_exp_source, fld_source, 1, ODS_8_0) FIELD(f_idx_statistics, nam_statistics, fld_statistics, 1, ODS_8_0) - FIELD(f_idx_ts_name, nam_ts_name, fld_ts_name, 1, ODS_13_0) // TODO: fix ODS version + FIELD(f_idx_ts_name, nam_ts_name, fld_ts_name, 1, ODS_14_0) END_RELATION // Relation 5 (RDB$RELATION_FIELDS) @@ -125,7 +125,7 @@ RELATION(nam_r_fields, rel_rfr, ODS_8_0, rel_persistent) FIELD(f_rfr_coll_id, nam_collate_id, fld_collate_id, 1, ODS_8_0) FIELD(f_rfr_gen_name, nam_gen_name, fld_gen_name, 1, ODS_12_0) FIELD(f_rfr_identity_type, nam_identity_type, fld_identity_type, 1, ODS_12_0) - FIELD(f_rfr_ts_name, nam_ts_name, fld_ts_name, 1, ODS_13_0) // TODO: fix ODS version + FIELD(f_rfr_ts_name, nam_ts_name, fld_ts_name, 1, ODS_14_0) END_RELATION // Relation 6 (RDB$RELATIONS) @@ -148,9 +148,9 @@ RELATION(nam_relations, rel_relations, ODS_8_0, rel_persistent) FIELD(f_rel_flags, nam_flags, fld_flag_nullable, 0, ODS_8_0) FIELD(f_rel_type, nam_r_type, fld_r_type, 0, ODS_11_1) FIELD(f_rel_sql_security, nam_sql_security, fld_b_sql_security, 1, ODS_13_0) - FIELD(f_rel_ts_name, nam_ts_name, fld_ts_name, 1, ODS_13_0) //TODO: fix ODS version - FIELD(f_rel_first_pp, nam_pp_number, fld_pp_number, 0, ODS_13_0) //TODO: fix ODS version - FIELD(f_rel_idx_root, nam_idx_number, fld_idx_number, 0, ODS_13_0) //TODO: fix ODS version + FIELD(f_rel_ts_name, nam_ts_name, fld_ts_name, 1, ODS_14_0) + FIELD(f_rel_first_pp, nam_pp_number, fld_pp_number, 0, ODS_14_0) + FIELD(f_rel_idx_root, nam_idx_number, fld_idx_number, 0, ODS_14_0) END_RELATION // Relation 7 (RDB$VIEW_RELATIONS) @@ -760,15 +760,14 @@ RELATION(nam_mon_compiled_statements, rel_mon_compiled_statements, ODS_13_1, rel END_RELATION // Relation 56 (RDB$TABLESPACES) -// TODO: fix ODS version -RELATION(nam_tablespaces, rel_tablespaces, ODS_13_1, rel_persistent) - FIELD(f_ts_id, nam_ts_id, fld_ts_id, 0, ODS_13_1) - FIELD(f_ts_name, nam_ts_name, fld_ts_name, 1, ODS_13_1) - FIELD(f_ts_class, nam_class, fld_class, 1, ODS_13_1) - FIELD(f_ts_sys_flag, nam_sys_flag, fld_flag, 1, ODS_13_1) - FIELD(f_ts_desc, nam_description, fld_description, 1, ODS_13_1) - FIELD(f_ts_owner, nam_owner, fld_user, 1, ODS_13_1) - FIELD(f_ts_file, nam_file_name, fld_file_name, 1, ODS_13_1) - FIELD(f_ts_offline, nam_ts_offline, fld_bool, 1, ODS_13_1) - FIELD(f_ts_readonly, nam_ts_readonly, fld_bool, 1, ODS_13_1) +RELATION(nam_tablespaces, rel_tablespaces, ODS_14_0, rel_persistent) + FIELD(f_ts_id, nam_ts_id, fld_ts_id, 0, ODS_14_0) + FIELD(f_ts_name, nam_ts_name, fld_ts_name, 1, ODS_14_0) + FIELD(f_ts_class, nam_class, fld_class, 1, ODS_14_0) + FIELD(f_ts_sys_flag, nam_sys_flag, fld_flag, 1, ODS_14_0) + FIELD(f_ts_desc, nam_description, fld_description, 1, ODS_14_0) + FIELD(f_ts_owner, nam_owner, fld_user, 1, ODS_14_0) + FIELD(f_ts_file, nam_file_name, fld_file_name, 1, ODS_14_0) + FIELD(f_ts_offline, nam_ts_offline, fld_bool, 1, ODS_14_0) + FIELD(f_ts_readonly, nam_ts_readonly, fld_bool, 1, ODS_14_0) END_RELATION From 1557ca5b82d37b341053e64a1ba469ddd7283415 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Wed, 4 May 2022 18:32:36 +0300 Subject: [PATCH 63/97] Undo changes which are not related to tablespaces --- src/jrd/dpm.epp | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/jrd/dpm.epp b/src/jrd/dpm.epp index ac91ce8f0c8..76a54ebe9df 100644 --- a/src/jrd/dpm.epp +++ b/src/jrd/dpm.epp @@ -665,21 +665,10 @@ ULONG DPM_data_pages(thread_db* tdbb, jrd_rel* relation) RelationPages* relPages = relation->getPages(tdbb); ULONG pages = relPages->rel_data_pages; - ULONG step = 1; - if (!pages) { - const size_t ppCount = relPages->rel_pages ? relPages->rel_pages->count() : 0; - const ULONG PAGES_LIMIT = 100; - - if (ppCount > PAGES_LIMIT) - { - step = ppCount / PAGES_LIMIT + 1; - DPM_scan_pages(tdbb, pag_pointer); - } - WIN window(relPages->rel_pg_space_id, -1); - for (ULONG sequence = 0; (step == 1) || (sequence < ppCount); sequence += step) + for (ULONG sequence = 0; true; sequence++) { const pointer_page* ppage = get_pointer_page(tdbb, relation, relPages, &window, sequence, LCK_read); @@ -698,16 +687,14 @@ ULONG DPM_data_pages(thread_db* tdbb, jrd_rel* relation) } if (ppage->ppg_header.pag_flags & ppg_eof) - { - CCH_RELEASE(tdbb, &window); break; - } CCH_RELEASE(tdbb, &window); tdbb->checkCancelState(); } + CCH_RELEASE(tdbb, &window); relPages->rel_data_pages = pages; } @@ -716,7 +703,7 @@ ULONG DPM_data_pages(thread_db* tdbb, jrd_rel* relation) " returned pages: %" ULONGFORMAT"\n", pages); #endif - return pages * step; + return pages; } From 9f3fa6baa099b777a02977c39e23e223565c5217 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 5 May 2022 10:49:45 +0300 Subject: [PATCH 64/97] Remove unused BTR_delete_index argument --- src/jrd/btr.cpp | 4 ++-- src/jrd/btr_proto.h | 2 +- src/jrd/dfw.epp | 2 +- src/jrd/idx.cpp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index a54f3860f29..cc3a56cef26 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -446,7 +446,7 @@ void BTR_create(thread_db* tdbb, } -bool BTR_delete_index(thread_db* tdbb, Jrd::jrd_rel* relation, WIN* window, USHORT id) +bool BTR_delete_index(thread_db* tdbb, WIN* window, USHORT id) { /************************************** * @@ -1835,7 +1835,7 @@ bool BTR_next_index(thread_db* tdbb, jrd_rel* relation, jrd_tra* transaction, in irt_desc = root->irt_rpt + id; if (irt_desc->getTransaction() == trans) - BTR_delete_index(tdbb, relation, window, id); + BTR_delete_index(tdbb, window, id); else CCH_RELEASE(tdbb, window); diff --git a/src/jrd/btr_proto.h b/src/jrd/btr_proto.h index aeb669313c1..b318e33774f 100644 --- a/src/jrd/btr_proto.h +++ b/src/jrd/btr_proto.h @@ -32,7 +32,7 @@ void BTR_all(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::IndexDescList&, Jrd::RelationPages*); void BTR_complement_key(Jrd::temporary_key*); void BTR_create(Jrd::thread_db*, Jrd::IndexCreation&, Jrd::SelectivityList&); -bool BTR_delete_index(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::win*, USHORT); +bool BTR_delete_index(Jrd::thread_db*, Jrd::win*, USHORT); bool BTR_description(Jrd::thread_db*, Jrd::jrd_rel*, Ods::index_root_page*, Jrd::index_desc*, USHORT); DSC* BTR_eval_expression(Jrd::thread_db*, Jrd::index_desc*, Jrd::Record*, bool&); void BTR_evaluate(Jrd::thread_db*, const Jrd::IndexRetrieval*, Jrd::RecordBitmap**, Jrd::RecordBitmap*); diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 5a2f9103cbd..c0fc710d58a 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -3127,7 +3127,7 @@ static void cleanup_index_creation(thread_db* tdbb, DeferredWork* work, jrd_tra* WIN window(relPages->rel_pg_space_id, relPages->rel_index_root); CCH_FETCH(tdbb, &window, LCK_write, pag_root); CCH_MARK_MUST_WRITE(tdbb, &window); - const bool tree_exists = BTR_delete_index(tdbb, relation, &window, work->dfw_id); + const bool tree_exists = BTR_delete_index(tdbb, &window, work->dfw_id); if (!isTempIndex) { work->dfw_id = dbb->dbb_max_idx; diff --git a/src/jrd/idx.cpp b/src/jrd/idx.cpp index 526700b0cda..957e84fd8e4 100644 --- a/src/jrd/idx.cpp +++ b/src/jrd/idx.cpp @@ -610,7 +610,7 @@ void IDX_delete_index(thread_db* tdbb, jrd_rel* relation, USHORT id) WIN window(get_root_page(tdbb, relation)); CCH_FETCH(tdbb, &window, LCK_write, pag_root); - const bool tree_exists = BTR_delete_index(tdbb, relation, &window, id); + const bool tree_exists = BTR_delete_index(tdbb, &window, id); if ((relation->rel_flags & REL_temp_conn) && (relation->getPages(tdbb)->rel_instance_id != 0) && tree_exists) @@ -650,7 +650,7 @@ void IDX_delete_indices(thread_db* tdbb, jrd_rel* relation, RelationPages* relPa for (USHORT i = 0; i < root->irt_count; i++) { - const bool tree_exists = BTR_delete_index(tdbb, relation, &window, i); + const bool tree_exists = BTR_delete_index(tdbb, &window, i); root = (index_root_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_root); if (is_temp && tree_exists) From ca374ee78ca6ecee190281632a78dc4859db409c Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 5 May 2022 16:19:01 +0300 Subject: [PATCH 65/97] Remove unused function --- src/dsql/TablespaceNodes.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/dsql/TablespaceNodes.h b/src/dsql/TablespaceNodes.h index a624cade07c..ca74805ff63 100644 --- a/src/dsql/TablespaceNodes.h +++ b/src/dsql/TablespaceNodes.h @@ -94,8 +94,6 @@ class DropTablespaceNode : public DdlNode statusVector << Firebird::Arg::Gds(isc_dsql_drop_ts_failed) << name; } - void handleDependencies(thread_db* tdbb, jrd_tra* transaction, bool drop); - public: MetaName name; bool silent; From d898f74421199a5ea3a880a41a5bb5c3c211770c Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 5 May 2022 16:35:38 +0300 Subject: [PATCH 66/97] Correct copyright and comments --- src/isql/show.epp | 2 +- src/jrd/Tablespace.cpp | 29 +++++++++++++++-------------- src/jrd/Tablespace.h | 30 ++++++++++++++++-------------- src/jrd/dfw.epp | 6 +++--- src/jrd/dpm.epp | 4 ++-- src/jrd/idx.h | 2 +- src/jrd/irq.h | 2 +- 7 files changed, 39 insertions(+), 36 deletions(-) diff --git a/src/isql/show.epp b/src/isql/show.epp index c9a3af04978..2fa69e363d7 100644 --- a/src/isql/show.epp +++ b/src/isql/show.epp @@ -5001,7 +5001,7 @@ static processing_state show_tablespaces(const SCHAR* tablespace_name) X.RDB$TABLESPACE_NAME EQ tablespace_name first = false; - // Print the name of the package + fb_utils::exact_name(X.RDB$TABLESPACE_NAME); isqlGlob.printf("%s", X.RDB$TABLESPACE_NAME); diff --git a/src/jrd/Tablespace.cpp b/src/jrd/Tablespace.cpp index a511a066e88..2277d630fda 100644 --- a/src/jrd/Tablespace.cpp +++ b/src/jrd/Tablespace.cpp @@ -1,22 +1,23 @@ /* - * The contents of this file are subject to the Interbase Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy - * of the License at http://www.Inprise.com/IPL.html + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. * - * Software distributed under the License is distributed on an - * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express - * or implied. See the License for the specific language governing - * rights and limitations under the License. + * Software distributed under the License is distributed AS IS, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. + * See the License for the specific language governing rights + * and limitations under the License. * - * The Original Code was created by Inprise Corporation - * and its predecessors. Portions created by Inprise Corporation are - * Copyright (C) Inprise Corporation. + * The Original Code was created by Roman Simakov + * for the RedDatabase project. * - * All Rights Reserved. - * Contributor(s): ______________________________________. + * Copyright (c) 2018 + * and all contributors signed below. * - * Adriano dos Santos Fernandes + * All Rights Reserved. + * Contributor(s): ______________________________________. */ #include "firebird.h" diff --git a/src/jrd/Tablespace.h b/src/jrd/Tablespace.h index 0ca411d2f5c..035ca487d33 100644 --- a/src/jrd/Tablespace.h +++ b/src/jrd/Tablespace.h @@ -1,21 +1,23 @@ /* - * The contents of this file are subject to the Interbase Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy - * of the License at http://www.Inprise.com/IPL.html + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. * - * Software distributed under the License is distributed on an - * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express - * or implied. See the License for the specific language governing - * rights and limitations under the License. + * Software distributed under the License is distributed AS IS, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. + * See the License for the specific language governing rights + * and limitations under the License. * - * The Original Code was created by Inprise Corporation - * and its predecessors. Portions created by Inprise Corporation are - * Copyright (C) Inprise Corporation. + * The Original Code was created by Roman Simakov + * for the RedDatabase project. * - * All Rights Reserved. - * Contributor(s): ______________________________________. - * Roman Simakov + * Copyright (c) 2018 + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. */ #ifndef JRD_TABLESPACE_H diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index c0fc710d58a..57c11570f4f 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -6665,7 +6665,7 @@ static bool move_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd { /************************************** * - * move_relation + * m o v e _ r e l a t i o n * ************************************** * @@ -6729,7 +6729,7 @@ static bool move_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd relation->setReplacedPages(newRelationPages); { // We delete all from RDB$PAGES about the relation to have an ability to understand that - // we need to restore pages if transaction won't be able to finish succeccfully. + // we need to restore pages if transaction won't be able to finish successfully. AutoRequest handle; FOR(REQUEST_HANDLE handle) X IN RDB$PAGES @@ -6761,7 +6761,7 @@ static bool move_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tr { /************************************** * - * move_index + * m o v e _ i n d e x * ************************************** * diff --git a/src/jrd/dpm.epp b/src/jrd/dpm.epp index 76a54ebe9df..fc5c313e424 100644 --- a/src/jrd/dpm.epp +++ b/src/jrd/dpm.epp @@ -3959,8 +3959,8 @@ void DPM_move_data_pages(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, RelationP * - fix every PP by correcting DP numbers and ppg_next pointer and build a map * - walking through the map and copy every DP to the new one by fixing * b_page and f_page numbers. - * We expect that DPM_scan_pages was called. - * In the end of work replace records in RDB$PAGES. + * We expect that DPM_scan_pages has been called. + * At the end of work replace records in RDB$PAGES. * **************************************/ SET_TDBB(tdbb); diff --git a/src/jrd/idx.h b/src/jrd/idx.h index 736c35bba99..f9a592d16ec 100644 --- a/src/jrd/idx.h +++ b/src/jrd/idx.h @@ -304,7 +304,7 @@ static const struct ini_idx_t indices[] = SEGMENT(f_pubtab_tab_name, idx_string), // table name SEGMENT(f_pubtab_pub_name, idx_string) // publication name }}, - // define index RDB$INDEX_57 for RDB$TABLESPACES unique RDB$TABALESPACE_NAME; + // define index RDB$INDEX_57 for RDB$TABLESPACES unique RDB$TABLESPACE_NAME; INDEX(57, rel_tablespaces, idx_unique, 1) SEGMENT(f_ts_name, idx_metadata) // tablespace name }}, diff --git a/src/jrd/irq.h b/src/jrd/irq.h index fbf49e8eb93..2e8089eeab3 100644 --- a/src/jrd/irq.h +++ b/src/jrd/irq.h @@ -190,7 +190,7 @@ enum irq_type_t irq_list_ts_files, // list tablespace files irq_find_ts_dfw, // find tablespace options by name in dfw irq_find_ts_dfw0, // find tablespace options by name in dfw for cleanup - irq_scan_ts, // scn tablespaces + irq_scan_ts, // scan tablespaces irq_ts_security, // verify security for tablespace irq_r_pages2, irq_s_first_pp, From c1d6e880abf28f76ac0cc01848181ce65fbe9e70 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Thu, 5 May 2022 16:45:24 +0300 Subject: [PATCH 67/97] Correct code formatting --- src/CMakeLists.txt | 4 +- src/burp/backup.epp | 1 + src/burp/burp.cpp | 1 - src/burp/burpswi.h | 2 +- src/dsql/DdlNodes.epp | 461 ++++++++++++++++++----------------- src/dsql/DdlNodes.h | 2 +- src/dsql/TablespaceNodes.epp | 2 - src/isql/extract.epp | 6 +- src/isql/show.epp | 4 +- src/jrd/Statement.cpp | 2 +- src/jrd/Tablespace.h | 2 +- src/jrd/btr.cpp | 3 +- src/jrd/btr.h | 2 +- src/jrd/btr_proto.h | 3 +- src/jrd/cch.cpp | 6 +- src/jrd/dfw.epp | 16 +- src/jrd/dfw_proto.h | 2 +- src/jrd/dpm.epp | 1 - src/jrd/grant.epp | 32 +-- src/jrd/irq.h | 2 +- src/jrd/jrd.cpp | 4 +- src/jrd/met.epp | 94 +++---- src/jrd/pag.cpp | 4 +- src/jrd/pag.h | 18 +- src/jrd/vio.cpp | 1 + 25 files changed, 333 insertions(+), 342 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 989c8bc9586..c67d7c2fd68 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,7 +47,7 @@ set(epp_boot_gds_files dsql/metd.epp dsql/DdlNodes.epp dsql/PackageNodes.epp - dsql/TablespaceNodes.epp + dsql/TablespaceNodes.epp jrd/dfw.epp jrd/dpm.epp jrd/dyn_util.epp @@ -470,7 +470,7 @@ set(engine_generated_src dsql/DdlNodes.epp dsql/metd.epp dsql/PackageNodes.epp - dsql/TablespaceNodes.epp + dsql/TablespaceNodes.epp jrd/dfw.epp jrd/dpm.epp jrd/dyn_util.epp diff --git a/src/burp/backup.epp b/src/burp/backup.epp index 8b1f91cc3f4..c619c992da0 100644 --- a/src/burp/backup.epp +++ b/src/burp/backup.epp @@ -350,6 +350,7 @@ int BACKUP_backup(const TEXT* dbb_file, const TEXT* file_name) BURP_verbose(406); // msg 406 writing tablespaces write_tablespaces(); } + // Now go back and write all data for (burp_rel* relation = tdgbl->relations; relation; relation = relation->rel_next) diff --git a/src/burp/burp.cpp b/src/burp/burp.cpp index cb990c87742..0e29a64fdcf 100644 --- a/src/burp/burp.cpp +++ b/src/burp/burp.cpp @@ -2906,7 +2906,6 @@ void BurpGlobals::loadMapping(const char* mapping_file, StringMap& map, bool cle fclose(f); } - void BURP_makeSymbol(BurpGlobals* tdgbl, Firebird::string& name) // add double quotes to string { if (tdgbl->gbl_dialect < SQL_DIALECT_V6) diff --git a/src/burp/burpswi.h b/src/burp/burpswi.h index f1c128816b5..4979e810ca6 100644 --- a/src/burp/burpswi.h +++ b/src/burp/burpswi.h @@ -98,7 +98,7 @@ const int IN_SW_BURP_CRYPT = 51; // name of crypt plugin const int IN_SW_BURP_INCLUDE_DATA = 52; // backup data from tables const int IN_SW_BURP_REPLICA = 53; // replica mode -const int IN_SW_BURP_TS_MAPPING_FILE = 54; // mapping file for tablespaces +const int IN_SW_BURP_TS_MAPPING_FILE = 54; // mapping file for tablespaces const int IN_SW_BURP_TS_ORIGINAL_PATHS = 55; // restore tablespaces to their original paths const int IN_SW_BURP_TS_PATH = 56; // set a path for a tablespace diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 3d7dcc384a2..573d1d470ad 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -7847,6 +7847,39 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc break; } + case Clause::TYPE_ALTER_PUBLICATION: + { + fb_assert(replicationState.specified); + + if (replicationState.value) + { + // Add table to the publication + + try + { + RelationNode::addToPublication(tdbb, transaction, + name, DEFAULT_PUBLICATION); + } + catch (const status_exception& ex) + { + if (ex.value()[1] != isc_unique_key_violation) + throw; + + // Ignore duplicated records + fb_utils::init_status(tdbb->tdbb_status_vector); + } + } + else + { + // Drop table from the publication + + RelationNode::dropFromPublication(tdbb, transaction, + name, DEFAULT_PUBLICATION); + } + + break; + } + case Clause::TYPE_SET_TABLESPACE: { fb_assert(tableSpace.hasData()); @@ -7908,39 +7941,6 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc break; } - case Clause::TYPE_ALTER_PUBLICATION: - { - fb_assert(replicationState.specified); - - if (replicationState.value) - { - // Add table to the publication - - try - { - RelationNode::addToPublication(tdbb, transaction, - name, DEFAULT_PUBLICATION); - } - catch (const status_exception& ex) - { - if (ex.value()[1] != isc_unique_key_violation) - throw; - - // Ignore duplicated records - fb_utils::init_status(tdbb->tdbb_status_vector); - } - } - else - { - // Drop table from the publication - - RelationNode::dropFromPublication(tdbb, transaction, - name, DEFAULT_PUBLICATION); - } - - break; - } - default: fb_assert(false); break; @@ -8485,200 +8485,200 @@ void DropRelationNode::deleteGlobalField(thread_db* tdbb, jrd_tra* transaction, void DropRelationNode::dropRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, bool view, jrd_rel* rel_drop, const MetaName& name) { - if (!view && rel_drop) - { - RelationPages* relPages = rel_drop->getBasePages(); - if (!relPages->rel_pages || (relPages->rel_pages->count() == 0)) - DPM_scan_pages(tdbb, pag_pointer, rel_drop->rel_id); - if (!relPages->rel_index_root) - DPM_scan_pages(tdbb, pag_root, rel_drop->rel_id); - } - - const int ddlTriggerAction = (view ? DDL_TRIGGER_DROP_VIEW : DDL_TRIGGER_DROP_TABLE); - - // run all statements under savepoint control - AutoSavePoint savePoint(tdbb, transaction); - - AutoCacheRequest request(tdbb, drq_l_relation, DYN_REQUESTS); - bool found = false; - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - R IN RDB$RELATIONS - WITH R.RDB$RELATION_NAME EQ name.c_str() - { - executeDdlTrigger(tdbb, transaction, DTW_BEFORE, ddlTriggerAction, name, NULL, *dsqlScratch->getDsqlStatement()->getSqlText()); - found = true; - } - END_FOR - - request.reset(tdbb, drq_e_rel_con2, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - CRT IN RDB$RELATION_CONSTRAINTS - WITH CRT.RDB$RELATION_NAME EQ name.c_str() AND - (CRT.RDB$CONSTRAINT_TYPE EQ PRIMARY_KEY OR - CRT.RDB$CONSTRAINT_TYPE EQ UNIQUE_CNSTRT OR - CRT.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY) - SORTED BY ASCENDING CRT.RDB$CONSTRAINT_TYPE - { - ERASE CRT; - } - END_FOR - - request.reset(tdbb, drq_e_rel_idxs, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - IDX IN RDB$INDICES - WITH IDX.RDB$RELATION_NAME EQ name.c_str() - { - DropIndexNode::deleteSegmentRecords(tdbb, transaction, IDX.RDB$INDEX_NAME); - ERASE IDX; - } - END_FOR - - request.reset(tdbb, drq_e_trg_msgs2, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - TM IN RDB$TRIGGER_MESSAGES - CROSS T IN RDB$TRIGGERS - WITH T.RDB$RELATION_NAME EQ name.c_str() AND - TM.RDB$TRIGGER_NAME EQ T.RDB$TRIGGER_NAME - { - ERASE TM; - } - END_FOR - - // CVC: Moved this block here to avoid SF Bug #1111570. - request.reset(tdbb, drq_e_rel_con3, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - CRT IN RDB$RELATION_CONSTRAINTS - WITH CRT.RDB$RELATION_NAME EQ name.c_str() AND - (CRT.RDB$CONSTRAINT_TYPE EQ CHECK_CNSTRT OR - CRT.RDB$CONSTRAINT_TYPE EQ NOT_NULL_CNSTRT) - { - ERASE CRT; - } - END_FOR - - request.reset(tdbb, drq_e_rel_flds, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - RFR IN RDB$RELATION_FIELDS - WITH RFR.RDB$RELATION_NAME EQ name.c_str() - { - if (!RFR.RDB$GENERATOR_NAME.NULL) - DropSequenceNode::deleteIdentity(tdbb, transaction, RFR.RDB$GENERATOR_NAME); - - ERASE RFR; - - if (!RFR.RDB$SECURITY_CLASS.NULL && - !strncmp(RFR.RDB$SECURITY_CLASS, SQL_SECCLASS_PREFIX, SQL_SECCLASS_PREFIX_LEN)) - { - deleteSecurityClass(tdbb, transaction, RFR.RDB$SECURITY_CLASS); - } - - deleteGlobalField(tdbb, transaction, RFR.RDB$FIELD_SOURCE); - } - END_FOR - - request.reset(tdbb, drq_e_view_rels, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - VR IN RDB$VIEW_RELATIONS - WITH VR.RDB$VIEW_NAME EQ name.c_str() - { - ERASE VR; - } - END_FOR - - request.reset(tdbb, drq_e_relation, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - R IN RDB$RELATIONS - WITH R.RDB$RELATION_NAME EQ name.c_str() - { - ERASE R; - - if (!R.RDB$SECURITY_CLASS.NULL && - !strncmp(R.RDB$SECURITY_CLASS, SQL_SECCLASS_PREFIX, SQL_SECCLASS_PREFIX_LEN)) - { - deleteSecurityClass(tdbb, transaction, R.RDB$SECURITY_CLASS); - } - } - END_FOR - - if (!found) - { - // msg 61: "Relation not found" - status_exception::raise(Arg::PrivateDyn(61)); - } - - // Triggers must be deleted after check constraints - - MetaName triggerName; - - request.reset(tdbb, drq_e_trigger2, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - X IN RDB$TRIGGERS - WITH X.RDB$RELATION_NAME EQ name.c_str() - { - triggerName = X.RDB$TRIGGER_NAME; - ERASE X; - - AutoCacheRequest request2(tdbb, drq_e_trg_prv, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) - PRIV IN RDB$USER_PRIVILEGES - WITH PRIV.RDB$USER EQ triggerName.c_str() AND - PRIV.RDB$USER_TYPE = obj_trigger AND - PRIV.RDB$GRANTOR NOT MISSING - { - ERASE PRIV; - } - END_FOR - } - END_FOR - - deletePrivilegesByRelName(tdbb, transaction, name, obj_relation); - - request.reset(tdbb, drq_e_view_prv, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - PRIV IN RDB$USER_PRIVILEGES - WITH PRIV.RDB$USER EQ name.c_str() AND - PRIV.RDB$USER_TYPE = obj_view AND - PRIV.RDB$GRANTOR NOT MISSING - { - ERASE PRIV; - } - END_FOR - - // Drop table from all publications - - request.reset(tdbb, drq_e_pub_tab_all, DYN_REQUESTS); - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - PTAB IN RDB$PUBLICATION_TABLES - WITH PTAB.RDB$TABLE_NAME EQ name.c_str() - { - ERASE PTAB; - } - END_FOR - - if (found) - executeDdlTrigger(tdbb, transaction, DTW_AFTER, ddlTriggerAction, name, NULL, *dsqlScratch->getDsqlStatement()->getSqlText()); - else - { - // msg 61: "Relation not found" - status_exception::raise(Arg::PrivateDyn(61)); - } - - savePoint.release(); // everything is ok - - METD_drop_relation(transaction, name.c_str()); - MET_dsql_cache_release(tdbb, SYM_relation, name); + if (!view && rel_drop) + { + RelationPages* relPages = rel_drop->getBasePages(); + if (!relPages->rel_pages || (relPages->rel_pages->count() == 0)) + DPM_scan_pages(tdbb, pag_pointer, rel_drop->rel_id); + if (!relPages->rel_index_root) + DPM_scan_pages(tdbb, pag_root, rel_drop->rel_id); + } + + const int ddlTriggerAction = (view ? DDL_TRIGGER_DROP_VIEW : DDL_TRIGGER_DROP_TABLE); + + // run all statements under savepoint control + AutoSavePoint savePoint(tdbb, transaction); + + AutoCacheRequest request(tdbb, drq_l_relation, DYN_REQUESTS); + bool found = false; + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + R IN RDB$RELATIONS + WITH R.RDB$RELATION_NAME EQ name.c_str() + { + executeDdlTrigger(tdbb, transaction, DTW_BEFORE, ddlTriggerAction, name, NULL, *dsqlScratch->getDsqlStatement()->getSqlText()); + found = true; + } + END_FOR + + request.reset(tdbb, drq_e_rel_con2, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + CRT IN RDB$RELATION_CONSTRAINTS + WITH CRT.RDB$RELATION_NAME EQ name.c_str() AND + (CRT.RDB$CONSTRAINT_TYPE EQ PRIMARY_KEY OR + CRT.RDB$CONSTRAINT_TYPE EQ UNIQUE_CNSTRT OR + CRT.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY) + SORTED BY ASCENDING CRT.RDB$CONSTRAINT_TYPE + { + ERASE CRT; + } + END_FOR + + request.reset(tdbb, drq_e_rel_idxs, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + IDX IN RDB$INDICES + WITH IDX.RDB$RELATION_NAME EQ name.c_str() + { + DropIndexNode::deleteSegmentRecords(tdbb, transaction, IDX.RDB$INDEX_NAME); + ERASE IDX; + } + END_FOR + + request.reset(tdbb, drq_e_trg_msgs2, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + TM IN RDB$TRIGGER_MESSAGES + CROSS T IN RDB$TRIGGERS + WITH T.RDB$RELATION_NAME EQ name.c_str() AND + TM.RDB$TRIGGER_NAME EQ T.RDB$TRIGGER_NAME + { + ERASE TM; + } + END_FOR + + // CVC: Moved this block here to avoid SF Bug #1111570. + request.reset(tdbb, drq_e_rel_con3, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + CRT IN RDB$RELATION_CONSTRAINTS + WITH CRT.RDB$RELATION_NAME EQ name.c_str() AND + (CRT.RDB$CONSTRAINT_TYPE EQ CHECK_CNSTRT OR + CRT.RDB$CONSTRAINT_TYPE EQ NOT_NULL_CNSTRT) + { + ERASE CRT; + } + END_FOR + + request.reset(tdbb, drq_e_rel_flds, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + RFR IN RDB$RELATION_FIELDS + WITH RFR.RDB$RELATION_NAME EQ name.c_str() + { + if (!RFR.RDB$GENERATOR_NAME.NULL) + DropSequenceNode::deleteIdentity(tdbb, transaction, RFR.RDB$GENERATOR_NAME); + + ERASE RFR; + + if (!RFR.RDB$SECURITY_CLASS.NULL && + !strncmp(RFR.RDB$SECURITY_CLASS, SQL_SECCLASS_PREFIX, SQL_SECCLASS_PREFIX_LEN)) + { + deleteSecurityClass(tdbb, transaction, RFR.RDB$SECURITY_CLASS); + } + + deleteGlobalField(tdbb, transaction, RFR.RDB$FIELD_SOURCE); + } + END_FOR + + request.reset(tdbb, drq_e_view_rels, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + VR IN RDB$VIEW_RELATIONS + WITH VR.RDB$VIEW_NAME EQ name.c_str() + { + ERASE VR; + } + END_FOR + + request.reset(tdbb, drq_e_relation, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + R IN RDB$RELATIONS + WITH R.RDB$RELATION_NAME EQ name.c_str() + { + ERASE R; + + if (!R.RDB$SECURITY_CLASS.NULL && + !strncmp(R.RDB$SECURITY_CLASS, SQL_SECCLASS_PREFIX, SQL_SECCLASS_PREFIX_LEN)) + { + deleteSecurityClass(tdbb, transaction, R.RDB$SECURITY_CLASS); + } + } + END_FOR + + if (!found) + { + // msg 61: "Relation not found" + status_exception::raise(Arg::PrivateDyn(61)); + } + + // Triggers must be deleted after check constraints + + MetaName triggerName; + + request.reset(tdbb, drq_e_trigger2, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + X IN RDB$TRIGGERS + WITH X.RDB$RELATION_NAME EQ name.c_str() + { + triggerName = X.RDB$TRIGGER_NAME; + ERASE X; + + AutoCacheRequest request2(tdbb, drq_e_trg_prv, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + WITH PRIV.RDB$USER EQ triggerName.c_str() AND + PRIV.RDB$USER_TYPE = obj_trigger AND + PRIV.RDB$GRANTOR NOT MISSING + { + ERASE PRIV; + } + END_FOR + } + END_FOR + + deletePrivilegesByRelName(tdbb, transaction, name, obj_relation); + + request.reset(tdbb, drq_e_view_prv, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + WITH PRIV.RDB$USER EQ name.c_str() AND + PRIV.RDB$USER_TYPE = obj_view AND + PRIV.RDB$GRANTOR NOT MISSING + { + ERASE PRIV; + } + END_FOR + + // Drop table from all publications + + request.reset(tdbb, drq_e_pub_tab_all, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + PTAB IN RDB$PUBLICATION_TABLES + WITH PTAB.RDB$TABLE_NAME EQ name.c_str() + { + ERASE PTAB; + } + END_FOR + + if (found) + executeDdlTrigger(tdbb, transaction, DTW_AFTER, ddlTriggerAction, name, NULL, *dsqlScratch->getDsqlStatement()->getSqlText()); + else + { + // msg 61: "Relation not found" + status_exception::raise(Arg::PrivateDyn(61)); + } + + savePoint.release(); // everything is ok + + METD_drop_relation(transaction, name.c_str()); + MET_dsql_cache_release(tdbb, SYM_relation, name); } string DropRelationNode::internalPrint(NodePrinter& printer) const @@ -8717,7 +8717,7 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch // Check that DROP TABLE is dropping a table and that DROP VIEW is dropping a view. if (view) { - if (!relation || !(relation->rel_flags & REL_view)) + if (!relation || !(relation->rel_flags & REL_view)) { status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-607) << @@ -8727,7 +8727,7 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch } else { - if (!relation || (relation->rel_flags & REL_view)) + if (!relation || (relation->rel_flags & REL_view)) { status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-607) << @@ -8736,7 +8736,7 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch } } - dropRelation(tdbb, dsqlScratch, transaction, view, rel_drop, name); + dropRelation(tdbb, dsqlScratch, transaction, view, rel_drop, name); } @@ -11680,6 +11680,7 @@ static bool checkObjectExist(thread_db* tdbb, jrd_tra* transaction, const MetaNa END_FOR break; } + case obj_tablespaces: { AutoCacheRequest request(tdbb, drq_tablespace_exist, DYN_REQUESTS); diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index 5e1f3054fcd..c6f86945c26 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -1636,7 +1636,7 @@ class DropRelationNode : public DdlNode static void deleteGlobalField(thread_db* tdbb, jrd_tra* transaction, const MetaName& globalName); - static void dropRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, bool view, jrd_rel* rel_drop, const MetaName& name); + static void dropRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, bool view, jrd_rel* rel_drop, const MetaName& name); public: virtual Firebird::string internalPrint(NodePrinter& printer) const; diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index 778d7639c98..0c9d4f46713 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -46,8 +46,6 @@ using namespace Firebird; namespace Jrd { -using namespace Firebird; - DATABASE DB = STATIC "ODS.RDB"; diff --git a/src/isql/extract.epp b/src/isql/extract.epp index 42066b5dccb..79ffc59f024 100644 --- a/src/isql/extract.epp +++ b/src/isql/extract.epp @@ -3614,10 +3614,10 @@ static void list_tablespaces() * **************************************/ - if (isqlGlob.major_ods < ODS_VERSION14) - return; + if (isqlGlob.major_ods < ODS_VERSION14) + return; - bool first = true; + bool first = true; FOR X IN RDB$TABLESPACES WITH (X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$SYSTEM_FLAG MISSING) diff --git a/src/isql/show.epp b/src/isql/show.epp index 2fa69e363d7..be3fcc8b6bc 100644 --- a/src/isql/show.epp +++ b/src/isql/show.epp @@ -105,9 +105,9 @@ static void show_index(SCHAR*, SCHAR*, const SSHORT, const SSHORT, const SSHORT, static processing_state show_indices(const SCHAR* const*); static processing_state show_proc(const SCHAR*); static processing_state show_packages(const SCHAR* package_name); +static processing_state show_tablespaces(const SCHAR*); static processing_state show_role(const SCHAR*, bool, const char* msg = NULL); static processing_state show_secclass(const char* object, const char* opt); -static processing_state show_tablespaces(const SCHAR*); static processing_state show_table(const SCHAR*, bool); static processing_state show_trigger(const SCHAR*, bool, bool); static processing_state show_users(); @@ -2092,7 +2092,7 @@ processing_state SHOW_metadata(const SCHAR* const* cmd, SCHAR** lcmd) {ShowOptions::package, "PACKAGES", 4}, {ShowOptions::schema, "SCHEMAS", 4}, {ShowOptions::map, "MAPPING", 3}, - {ShowOptions::tablespace, "TABLESPACES", 0 } + {ShowOptions::tablespace, "TABLESPACES", 0} }; const ShowOptions showoptions(options, FB_NELEM(options), ShowOptions::wrong); diff --git a/src/jrd/Statement.cpp b/src/jrd/Statement.cpp index f30f869261c..44785d4a284 100644 --- a/src/jrd/Statement.cpp +++ b/src/jrd/Statement.cpp @@ -677,7 +677,7 @@ void Statement::release(thread_db* tdbb) // Should we check it here again? Tablespace* ts = tdbb->getAttachment()->getTablespace(i); fb_assert(ts); - + if (ts) ts->release(tdbb); } diff --git a/src/jrd/Tablespace.h b/src/jrd/Tablespace.h index 035ca487d33..e0dd1c798b6 100644 --- a/src/jrd/Tablespace.h +++ b/src/jrd/Tablespace.h @@ -46,7 +46,7 @@ namespace Jrd name(p), existenceLock(NULL), modified(false), - useCount(0) + useCount(0) { } diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index cc3a56cef26..d542219462c 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -2105,7 +2105,6 @@ void BTR_selectivity(thread_db* tdbb, jrd_rel* relation, USHORT id, SelectivityL return; } - const bool descending = (root->irt_rpt[id].irt_flags & irt_descending); const ULONG segments = root->irt_rpt[id].irt_keys; @@ -2270,7 +2269,7 @@ void BTR_selectivity(thread_db* tdbb, jrd_rel* relation, USHORT id, SelectivityL selectivity[0] = (float) (nodes ? 1.0 / (float) (nodes - duplicates) : 0.0); // Store the selectivity on the root page - window.win_page = PageNumber(relPages->rel_pg_space_id, relPages->rel_index_root); + window.win_page = PageNumber(relPages->rel_pg_space_id, relPages->rel_index_root); window.win_flags = 0; root = (index_root_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_root); CCH_MARK(tdbb, &window); diff --git a/src/jrd/btr.h b/src/jrd/btr.h index 19bca403c2b..5374e689898 100644 --- a/src/jrd/btr.h +++ b/src/jrd/btr.h @@ -310,7 +310,7 @@ class IndexErrorContext bool isLocationDefined; }; -} //namespace Jrd +} //namespace Jrd #endif // JRD_BTR_H diff --git a/src/jrd/btr_proto.h b/src/jrd/btr_proto.h index b318e33774f..14c8cc64928 100644 --- a/src/jrd/btr_proto.h +++ b/src/jrd/btr_proto.h @@ -53,7 +53,6 @@ void BTR_remove(Jrd::thread_db*, Jrd::win*, Jrd::index_insertion*); void BTR_reserve_slot(Jrd::thread_db*, Jrd::IndexCreation&); void BTR_selectivity(Jrd::thread_db*, Jrd::jrd_rel*, USHORT, Jrd::SelectivityList&); bool BTR_types_comparable(const dsc& target, const dsc& source); -bool BTR_move_index(Jrd::thread_db*, Jrd::jrd_rel*, SLONG, USHORT, Jrd::PageNumber&); - +bool BTR_move_index(Jrd::thread_db*, Jrd::jrd_rel*, SLONG, USHORT, Jrd::PageNumber&); #endif // JRD_BTR_PROTO_H diff --git a/src/jrd/cch.cpp b/src/jrd/cch.cpp index d9cf408c475..20ee218674d 100644 --- a/src/jrd/cch.cpp +++ b/src/jrd/cch.cpp @@ -3126,7 +3126,7 @@ static void check_precedence(thread_db* tdbb, WIN* window, PageNumber page) const USHORT pageSpaceId = page.getPageSpaceID(); - switch(pageSpaceId) + switch (pageSpaceId) { case DB_PAGE_SPACE: break; @@ -3138,8 +3138,8 @@ static void check_precedence(thread_db* tdbb, WIN* window, PageNumber page) break; default: - if (PageSpace::isTablespace(pageSpaceId)) - break; + if (PageSpace::isTablespace(pageSpaceId)) + break; fb_assert(false); return; } diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 57c11570f4f..9fbbc3a384b 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -487,9 +487,7 @@ static bool grant_privileges(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool db_crypt(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool set_linger(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool clear_cache(thread_db*, SSHORT, DeferredWork*, jrd_tra*); - static bool change_repl_state(thread_db*, SSHORT, DeferredWork*, jrd_tra*); - static bool create_tablespace(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool drop_tablespace(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool modify_tablespace(thread_db*, SSHORT, DeferredWork*, jrd_tra*); @@ -1242,16 +1240,12 @@ static const deferred_task task_table[] = { dfw_db_crypt, db_crypt }, { dfw_set_linger, set_linger }, { dfw_clear_cache, clear_cache }, - { dfw_change_repl_state, change_repl_state }, - { dfw_create_tablespace, create_tablespace }, { dfw_drop_tablespace, drop_tablespace }, { dfw_modify_tablespace, modify_tablespace }, { dfw_move_relation, move_relation }, { dfw_move_index, move_index }, - - { dfw_null, NULL } }; @@ -2785,7 +2779,7 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* if (!IDX.RDB$TABLESPACE_NAME.NULL) tableSpaceId = MET_tablespace(tdbb, IDX.RDB$TABLESPACE_NAME)->id; - if (IDX.RDB$INDEX_ID && IDX.RDB$STATISTICS < 0.0) + if (IDX.RDB$INDEX_ID && IDX.RDB$STATISTICS < 0.0) { SelectivityList selectivity(*tdbb->getDefaultPool()); const USHORT localId = IDX.RDB$INDEX_ID - 1; @@ -6562,9 +6556,9 @@ static bool drop_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, j Database* dbb = tdbb->getDatabase(); Attachment* attachment = tdbb->getAttachment(); - Tablespace* tablespace = MET_tablespace_id(tdbb, work->dfw_id); + Tablespace* tablespace = MET_tablespace_id(tdbb, work->dfw_id); - // We assume the tablespace must exists if dfw with has added + // We assume the tablespace must exists if dfw with has added fb_assert(tablespace); fb_assert(tablespace->existenceLock); fb_assert(tablespace->existenceLock->lck_logical != LCK_none); @@ -6577,11 +6571,11 @@ static bool drop_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, j case 1: { - // Make sure that nobody uses the tablespace + // Make sure that nobody uses the tablespace if (tablespace->isUsed() || !LCK_convert(tdbb, tablespace->existenceLock, LCK_EX, transaction->getLockWait())) { - raiseObjectInUseError("TABLESPACE", tablespace->name.c_str()); + raiseObjectInUseError("TABLESPACE", tablespace->name.c_str()); } } return true; diff --git a/src/jrd/dfw_proto.h b/src/jrd/dfw_proto.h index e330fb4bac0..69618f6cf69 100644 --- a/src/jrd/dfw_proto.h +++ b/src/jrd/dfw_proto.h @@ -1,4 +1,4 @@ - /* +/* * PROGRAM: JRD Access Method * MODULE: dfw_proto.h * DESCRIPTION: Prototype header file for dfw.cpp diff --git a/src/jrd/dpm.epp b/src/jrd/dpm.epp index fc5c313e424..dca0838750f 100644 --- a/src/jrd/dpm.epp +++ b/src/jrd/dpm.epp @@ -1137,7 +1137,6 @@ void DPM_delete_relation_pages(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, relPages->rel_index_root = 0; } - bool DPM_fetch(thread_db* tdbb, record_param* rpb, USHORT lock) { /************************************** diff --git a/src/jrd/grant.epp b/src/jrd/grant.epp index 58b7a2f9bab..4219c1af35d 100644 --- a/src/jrd/grant.epp +++ b/src/jrd/grant.epp @@ -519,22 +519,22 @@ static void get_object_info(thread_db* tdbb, } END_FOR } - else if (obj_type == obj_tablespace) - { - AutoCacheRequest request(tdbb, irq_grant20, IRQ_REQUESTS); - - FOR(REQUEST_HANDLE request) - X IN RDB$TABLESPACES WITH - X.RDB$TABLESPACE_NAME EQ object_name - { - s_class = X.RDB$SECURITY_CLASS; - default_class = ""; - owner = X.RDB$OWNER_NAME; - view = false; - } - END_FOR - } - else + else if (obj_type == obj_tablespace) + { + AutoCacheRequest request(tdbb, irq_grant20, IRQ_REQUESTS); + + FOR(REQUEST_HANDLE request) + X IN RDB$TABLESPACES WITH + X.RDB$TABLESPACE_NAME EQ object_name + { + s_class = X.RDB$SECURITY_CLASS; + default_class = ""; + owner = X.RDB$OWNER_NAME; + view = false; + } + END_FOR + } + else { s_class = getSecurityClassName(obj_type); default_class = ""; diff --git a/src/jrd/irq.h b/src/jrd/irq.h index 2e8089eeab3..d96e7f84c17 100644 --- a/src/jrd/irq.h +++ b/src/jrd/irq.h @@ -184,9 +184,9 @@ enum irq_type_t irq_find_rel_ts, // find tablespace options for relation irq_find_idx_ts, // find tablespace options for index irq_find_ts, // find tablespace options by name + irq_find_ts_id, // find tablespace options by id irq_out_proc_param_dep, // check output procedure parameter dependency irq_l_pub_tab_state, // lookup publication state for a table - irq_find_ts_id, // find tablespace options by id irq_list_ts_files, // list tablespace files irq_find_ts_dfw, // find tablespace options by name in dfw irq_find_ts_dfw0, // find tablespace options by name in dfw for cleanup diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index a4ebad555e9..83a421370fe 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -6741,8 +6741,8 @@ static bool drop_files(ObjectsArray& tsFiles) if (unlink(file.c_str())) { ERR_build_status(&status, Arg::Gds(isc_io_error) << Arg::Str("unlink") << - Arg::Str(file) << - Arg::Gds(isc_io_delete_err) << SYS_ERR(errno)); + Arg::Str(file) << + Arg::Gds(isc_io_delete_err) << SYS_ERR(errno)); Database* dbb = GET_DBB(); PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); iscDbLogStatus(pageSpace->file->fil_string, &status); diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 46d6066d302..c86d5da3a46 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -5503,9 +5503,9 @@ Nullable MET_get_ss_definer(Jrd::thread_db* tdbb) * **************************************/ SET_TDBB(tdbb); - - Nullable r; Attachment* attachment = tdbb->getAttachment(); + Nullable r; + AutoCacheRequest request(tdbb, irq_dbb_ss_definer, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) @@ -5529,9 +5529,9 @@ USHORT MET_rel_pagespace(Jrd::thread_db* tdbb, USHORT rel_id) * * Functional description * Find id and filename of tablespace by ID of relation and allocate page space - * Returns page space id for relation of default DB_PAGE_SPACE if table space - * for relation is not specified - * RS: Probably later it would be useful to implement cache of tablespaces + * Returns page space id for relation of default DB_PAGE_SPACE if table space + * for relation is not specified + * RS: Probably later it would be useful to implement cache of tablespaces * **************************************/ SET_TDBB(tdbb); @@ -5564,9 +5564,9 @@ USHORT MET_index_pagespace(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, USHORT * * Functional description * Find tablespace name for index and lookup page space for it. - * If there is no tablespace for the index or relation is system - * returns relation pagespace. - * + * If there is no tablespace for the index or relation is system + * returns relation pagespace. + * **************************************/ SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); @@ -5615,10 +5615,10 @@ Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id, bool open) Database* dbb = tdbb->getDatabase(); CHECK_DBB(dbb); - // Check that pageSpaceId has reasonable value - fb_assert(PageSpace::isTablespace(id)); + // Check that pageSpaceId has reasonable value + fb_assert(PageSpace::isTablespace(id)); - Attachment* attachment = tdbb->getAttachment(); + Attachment* attachment = tdbb->getAttachment(); Tablespace* ts = attachment->getTablespace(id); @@ -5639,19 +5639,19 @@ Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id, bool open) } // Now we need to find tablespace in system table - AutoCacheRequest request(tdbb, irq_find_ts_id, IRQ_REQUESTS); + AutoCacheRequest request(tdbb, irq_find_ts_id, IRQ_REQUESTS); - MetaName tableSpaceName; + MetaName tableSpaceName; PathName file; bool found = false; - FOR(REQUEST_HANDLE request) + FOR(REQUEST_HANDLE request) TS IN RDB$TABLESPACES - WITH TS.RDB$TABLESPACE_ID EQ id - { - found = true; - tableSpaceName = TS.RDB$TABLESPACE_NAME; - file = TS.RDB$FILE_NAME; + WITH TS.RDB$TABLESPACE_ID EQ id + { + found = true; + tableSpaceName = TS.RDB$TABLESPACE_NAME; + file = TS.RDB$FILE_NAME; } END_FOR @@ -5662,7 +5662,7 @@ Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id, bool open) } // Check that pageSpaceId is either new or is not set (else it should be found in att_tablespaces above) - fb_assert(!attachment->getTablespace(id)); + fb_assert(!attachment->getTablespace(id)); Tablespace* tableSpace = NULL; @@ -5723,13 +5723,13 @@ Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const MetaName& tableSpaceName) * Return a pointer to the tablespace. * **************************************/ - SET_TDBB(tdbb); - Database* dbb = tdbb->getDatabase(); - CHECK_DBB(dbb); + SET_TDBB(tdbb); + Database* dbb = tdbb->getDatabase(); + CHECK_DBB(dbb); - Attachment* attachment = tdbb->getAttachment(); - if (tableSpaceName.isEmpty()) - return attachment->getTablespace(DB_PAGE_SPACE); + Attachment* attachment = tdbb->getAttachment(); + if (tableSpaceName.isEmpty()) + return attachment->getTablespace(DB_PAGE_SPACE); Tablespace* ts = attachment->getTablespaceByName(tableSpaceName); @@ -5749,31 +5749,31 @@ Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const MetaName& tableSpaceName) return ts; } - // Now we need to find tablespace in system table - AutoCacheRequest request(tdbb, irq_find_ts, IRQ_REQUESTS); + // Now we need to find tablespace in system table + AutoCacheRequest request(tdbb, irq_find_ts, IRQ_REQUESTS); - USHORT pageSpaceId; - PathName file; - bool found = false; + USHORT pageSpaceId; + PathName file; + bool found = false; - FOR(REQUEST_HANDLE request) - TS IN RDB$TABLESPACES - WITH TS.RDB$TABLESPACE_NAME EQ tableSpaceName.c_str() - { - found = true; - pageSpaceId = TS.RDB$TABLESPACE_ID; - file = TS.RDB$FILE_NAME; - } - END_FOR + FOR(REQUEST_HANDLE request) + TS IN RDB$TABLESPACES + WITH TS.RDB$TABLESPACE_NAME EQ tableSpaceName.c_str() + { + found = true; + pageSpaceId = TS.RDB$TABLESPACE_ID; + file = TS.RDB$FILE_NAME; + } + END_FOR - if (!found) - status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(tableSpaceName)); + if (!found) + status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(tableSpaceName)); - // Check that pageSpaceId has reasonable value - fb_assert(PageSpace::isTablespace(pageSpaceId)); + // Check that pageSpaceId has reasonable value + fb_assert(PageSpace::isTablespace(pageSpaceId)); - // Check that pageSpaceId is either new or is not set (else it should be found in att_tablespaces above) - fb_assert(!attachment->getTablespace(pageSpaceId)); + // Check that pageSpaceId is either new or is not set (else it should be found in att_tablespaces above) + fb_assert(!attachment->getTablespace(pageSpaceId)); Tablespace* tableSpace = NULL; @@ -5813,7 +5813,7 @@ Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const MetaName& tableSpaceName) } attachment->setTablespace(pageSpaceId, tableSpace); - return tableSpace; + return tableSpace; } diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index a9b172f2989..00add5e5f71 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -2617,7 +2617,7 @@ void PageManager::allocTableSpace(thread_db* tdbb, USHORT tableSpaceID, bool cre /*** * NOTE: PageSpaceId of Tablespaces is equal to tablespace id */ - fb_assert(PageSpace::isTablespace(tableSpaceID)); + fb_assert(PageSpace::isTablespace(tableSpaceID)); if (!findPageSpace(tableSpaceID)) { @@ -2658,7 +2658,7 @@ void PageManager::allocTableSpace(thread_db* tdbb, USHORT tableSpaceID, bool cre delete newPageSpace; throw; } - + WriteLockGuard writeGuard(pageSpacesLock, FB_FUNCTION); pageSpaces.add(newPageSpace); } diff --git a/src/jrd/pag.h b/src/jrd/pag.h index 5881b2d92c0..a1af4ff92c2 100644 --- a/src/jrd/pag.h +++ b/src/jrd/pag.h @@ -110,15 +110,15 @@ class PageSpace : public pool_alloc return isTemporary(pageSpaceID); } - static inline bool isTablespace(USHORT aPageSpaceID) - { - return (aPageSpaceID > DB_PAGE_SPACE) && (aPageSpaceID < TRANS_PAGE_SPACE); - } - - inline bool isTablespace() const - { - return isTablespace(pageSpaceID); - } + static inline bool isTablespace(USHORT aPageSpaceID) + { + return (aPageSpaceID > DB_PAGE_SPACE) && (aPageSpaceID < TRANS_PAGE_SPACE); + } + + inline bool isTablespace() const + { + return isTablespace(pageSpaceID); + } static inline SLONG generate(const PageSpace* Item) { diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index d1424fbd472..fd1a889c862 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -3480,6 +3480,7 @@ bool VIO_refetch_record(thread_db* tdbb, record_param* rpb, jrd_tra* transaction return true; } + void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) { /************************************** From 5634fb6836e679a89d58b60f07a15f203e54f97c Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 6 May 2022 11:35:41 +0300 Subject: [PATCH 68/97] 1. Remove unused startSequence argument from DPM_scan_pages(). 2. Remove RDB$PAGE_SEQUENCE field from index on RDB$PAGES because DPM_scan_pages() doesn't use the field anymore. --- src/jrd/dpm.epp | 9 +-------- src/jrd/dpm_proto.h | 2 +- src/jrd/idx.h | 5 ++--- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/jrd/dpm.epp b/src/jrd/dpm.epp index dca0838750f..524fc1a0f19 100644 --- a/src/jrd/dpm.epp +++ b/src/jrd/dpm.epp @@ -2014,7 +2014,7 @@ SLONG DPM_prefetch_bitmap(thread_db* tdbb, jrd_rel* relation, PageBitmap* bitmap #endif -void DPM_scan_pages(thread_db* tdbb, SCHAR pagType /*= 0*/, int relId /*= 0*/, ULONG startSequence /*= 0*/) +void DPM_scan_pages(thread_db* tdbb, SCHAR pagType /*= 0*/, int relId /*= 0*/) { /************************************** * @@ -2115,7 +2115,6 @@ void DPM_scan_pages(thread_db* tdbb, SCHAR pagType /*= 0*/, int relId /*= 0*/, U FOR(REQUEST_HANDLE request) X IN RDB$PAGES WITH X.RDB$RELATION_ID = relId AND X.RDB$PAGE_TYPE = pagType - AND X.RDB$PAGE_SEQUENCE >= startSequence { relation = MET_relation(tdbb, X.RDB$RELATION_ID); relPages = relation->getBasePages(); @@ -2142,12 +2141,6 @@ void DPM_scan_pages(thread_db* tdbb, SCHAR pagType /*= 0*/, int relId /*= 0*/, U CORRUPT(257); // msg 257 bad record in RDB$PAGES } - if ((sequence == startSequence) && (vector = *address)) - { - fb_assert(vector->count() > sequence); - fb_assert((*vector)[sequence] == X.RDB$PAGE_NUMBER); - } - vector = *address = vcl::newVector(*dbb->dbb_permanent, *address, sequence + 1); (*vector)[sequence] = X.RDB$PAGE_NUMBER; } diff --git a/src/jrd/dpm_proto.h b/src/jrd/dpm_proto.h index 2094c8d3e0e..d0973a52a58 100644 --- a/src/jrd/dpm_proto.h +++ b/src/jrd/dpm_proto.h @@ -73,7 +73,7 @@ void DPM_pages(Jrd::thread_db*, SSHORT, int, ULONG, ULONG); #ifdef SUPERSERVER_V2 SLONG DPM_prefetch_bitmap(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::PageBitmap*, SLONG); #endif -void DPM_scan_pages(Jrd::thread_db*, SCHAR pagType = 0, int relId = 0, ULONG startSequence = 0); +void DPM_scan_pages(Jrd::thread_db*, SCHAR pagType = 0, int relId = 0); void DPM_store(Jrd::thread_db*, Jrd::record_param*, Jrd::PageStack&, const Jrd::RecordStorageType type); RecordNumber DPM_store_blob(Jrd::thread_db*, Jrd::blb*, Jrd::Record*); void DPM_rewrite_header(Jrd::thread_db*, Jrd::record_param*); diff --git a/src/jrd/idx.h b/src/jrd/idx.h index f9a592d16ec..5dc5ce56a46 100644 --- a/src/jrd/idx.h +++ b/src/jrd/idx.h @@ -308,11 +308,10 @@ static const struct ini_idx_t indices[] = INDEX(57, rel_tablespaces, idx_unique, 1) SEGMENT(f_ts_name, idx_metadata) // tablespace name }}, - // define index RDB$INDEX_58 for RDB$PAGES RDB$PAGE_TYPE, RDB$RELATION_ID, RDB$PAGE_SEQUENCE; - INDEX(58, rel_pages, 0, 3) + // define index RDB$INDEX_58 for RDB$PAGES RDB$PAGE_TYPE, RDB$RELATION_ID; + INDEX(58, rel_pages, 0, 2) SEGMENT(f_pag_type, idx_numeric), // page type SEGMENT(f_pag_id, idx_numeric), // relation id - SEGMENT(f_pag_seq, idx_numeric) // page sequence }} }; From 4dce809823d36f56179ecd229de0588c4734f374 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 6 May 2022 18:14:37 +0300 Subject: [PATCH 69/97] Fix warning --- src/jrd/validation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jrd/validation.cpp b/src/jrd/validation.cpp index 39a083a3eb6..7b1aa7c2354 100644 --- a/src/jrd/validation.cpp +++ b/src/jrd/validation.cpp @@ -2892,7 +2892,7 @@ void Validation::checkDPinPP(jrd_rel* relation, ULONG page_number) WIN window(pageSpaceId, page_number); data_page* dpage; fetch_page(false, window.win_page, pag_data, &window, &dpage); - const SLONG sequence = dpage->dpg_sequence; + const ULONG sequence = dpage->dpg_sequence; const bool dpEmpty = (dpage->dpg_count == 0); release_page(&window); From c3a831438f0bc2cdb3378660d5bec49efa19da77 Mon Sep 17 00:00:00 2001 From: Alexander Zhdanov Date: Thu, 11 Jul 2024 18:36:06 +0300 Subject: [PATCH 70/97] Fixed errors after merge with firebird_master --- src/burp/OdsDetection.epp | 2 +- src/burp/backup.epp | 2 +- src/burp/burpswi.h | 8 +- src/burp/restore.epp | 3 - src/common/keywords.cpp | 567 ----------------------------------- src/dsql/parse-conflicts.txt | 2 +- src/include/gen/Firebird.pas | 12 +- src/isql/extract.epp | 2 +- src/isql/show.epp | 2 +- src/jrd/btr.cpp | 2 +- src/jrd/pag.cpp | 3 - src/jrd/relations.h | 30 +- src/jrd/validation.cpp | 2 +- 13 files changed, 32 insertions(+), 605 deletions(-) delete mode 100644 src/common/keywords.cpp diff --git a/src/burp/OdsDetection.epp b/src/burp/OdsDetection.epp index 74e049afc69..f899606bfe6 100644 --- a/src/burp/OdsDetection.epp +++ b/src/burp/OdsDetection.epp @@ -45,7 +45,7 @@ namespace {"RDB$ROLES", 0, DB_VERSION_DDL9}, // IB5 {"RDB$PACKAGES", 0, DB_VERSION_DDL12}, // FB3 {"RDB$PUBLICATIONS", 0, DB_VERSION_DDL13}, // FB4 - {"RDB$TABLESPACES", 0, DB_VERSION_DDL14}, + {"RDB$TABLESPACES", 0, DB_VERSION_DDL13}, {0, 0, 0} }; diff --git a/src/burp/backup.epp b/src/burp/backup.epp index 70e9e2dc76b..d2f357decb8 100644 --- a/src/burp/backup.epp +++ b/src/burp/backup.epp @@ -403,7 +403,7 @@ int BACKUP_backup(const TEXT* dbb_file, const TEXT* file_name) write_packages(); } - if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + if (tdgbl->runtimeODS >= DB_VERSION_DDL13) { // Write tablespaces BURP_verbose(411); // msg 411 writing tablespaces diff --git a/src/burp/burpswi.h b/src/burp/burpswi.h index f681cd49907..e781206a11e 100644 --- a/src/burp/burpswi.h +++ b/src/burp/burpswi.h @@ -98,13 +98,13 @@ const int IN_SW_BURP_CRYPT = 51; // name of crypt plugin const int IN_SW_BURP_INCLUDE_DATA = 52; // backup data from tables const int IN_SW_BURP_REPLICA = 53; // replica mode -const int IN_SW_BURP_TS_MAPPING_FILE = 54; // mapping file for tablespaces -const int IN_SW_BURP_TS_ORIGINAL_PATHS = 55; // restore tablespaces to their original paths -const int IN_SW_BURP_TS_PATH = 56; // set a path for a tablespace - const int IN_SW_BURP_PARALLEL_WORKERS = 54; // parallel workers const int IN_SW_BURP_DIRECT_IO = 55; // direct IO for backup files +const int IN_SW_BURP_TS_MAPPING_FILE = 56; // mapping file for tablespaces +const int IN_SW_BURP_TS_ORIGINAL_PATHS = 57; // restore tablespaces to their original paths +const int IN_SW_BURP_TS_PATH = 58; // set a path for a tablespace + /**************************************************************************/ static const char* const BURP_SW_MODE_NONE = "NONE"; diff --git a/src/burp/restore.epp b/src/burp/restore.epp index 6f343a32ed2..b82ebe21fdd 100644 --- a/src/burp/restore.epp +++ b/src/burp/restore.epp @@ -64,11 +64,8 @@ #include "../common/os/path_utils.h" #include "../common/dsc_proto.h" #include "../common/ThreadStart.h" -<<<<<<< HEAD #include "../common/db_alias.h" -======= #include "../common/msg_encode.h" ->>>>>>> firebird_master using MsgFormat::SafeArg; using namespace Firebird; diff --git a/src/common/keywords.cpp b/src/common/keywords.cpp deleted file mode 100644 index e57f8b5f014..00000000000 --- a/src/common/keywords.cpp +++ /dev/null @@ -1,567 +0,0 @@ -/* - * The contents of this file are subject to the Initial - * Developer's Public License Version 1.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. - * - * Software distributed under the License is distributed AS IS, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the License for the specific language governing rights - * and limitations under the License. - * - * The Original Code was created by Mark O'Donohue - * for the Firebird Open Source RDBMS project. - * - * Copyright (c) 2002 Mark O'Donohue - * and all contributors signed below. - * - * All Rights Reserved. - * Contributor(s): ______________________________________. - * - * 2005.05.19 Claudio Valderrama: signal tokens that aren't reserved in the - * engine thanks to special handling. - * Adriano dos Santos Fernandes - */ - -#include "firebird.h" - -#ifdef HAVE_STRING_H -#include -#endif - -#define _yacc_defines_yystype -#include "gen/parse.h" -#include "keywords.h" - -// CVC: The latest column indicates whether the token has special handling in -// the parser. If it does, KEYWORD_stringIsAToken will return false. -// I discovered isql was being fooled and put double quotes around those -// special cases unnecessarily. - -static const TOK tokens[] = -{ - {TOK_NOT_LSS, "!<", false}, - {TOK_NEQ, "!=", false}, - {TOK_NOT_GTR, "!>", false}, - {'(', "(", false}, - {')', ")", false}, - {',', ",", false}, - {'<', "<", false}, - {TOK_LEQ, "<=", false}, - {TOK_NEQ, "<>", false}, // Alias of != - {'=', "=", false}, - {'>', ">", false}, - {TOK_GEQ, ">=", false}, - {TOK_BIND_PARAM, ":=", false}, - {TOK_ABS, "ABS", true}, - {TOK_ABSOLUTE, "ABSOLUTE", true}, - {TOK_ACCENT, "ACCENT", true}, - {TOK_ACOS, "ACOS", true}, - {TOK_ACOSH, "ACOSH", true}, - {TOK_ACTION, "ACTION", true}, - {TOK_ACTIVE, "ACTIVE", true}, - {TOK_ADD, "ADD", false}, - {TOK_ADMIN, "ADMIN", false}, - {TOK_AFTER, "AFTER", true}, - {TOK_ALL, "ALL", false}, - {TOK_ALTER, "ALTER", false}, - {TOK_ALWAYS, "ALWAYS", true}, - {TOK_AND, "AND", false}, - {TOK_ANY, "ANY", false}, - {TOK_AS, "AS", false}, - {TOK_ASC, "ASC", true}, // Alias of ASCENDING - {TOK_ASC, "ASCENDING", true}, - {TOK_ASCII_CHAR, "ASCII_CHAR", true}, - {TOK_ASCII_VAL, "ASCII_VAL", true}, - {TOK_ASIN, "ASIN", true}, - {TOK_ASINH, "ASINH", true}, - {TOK_AT, "AT", false}, - {TOK_ATAN, "ATAN", true}, - {TOK_ATAN2, "ATAN2", true}, - {TOK_ATANH, "ATANH", true}, - {TOK_AUTO, "AUTO", true}, - {TOK_AUTONOMOUS, "AUTONOMOUS", true}, - {TOK_AVG, "AVG", false}, - {TOK_BACKUP, "BACKUP", true}, - {TOK_BASE64_DECODE, "BASE64_DECODE", true}, - {TOK_BASE64_ENCODE, "BASE64_ENCODE", true}, - {TOK_BEFORE, "BEFORE", true}, - {TOK_BEGIN, "BEGIN", false}, - {TOK_BETWEEN, "BETWEEN", false}, - {TOK_BIGINT, "BIGINT", false}, - {TOK_BIN_AND, "BIN_AND", true}, - {TOK_BIN_NOT, "BIN_NOT", true}, - {TOK_BIN_OR, "BIN_OR", true}, - {TOK_BIN_SHL, "BIN_SHL", true}, - {TOK_BIN_SHR, "BIN_SHR", true}, - {TOK_BIN_XOR, "BIN_XOR", true}, - {TOK_BINARY, "BINARY", false}, - {TOK_BIND, "BIND", true}, - {TOK_BIT_LENGTH, "BIT_LENGTH", false}, - {TOK_BLOB, "BLOB", false}, - {TOK_BLOCK, "BLOCK", true}, - {TOK_BODY, "BODY", true}, - {TOK_BOOLEAN, "BOOLEAN", false}, - {TOK_BOTH, "BOTH", false}, - {TOK_BREAK, "BREAK", true}, - {TOK_BY, "BY", false}, - {TOK_CALLER, "CALLER", true}, - {TOK_CASCADE, "CASCADE", true}, - {TOK_CASE, "CASE", false}, - {TOK_CAST, "CAST", false}, - {TOK_CEIL, "CEIL", true}, // Alias of CEILING - {TOK_CEIL, "CEILING", true}, - {TOK_CHAR, "CHAR", false}, - {TOK_CHAR_LENGTH, "CHAR_LENGTH", false}, - {TOK_CHAR_TO_UUID, "CHAR_TO_UUID", true}, - {TOK_CHARACTER, "CHARACTER", false}, - {TOK_CHARACTER_LENGTH, "CHARACTER_LENGTH", false}, - {TOK_CHECK, "CHECK", false}, - {TOK_CLEAR, "CLEAR", true}, - {TOK_CLOSE, "CLOSE", false}, - {TOK_COALESCE, "COALESCE", true}, - {TOK_COLLATE, "COLLATE", false}, - {TOK_COLLATION, "COLLATION", true}, - {TOK_COLUMN, "COLUMN", false}, - {TOK_COMMENT, "COMMENT", false}, - {TOK_COMMIT, "COMMIT", false}, - {TOK_COMMITTED, "COMMITTED", true}, - {TOK_COMMON, "COMMON", true}, - {TOK_COMPARE_DECFLOAT, "COMPARE_DECFLOAT", true}, - {TOK_COMPUTED, "COMPUTED", true}, - {TOK_CONDITIONAL, "CONDITIONAL", true}, - {TOK_CONNECT, "CONNECT", false}, - {TOK_CONNECTIONS, "CONNECTIONS", true}, - {TOK_CONSISTENCY, "CONSISTENCY", true}, - {TOK_CONSTRAINT, "CONSTRAINT", false}, - {TOK_CONTAINING, "CONTAINING", true}, - {TOK_CONTENTS, "CONTENTS", true}, - {TOK_CONTINUE, "CONTINUE", true}, - {TOK_CORR, "CORR", false}, - {TOK_COS, "COS", true}, - {TOK_COSH, "COSH", true}, - {TOK_COT, "COT", true}, - {TOK_COUNT, "COUNT", false}, - {TOK_COUNTER, "COUNTER", true}, - {TOK_COVAR_POP, "COVAR_POP", false}, - {TOK_COVAR_SAMP, "COVAR_SAMP", false}, - {TOK_CREATE, "CREATE", false}, - {TOK_CROSS, "CROSS", false}, - {TOK_CRYPT_HASH, "CRYPT_HASH", true}, - {TOK_CSTRING, "CSTRING", true}, - {TOK_CTR_BIG_ENDIAN, "CTR_BIG_ENDIAN", true}, - {TOK_CTR_LENGTH, "CTR_LENGTH", true}, - {TOK_CTR_LITTLE_ENDIAN, "CTR_LITTLE_ENDIAN", true}, - {TOK_CUME_DIST, "CUME_DIST", true}, - {TOK_CURRENT, "CURRENT", false}, - {TOK_CURRENT_CONNECTION, "CURRENT_CONNECTION", false}, - {TOK_CURRENT_DATE, "CURRENT_DATE", false}, - {TOK_CURRENT_ROLE, "CURRENT_ROLE", false}, - {TOK_CURRENT_TIME, "CURRENT_TIME", false}, - {TOK_CURRENT_TIMESTAMP, "CURRENT_TIMESTAMP", false}, - {TOK_CURRENT_TRANSACTION, "CURRENT_TRANSACTION", false}, - {TOK_CURRENT_USER, "CURRENT_USER", false}, - {TOK_CURSOR, "CURSOR", false}, - {TOK_DATABASE, "DATABASE", true}, - {TOK_DATA, "DATA", true}, - {TOK_DATE, "DATE", false}, - {TOK_DATEADD, "DATEADD", true}, - {TOK_DATEDIFF, "DATEDIFF", true}, - {TOK_DAY, "DAY", false}, - {TOK_DDL, "DDL", true}, - {TOK_DEBUG, "DEBUG", true}, - {TOK_DEC, "DEC", false}, - {TOK_DECFLOAT, "DECFLOAT", false}, - {TOK_DECIMAL, "DECIMAL", false}, - {TOK_DECLARE, "DECLARE", false}, - {TOK_DECODE, "DECODE", true}, - {TOK_DECRYPT, "DECRYPT", true}, - {TOK_DEFAULT, "DEFAULT", false}, - {TOK_DEFINER, "DEFINER", true}, - {TOK_DELETE, "DELETE", false}, - {TOK_DELETING, "DELETING", false}, - {TOK_DENSE_RANK, "DENSE_RANK", true}, - {TOK_DESC, "DESC", true}, // Alias of DESCENDING - {TOK_DESC, "DESCENDING", true}, - {TOK_DESCRIPTOR, "DESCRIPTOR", true}, - {TOK_DETERMINISTIC, "DETERMINISTIC", false}, - {TOK_DIFFERENCE, "DIFFERENCE", true}, - {TOK_DISABLE, "DISABLE", true}, - {TOK_DISCONNECT, "DISCONNECT", false}, - {TOK_DISTINCT, "DISTINCT", false}, - {TOK_DO, "DO", true}, - {TOK_DOMAIN, "DOMAIN", true}, - {TOK_DOUBLE, "DOUBLE", false}, - {TOK_DROP, "DROP", false}, - {TOK_ELSE, "ELSE", false}, - {TOK_ENABLE, "ENABLE", true}, - {TOK_ENCRYPT, "ENCRYPT", true}, - {TOK_END, "END", false}, - {TOK_ENGINE, "ENGINE", true}, - {TOK_ENTRY_POINT, "ENTRY_POINT", true}, - {TOK_ESCAPE, "ESCAPE", false}, - {TOK_EXCEPTION, "EXCEPTION", true}, - {TOK_EXCESS, "EXCESS", true}, - {TOK_EXCLUDE, "EXCLUDE", true}, - {TOK_EXECUTE, "EXECUTE", false}, - {TOK_EXISTS, "EXISTS", false}, - {TOK_EXIT, "EXIT", true}, - {TOK_EXP, "EXP", true}, - {TOK_EXTENDED, "EXTENDED", true}, - {TOK_EXTERNAL, "EXTERNAL", false}, - {TOK_EXTRACT, "EXTRACT", false}, - {TOK_FALSE, "FALSE", false}, - {TOK_FETCH, "FETCH", false}, - {TOK_FILE, "FILE", true}, - {TOK_FILTER, "FILTER", false}, - {TOK_FIRST, "FIRST", true}, - {TOK_FIRST_DAY, "FIRST_DAY", true}, - {TOK_FIRST_VALUE, "FIRST_VALUE", true}, - {TOK_FIRSTNAME, "FIRSTNAME", true}, - {TOK_FLOAT, "FLOAT", false}, - {TOK_FLOOR, "FLOOR", true}, - {TOK_FOLLOWING, "FOLLOWING", true}, - {TOK_FOR, "FOR", false}, - {TOK_FOREIGN, "FOREIGN", false}, - {TOK_FREE_IT, "FREE_IT", true}, - {TOK_FROM, "FROM", false}, - {TOK_FULL, "FULL", false}, - {TOK_FUNCTION, "FUNCTION", false}, - {TOK_GDSCODE, "GDSCODE", false}, - {TOK_GENERATED, "GENERATED", true}, - {TOK_GENERATOR, "GENERATOR", true}, - {TOK_GEN_ID, "GEN_ID", true}, - {TOK_GEN_UUID, "GEN_UUID", true}, - {TOK_GLOBAL, "GLOBAL", false}, - {TOK_GRANT, "GRANT", false}, - {TOK_GRANTED, "GRANTED", true}, - {TOK_GROUP, "GROUP", false}, - {TOK_HASH, "HASH", true}, - {TOK_HAVING, "HAVING", false}, - {TOK_HEX_DECODE, "HEX_DECODE", true}, - {TOK_HEX_ENCODE, "HEX_ENCODE", true}, - {TOK_HOUR, "HOUR", false}, - {TOK_IDENTITY, "IDENTITY", true}, - {TOK_IDLE, "IDLE", true}, - {TOK_IF, "IF", true}, - {TOK_IGNORE, "IGNORE", true}, - {TOK_IIF, "IIF", true}, - {TOK_IN, "IN", false}, - {TOK_INACTIVE, "INACTIVE", true}, - {TOK_INCLUDE, "INCLUDE", true}, - {TOK_INCLUDING, "INCLUDING", true}, - {TOK_INCREMENT, "INCREMENT", true}, - {TOK_INDEX, "INDEX", false}, - {TOK_INNER, "INNER", false}, - {TOK_INPUT_TYPE, "INPUT_TYPE", true}, - {TOK_INSENSITIVE, "INSENSITIVE", false}, - {TOK_INSERT, "INSERT", false}, - {TOK_INSERTING, "INSERTING", false}, - {TOK_INT, "INT", false}, - {TOK_INT128, "INT128", false}, - {TOK_INTEGER, "INTEGER", false}, - {TOK_INTO, "INTO", false}, - {TOK_INVOKER, "INVOKER", true}, - {TOK_IS, "IS", false}, - {TOK_ISOLATION, "ISOLATION", true}, - {TOK_IV, "IV", true}, - {TOK_JOIN, "JOIN", false}, - {TOK_KEY, "KEY", true}, - {TOK_LAG, "LAG", true}, - {TOK_LAST, "LAST", true}, - {TOK_LAST_DAY, "LAST_DAY", true}, - {TOK_LAST_VALUE, "LAST_VALUE", true}, - {TOK_LASTNAME, "LASTNAME", true}, - {TOK_LEAD, "LEAD", true}, - {TOK_LEADING, "LEADING", false}, - {TOK_LEAVE, "LEAVE", true}, - {TOK_LEFT, "LEFT", false}, - {TOK_LEGACY, "LEGACY", true}, - {TOK_LENGTH, "LENGTH", true}, - {TOK_LEVEL, "LEVEL", true}, - {TOK_LIFETIME, "LIFETIME", true}, - {TOK_LIKE, "LIKE", false}, - {TOK_LIMBO, "LIMBO", true}, - {TOK_LINGER, "LINGER", true}, - {TOK_LIST, "LIST", true}, - {TOK_LN, "LN", true}, - {TOK_LATERAL, "LATERAL", false}, - {TOK_LOCAL, "LOCAL", false}, - {TOK_LOCALTIME, "LOCALTIME", false}, - {TOK_LOCALTIMESTAMP, "LOCALTIMESTAMP", false}, - {TOK_LOCK, "LOCK", true}, - {TOK_LOG, "LOG", true}, - {TOK_LOG10, "LOG10", true}, - {TOK_LONG, "LONG", false}, - {TOK_LOWER, "LOWER", false}, - {TOK_LPAD, "LPAD", true}, - {TOK_LPARAM, "LPARAM", true}, - {TOK_MAKE_DBKEY, "MAKE_DBKEY", true}, - {TOK_MANUAL, "MANUAL", true}, - {TOK_MAPPING, "MAPPING", true}, - {TOK_MATCHED, "MATCHED", true}, - {TOK_MATCHING, "MATCHING", true}, - {TOK_MAXIMUM, "MAX", false}, - {TOK_MAXVALUE, "MAXVALUE", true}, - {TOK_MERGE, "MERGE", false}, - {TOK_MESSAGE, "MESSAGE", true}, - {TOK_MILLISECOND, "MILLISECOND", true}, - {TOK_MIDDLENAME, "MIDDLENAME", true}, - {TOK_MINIMUM, "MIN", false}, - {TOK_MINUTE, "MINUTE", false}, - {TOK_MINVALUE, "MINVALUE", true}, - {TOK_MOD, "MOD", true}, - {TOK_MODE, "MODE", true}, - {TOK_MODULE_NAME, "MODULE_NAME", true}, - {TOK_MONTH, "MONTH", false}, - {TOK_NAME, "NAME", true}, - {TOK_NAMES, "NAMES", true}, - {TOK_NATIONAL, "NATIONAL", false}, - {TOK_NATIVE, "NATIVE", true}, - {TOK_NATURAL, "NATURAL", false}, - {TOK_NCHAR, "NCHAR", false}, - {TOK_NEXT, "NEXT", true}, - {TOK_NO, "NO", false}, - {TOK_NORMALIZE_DECFLOAT, "NORMALIZE_DECFLOAT", true}, - {TOK_NOT, "NOT", false}, - {TOK_NTH_VALUE, "NTH_VALUE", true}, - {TOK_NTILE, "NTILE", true}, - {TOK_NULLIF, "NULLIF", true}, - {TOK_NULL, "NULL", false}, - {TOK_NULLS, "NULLS", true}, - {TOK_NUMBER, "NUMBER", true}, - {TOK_NUMERIC, "NUMERIC", false}, - {TOK_OCTET_LENGTH, "OCTET_LENGTH", false}, - {TOK_OF, "OF", false}, - {TOK_OFFSET, "OFFSET", false}, - {TOK_OLDEST, "OLDEST", true}, - {TOK_ON, "ON", false}, - {TOK_OFFLINE, "OFFLINE", true}, - {TOK_ONLINE, "ONLINE", true}, - {TOK_ONLY, "ONLY", false}, - {TOK_OPEN, "OPEN", false}, - {TOK_OPTION, "OPTION", true}, - {TOK_OR, "OR", false}, - {TOK_ORDER, "ORDER", false}, - {TOK_OS_NAME, "OS_NAME", true}, - {TOK_OTHERS, "OTHERS", true}, - {TOK_OUTER, "OUTER", false}, - {TOK_OUTPUT_TYPE, "OUTPUT_TYPE", true}, - {TOK_OVER, "OVER", false}, - {TOK_OVERFLOW, "OVERFLOW", true}, - {TOK_OVERLAY, "OVERLAY", true}, - {TOK_OVERRIDING, "OVERRIDING", true}, - {TOK_PACKAGE, "PACKAGE", true}, - {TOK_PAD, "PAD", true}, - {TOK_PAGE, "PAGE", true}, - {TOK_PAGES, "PAGES", true}, - {TOK_PAGE_SIZE, "PAGE_SIZE", true}, - {TOK_PARAMETER, "PARAMETER", false}, - {TOK_PARTITION, "PARTITION", true}, - {TOK_PASSWORD, "PASSWORD", true}, - {TOK_PERCENT_RANK, "PERCENT_RANK", true}, - {TOK_PI, "PI", true}, - {TOK_PKCS_1_5, "PKCS_1_5", true}, - {TOK_PLACING, "PLACING", true}, - {TOK_PLAN, "PLAN", false}, - {TOK_PLUGIN, "PLUGIN", true}, - {TOK_POOL, "POOL", true}, - {TOK_POSITION, "POSITION", false}, - {TOK_POST_EVENT, "POST_EVENT", false}, - {TOK_POWER, "POWER", true}, - {TOK_PRECEDING, "PRECEDING", true}, - {TOK_PRECISION, "PRECISION", false}, - {TOK_PRESERVE, "PRESERVE", true}, - {TOK_PRIMARY, "PRIMARY", true}, - {TOK_PRIOR, "PRIOR", true}, - {TOK_PRIVILEGE, "PRIVILEGE", true}, - {TOK_PRIVILEGES, "PRIVILEGES", true}, - {TOK_PROCEDURE, "PROCEDURE", false}, - {TOK_PROTECTED, "PROTECTED", true}, - {TOK_PUBLICATION, "PUBLICATION", false}, - {TOK_QUANTIZE, "QUANTIZE", true}, - {TOK_RAND, "RAND", true}, - {TOK_RANGE, "RANGE", true}, - {TOK_RANK, "RANK", true}, - {TOK_DB_KEY, "RDB$DB_KEY", false}, - {TOK_RDB_ERROR, "RDB$ERROR", false}, - {TOK_RDB_GET_CONTEXT, "RDB$GET_CONTEXT", false}, - {TOK_RDB_GET_TRANSACTION_CN, "RDB$GET_TRANSACTION_CN", false}, - {TOK_RDB_RECORD_VERSION, "RDB$RECORD_VERSION", false}, - {TOK_RDB_ROLE_IN_USE, "RDB$ROLE_IN_USE", false}, - {TOK_RDB_SET_CONTEXT, "RDB$SET_CONTEXT", false}, - {TOK_RDB_SYSTEM_PRIVILEGE, "RDB$SYSTEM_PRIVILEGE", false}, - {TOK_READ, "READ", true}, - {TOK_REAL, "REAL", false}, - {TOK_VERSION, "RECORD_VERSION", false}, - {TOK_RECREATE, "RECREATE", false}, - {TOK_RECURSIVE, "RECURSIVE", false}, - {TOK_REFERENCES, "REFERENCES", false}, - {TOK_REGR_AVGX, "REGR_AVGX", false}, - {TOK_REGR_AVGY, "REGR_AVGY", false}, - {TOK_REGR_COUNT, "REGR_COUNT", false}, - {TOK_REGR_INTERCEPT, "REGR_INTERCEPT", false}, - {TOK_REGR_R2, "REGR_R2", false}, - {TOK_REGR_SLOPE, "REGR_SLOPE", false}, - {TOK_REGR_SXX, "REGR_SXX", false}, - {TOK_REGR_SXY, "REGR_SXY", false}, - {TOK_REGR_SYY, "REGR_SYY", false}, - {TOK_RELATIVE, "RELATIVE", true}, - {TOK_RELEASE, "RELEASE", false}, - {TOK_REPLACE, "REPLACE", true}, - {TOK_REQUESTS, "REQUESTS", true}, - {TOK_RESERVING, "RESERV", true}, // Alias of RESERVING - {TOK_RESERVING, "RESERVING", true}, - {TOK_RESET, "RESET", true}, - {TOK_RESETTING, "RESETTING", false}, - {TOK_RESTART, "RESTART", true}, - {TOK_RESTRICT, "RESTRICT", true}, - {TOK_RETAIN, "RETAIN", true}, - {TOK_RETURN, "RETURN", false}, - {TOK_RETURNING, "RETURNING", true}, - {TOK_RETURNING_VALUES, "RETURNING_VALUES", false}, - {TOK_RETURNS, "RETURNS", false}, - {TOK_REVERSE, "REVERSE", true}, - {TOK_REVOKE, "REVOKE", false}, - {TOK_RIGHT, "RIGHT", false}, - {TOK_ROLE, "ROLE", true}, - {TOK_ROLLBACK, "ROLLBACK", false}, - {TOK_ROUND, "ROUND", true}, - {TOK_ROW, "ROW", false}, - {TOK_ROW_COUNT, "ROW_COUNT", false}, - {TOK_ROW_NUMBER, "ROW_NUMBER", true}, - {TOK_ROWS, "ROWS", false}, - {TOK_RPAD, "RPAD", true}, - {TOK_RSA_DECRYPT, "RSA_DECRYPT", true}, - {TOK_RSA_ENCRYPT, "RSA_ENCRYPT", true}, - {TOK_RSA_PRIVATE, "RSA_PRIVATE", true}, - {TOK_RSA_PUBLIC, "RSA_PUBLIC", true}, - {TOK_RSA_SIGN_HASH, "RSA_SIGN_HASH", true}, - {TOK_RSA_VERIFY_HASH, "RSA_VERIFY_HASH", true}, - {TOK_SALT_LENGTH, "SALT_LENGTH", true}, - {TOK_SAVEPOINT, "SAVEPOINT", false}, - {TOK_SCALAR_ARRAY, "SCALAR_ARRAY", true}, - {TOK_DATABASE, "SCHEMA", false}, // Alias of DATABASE - {TOK_SCROLL, "SCROLL", false}, - {TOK_SECOND, "SECOND", false}, - {TOK_SECURITY, "SECURITY", true}, - {TOK_SEGMENT, "SEGMENT", true}, - {TOK_SELECT, "SELECT", false}, - {TOK_SENSITIVE, "SENSITIVE", false}, - {TOK_SEQUENCE, "SEQUENCE", true}, - {TOK_SERVERWIDE, "SERVERWIDE", true}, - {TOK_SESSION, "SESSION", true}, - {TOK_SET, "SET", false}, - {TOK_SHADOW, "SHADOW", true}, - {TOK_SHARED, "SHARED", true}, - {TOK_SIGN, "SIGN", true}, - {TOK_SIGNATURE, "SIGNATURE", true}, - {TOK_SIMILAR, "SIMILAR", false}, - {TOK_SIN, "SIN", true}, - {TOK_SINGULAR, "SINGULAR", true}, - {TOK_SINH, "SINH", true}, - {TOK_SIZE, "SIZE", true}, - {TOK_SKIP, "SKIP", true}, - {TOK_SMALLINT, "SMALLINT", false}, - {TOK_SNAPSHOT, "SNAPSHOT", true}, - {TOK_SOME, "SOME", false}, - {TOK_SORT, "SORT", true}, - {TOK_SOURCE, "SOURCE", true}, - {TOK_SPACE, "SPACE", true}, - {TOK_SQL, "SQL", true}, - {TOK_SQLCODE, "SQLCODE", false}, - {TOK_SQLSTATE, "SQLSTATE", false}, - {TOK_SQRT, "SQRT", true}, - {TOK_STABILITY, "STABILITY", true}, - {TOK_START, "START", false}, - {TOK_STARTING, "STARTING", true}, - {TOK_STARTING, "STARTS", true}, // Alias of STARTING - {TOK_STATEMENT, "STATEMENT", true}, - {TOK_STATISTICS, "STATISTICS", true}, - {TOK_STDDEV_POP, "STDDEV_POP", false}, - {TOK_STDDEV_SAMP, "STDDEV_SAMP", false}, - {TOK_SUBSTRING, "SUBSTRING", true}, - {TOK_SUB_TYPE, "SUB_TYPE", true}, - {TOK_SUM, "SUM", false}, - {TOK_SUSPEND, "SUSPEND", true}, - {TOK_SYSTEM, "SYSTEM", true}, - {TOK_TABLE, "TABLE", false}, - {TOK_TABLESPACE, "TABLESPACE", true}, - {TOK_TAGS, "TAGS", true}, - {TOK_TAN, "TAN", true}, - {TOK_TANH, "TANH", true}, - {TOK_TARGET, "TARGET", true}, - {TOK_TEMPORARY, "TEMPORARY", true}, - {TOK_THEN, "THEN", false}, - {TOK_TIES, "TIES", true}, - {TOK_TIME, "TIME", false}, - {TOK_TIMESTAMP, "TIMESTAMP", false}, - {TOK_TIMEOUT, "TIMEOUT", true}, - {TOK_TIMEZONE_HOUR, "TIMEZONE_HOUR", false}, - {TOK_TIMEZONE_MINUTE, "TIMEZONE_MINUTE", false}, - {TOK_TIMEZONE_NAME, "TIMEZONE_NAME", true}, - {TOK_TO, "TO", false}, - {TOK_TOTALORDER, "TOTALORDER", true}, - {TOK_TRAILING, "TRAILING", false}, - {TOK_TRANSACTION, "TRANSACTION", true}, - {TOK_TRAPS, "TRAPS", true}, - {TOK_TRIGGER, "TRIGGER", false}, - {TOK_TRIM, "TRIM", false}, - {TOK_TRUE, "TRUE", false}, - {TOK_TRUNC, "TRUNC", true}, - {TOK_TRUSTED, "TRUSTED", true}, - {TOK_TWO_PHASE, "TWO_PHASE", true}, - {TOK_TYPE, "TYPE", true}, - {TOK_UNBOUNDED, "UNBOUNDED", false}, - {TOK_UNCOMMITTED, "UNCOMMITTED", true}, - {TOK_UNDO, "UNDO", true}, - {TOK_UNICODE_CHAR, "UNICODE_CHAR", true}, - {TOK_UNICODE_VAL, "UNICODE_VAL", true}, - {TOK_UNION, "UNION", false}, - {TOK_UNIQUE, "UNIQUE", false}, - {TOK_UNKNOWN, "UNKNOWN", false}, - {TOK_UPDATE, "UPDATE", false}, - {TOK_UPDATING, "UPDATING", false}, - {TOK_UPPER, "UPPER", false}, - {TOK_USAGE, "USAGE", true}, - {TOK_USER, "USER", false}, - {TOK_USING, "USING", false}, - {TOK_UUID_TO_CHAR, "UUID_TO_CHAR", true}, - {TOK_VALUE, "VALUE", false}, - {TOK_VALUES, "VALUES", false}, - {TOK_VAR_POP, "VAR_POP", false}, - {TOK_VAR_SAMP, "VAR_SAMP", false}, - {TOK_VARBINARY, "VARBINARY", false}, - {TOK_VARCHAR, "VARCHAR", false}, - {TOK_VARIABLE, "VARIABLE", false}, - {TOK_VARYING, "VARYING", false}, - {TOK_VIEW, "VIEW", false}, - {TOK_WAIT, "WAIT", true}, - {TOK_WEEK, "WEEK", true}, - {TOK_WEEKDAY, "WEEKDAY", true}, - {TOK_WHEN, "WHEN", false}, - {TOK_WHERE, "WHERE", false}, - {TOK_WHILE, "WHILE", false}, - {TOK_WINDOW, "WINDOW", false}, - {TOK_WITH, "WITH", false}, - {TOK_WITHOUT, "WITHOUT", false}, - {TOK_WORK, "WORK", true}, - {TOK_WRITE, "WRITE", true}, - {TOK_YEAR, "YEAR", false}, - {TOK_YEARDAY, "YEARDAY", true}, - {TOK_ZONE, "ZONE", true}, - {TOK_NOT_LSS, "^<", false}, // Alias of !< - {TOK_NEQ, "^=", false}, // Alias of != - {TOK_NOT_GTR, "^>", false}, // Alias of !> - {TOK_CONCATENATE, "||", false}, - {TOK_NOT_LSS, "~<", false}, // Alias of !< - {TOK_NEQ, "~=", false}, // Alias of != - {TOK_NOT_GTR, "~>", false}, // Alias of !> - {0, NULL, false} -}; - -Tokens keywordGetTokens() -{ - return tokens; -} diff --git a/src/dsql/parse-conflicts.txt b/src/dsql/parse-conflicts.txt index 58be4c6e996..10e43bf848e 100644 --- a/src/dsql/parse-conflicts.txt +++ b/src/dsql/parse-conflicts.txt @@ -1 +1 @@ -115 shift/reduce conflicts, 22 reduce/reduce conflicts. +121 shift/reduce conflicts, 28 reduce/reduce conflicts. diff --git a/src/include/gen/Firebird.pas b/src/include/gen/Firebird.pas index 8711235f663..2b688002324 100644 --- a/src/include/gen/Firebird.pas +++ b/src/include/gen/Firebird.pas @@ -5702,9 +5702,6 @@ IProfilerStatsImpl = class(IProfilerStats) isc_bad_loctab_num = 335545277; isc_quoted_str_bad = 335545278; isc_quoted_str_miss = 335545279; - isc_ts_file_exists = 335545280; - isc_tablespace_name = 335545281; - isc_ts_file_not_exists = 335545282; isc_wrong_shmem_ver = 335545280; isc_wrong_shmem_bitness = 335545281; isc_wrong_proc_plan = 335545282; @@ -5733,6 +5730,9 @@ IProfilerStatsImpl = class(IProfilerStats) isc_only_one_pattern_can_be_used = 335545305; isc_can_not_use_same_pattern_twice = 335545306; isc_sysf_invalid_gen_uuid_version = 335545307; + isc_ts_file_exists = 335545308; + isc_tablespace_name = 335545309; + isc_ts_file_not_exists = 335545310; isc_gfix_db_name = 335740929; isc_gfix_invalid_sw = 335740930; isc_gfix_incmp_sw = 335740932; @@ -5889,9 +5889,9 @@ IProfilerStatsImpl = class(IProfilerStats) isc_dyn_exc_not_exist = 336068915; isc_dyn_gen_not_exist = 336068916; isc_dyn_fld_not_exist = 336068917; - isc_dyn_ts_not_found = 336068918; - isc_dyn_cant_set_ts_table = 336068919; - isc_dyn_cant_set_ts_index = 336068920; + isc_dyn_ts_not_found = 336068922; + isc_dyn_cant_set_ts_table = 336068923; + isc_dyn_cant_set_ts_index = 336068924; isc_gbak_unknown_switch = 336330753; isc_gbak_page_size_missing = 336330754; isc_gbak_page_size_toobig = 336330755; diff --git a/src/isql/extract.epp b/src/isql/extract.epp index 4d8f7dbc3d8..0a60d8e69e4 100644 --- a/src/isql/extract.epp +++ b/src/isql/extract.epp @@ -3629,7 +3629,7 @@ static void list_tablespaces() * **************************************/ - if (isqlGlob.major_ods < ODS_VERSION14) + if (isqlGlob.major_ods < ODS_VERSION13) return; bool first = true; diff --git a/src/isql/show.epp b/src/isql/show.epp index 9125e600d8d..bf96a8b4d99 100644 --- a/src/isql/show.epp +++ b/src/isql/show.epp @@ -5076,7 +5076,7 @@ static processing_state show_tablespaces(const SCHAR* tablespace_name) * Functional description * Show all tablespaces or the named tablespace ************************************/ - if (isqlGlob.major_ods < ODS_VERSION14) + if (isqlGlob.major_ods < ODS_VERSION13) return OBJECT_NOT_FOUND; bool first = true; diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index 8e9f468812b..e0a6bf7b6ff 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -893,7 +893,7 @@ void BTR_create(thread_db* tdbb, idx->idx_pg_space_id = relPages->rel_pg_space_id; // Now that the index id has been checked out, create the index. - idx->idx_root = fast_load(tdbb, creation, selectivity, creation.sort); + idx->idx_root = fast_load(tdbb, creation, selectivity, creation.sort); // Index is created. Go back to the index root page and update it to // point to the index. diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index b70589ae27e..c8a957cad80 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -2417,9 +2417,6 @@ void PageManager::allocTableSpace(thread_db* tdbb, USHORT tableSpaceID, bool cre newPageSpace->pipFirst = FIRST_PIP_PAGE; newPageSpace->scnFirst = FIRST_SCN_PAGE; } - - if (dbb->dbb_flags & (DBB_force_write | DBB_no_fs_cache)) - PIO_force_write(newPageSpace->file, dbb->dbb_flags & DBB_force_write, dbb->dbb_flags & DBB_no_fs_cache); } catch (...) { diff --git a/src/jrd/relations.h b/src/jrd/relations.h index eb3fba992c3..513efbbff69 100644 --- a/src/jrd/relations.h +++ b/src/jrd/relations.h @@ -99,7 +99,7 @@ RELATION(nam_indices, rel_indices, ODS_8_0, rel_persistent) FIELD(f_idx_exp_blr, nam_exp_blr, fld_value, 1, ODS_8_0) FIELD(f_idx_exp_source, nam_exp_source, fld_source, 1, ODS_8_0) FIELD(f_idx_statistics, nam_statistics, fld_statistics, 1, ODS_8_0) - FIELD(f_idx_ts_name, nam_ts_name, fld_ts_name, 1, ODS_14_0) + FIELD(f_idx_ts_name, nam_ts_name, fld_ts_name, 1, ODS_13_0) FIELD(f_idx_cond_blr, nam_cond_blr, fld_value, 1, ODS_13_1) FIELD(f_idx_cond_source, nam_cond_source, fld_source, 1, ODS_13_1) END_RELATION @@ -127,7 +127,7 @@ RELATION(nam_r_fields, rel_rfr, ODS_8_0, rel_persistent) FIELD(f_rfr_coll_id, nam_collate_id, fld_collate_id, 1, ODS_8_0) FIELD(f_rfr_gen_name, nam_gen_name, fld_gen_name, 1, ODS_12_0) FIELD(f_rfr_identity_type, nam_identity_type, fld_identity_type, 1, ODS_12_0) - FIELD(f_rfr_ts_name, nam_ts_name, fld_ts_name, 1, ODS_14_0) + FIELD(f_rfr_ts_name, nam_ts_name, fld_ts_name, 1, ODS_13_0) END_RELATION // Relation 6 (RDB$RELATIONS) @@ -150,9 +150,9 @@ RELATION(nam_relations, rel_relations, ODS_8_0, rel_persistent) FIELD(f_rel_flags, nam_flags, fld_flag_nullable, 0, ODS_8_0) FIELD(f_rel_type, nam_r_type, fld_r_type, 0, ODS_11_1) FIELD(f_rel_sql_security, nam_sql_security, fld_b_sql_security, 1, ODS_13_0) - FIELD(f_rel_ts_name, nam_ts_name, fld_ts_name, 1, ODS_14_0) - FIELD(f_rel_first_pp, nam_pp_number, fld_pp_number, 0, ODS_14_0) - FIELD(f_rel_idx_root, nam_idx_number, fld_idx_number, 0, ODS_14_0) + FIELD(f_rel_ts_name, nam_ts_name, fld_ts_name, 1, ODS_13_0) + FIELD(f_rel_first_pp, nam_pp_number, fld_pp_number, 0, ODS_13_0) + FIELD(f_rel_idx_root, nam_idx_number, fld_idx_number, 0, ODS_13_0) END_RELATION // Relation 7 (RDB$VIEW_RELATIONS) @@ -765,14 +765,14 @@ RELATION(nam_mon_compiled_statements, rel_mon_compiled_statements, ODS_13_1, rel END_RELATION // Relation 56 (RDB$TABLESPACES) -RELATION(nam_tablespaces, rel_tablespaces, ODS_14_0, rel_persistent) - FIELD(f_ts_id, nam_ts_id, fld_ts_id, 0, ODS_14_0) - FIELD(f_ts_name, nam_ts_name, fld_ts_name, 1, ODS_14_0) - FIELD(f_ts_class, nam_class, fld_class, 1, ODS_14_0) - FIELD(f_ts_sys_flag, nam_sys_flag, fld_flag, 1, ODS_14_0) - FIELD(f_ts_desc, nam_description, fld_description, 1, ODS_14_0) - FIELD(f_ts_owner, nam_owner, fld_user, 1, ODS_14_0) - FIELD(f_ts_file, nam_file_name, fld_file_name, 1, ODS_14_0) - FIELD(f_ts_offline, nam_ts_offline, fld_bool, 1, ODS_14_0) - FIELD(f_ts_readonly, nam_ts_readonly, fld_bool, 1, ODS_14_0) +RELATION(nam_tablespaces, rel_tablespaces, ODS_13_0, rel_persistent) + FIELD(f_ts_id, nam_ts_id, fld_ts_id, 0, ODS_13_0) + FIELD(f_ts_name, nam_ts_name, fld_ts_name, 1, ODS_13_0) + FIELD(f_ts_class, nam_class, fld_class, 1, ODS_13_0) + FIELD(f_ts_sys_flag, nam_sys_flag, fld_flag, 1, ODS_13_0) + FIELD(f_ts_desc, nam_description, fld_description, 1, ODS_13_0) + FIELD(f_ts_owner, nam_owner, fld_user, 1, ODS_13_0) + FIELD(f_ts_file, nam_file_name, fld_file_name, 1, ODS_13_0) + FIELD(f_ts_offline, nam_ts_offline, fld_bool, 1, ODS_13_0) + FIELD(f_ts_readonly, nam_ts_readonly, fld_bool, 1, ODS_13_0) END_RELATION diff --git a/src/jrd/validation.cpp b/src/jrd/validation.cpp index a09b3a240da..8f43ab8affc 100644 --- a/src/jrd/validation.cpp +++ b/src/jrd/validation.cpp @@ -2657,7 +2657,7 @@ Validation::RTN Validation::walk_pointer_page(jrd_rel* relation, ULONG sequence) if (releasePP) { - fetch_page(false, (*vector)[sequence], pag_pointer, &window, &page); + fetch_page(false, PageNumber(pageSpaceId, (*vector)[sequence]), pag_pointer, &window, &page); bits = (UCHAR*) (page->ppg_page + dbb->dbb_dp_per_pp); pages = &page->ppg_page[slot]; } From 5ff5d24c823cfc6e153cd48feca462566b777c2a Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 13 May 2022 17:58:05 +0300 Subject: [PATCH 71/97] Fix a bug when it was possible to create several tablespaces with the same --- src/dsql/TablespaceNodes.epp | 2 +- src/jrd/idx.h | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index 0c9d4f46713..d14f6cfd77e 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -138,7 +138,7 @@ void CreateAlterTablespaceNode::executeCreate(thread_db* tdbb, DsqlCompilerScrat id = DYN_UTIL_gen_unique_id(tdbb, drq_g_nxt_ts_id, "RDB$TABLESPACES") + 1; // +1 to skip DB_PAGE_SPACE id %= TRANS_PAGE_SPACE; - if (!id) + if (!id || id == 1) // skip DB_PAGE_SPACE continue; STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) diff --git a/src/jrd/idx.h b/src/jrd/idx.h index a1c883c1b7f..1a6c8a1db83 100644 --- a/src/jrd/idx.h +++ b/src/jrd/idx.h @@ -314,8 +314,12 @@ static const struct ini_idx_t indices[] = INDEX(58, rel_tablespaces, idx_unique, 1, ODS_13_0) SEGMENT(f_ts_name, idx_metadata) // tablespace name }}, - // define index RDB$INDEX_59 for RDB$PAGES RDB$PAGE_TYPE, RDB$RELATION_ID; - INDEX(59, rel_pages, 0, 2, ODS_13_0) + // define index RDB$INDEX_59 for RDB$TABLESPACES unique RDB$TABLESPACE_ID; + INDEX(59, rel_tablespaces, idx_unique, 1, ODS_13_0) + SEGMENT(f_ts_id, idx_numeric) // tablespace id + }}, + // define index RDB$INDEX_60 for RDB$PAGES RDB$PAGE_TYPE, RDB$RELATION_ID; + INDEX(60, rel_pages, 0, 2, ODS_13_0) SEGMENT(f_pag_type, idx_numeric), // page type SEGMENT(f_pag_id, idx_numeric), // relation id }} From 06d819a4e5930c8615e7751edcc173a5b4d2d297 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Mon, 16 May 2022 16:31:12 +0300 Subject: [PATCH 72/97] Use 4-byte unsigned integer for page space id --- src/dsql/TablespaceNodes.epp | 4 +-- src/jrd/Attachment.h | 6 ++--- src/jrd/Relation.cpp | 2 +- src/jrd/Relation.h | 4 +-- src/jrd/Statement.cpp | 8 +++--- src/jrd/Tablespace.h | 2 +- src/jrd/blb.cpp | 13 +++++----- src/jrd/blb.h | 4 +-- src/jrd/btr.cpp | 10 ++++---- src/jrd/btr.h | 2 +- src/jrd/btr_proto.h | 2 +- src/jrd/cch.cpp | 4 +-- src/jrd/dfw.epp | 6 ++--- src/jrd/dpm.epp | 4 +-- src/jrd/fields.h | 2 +- src/jrd/jrd.h | 2 +- src/jrd/met.epp | 18 ++++++------- src/jrd/met_proto.h | 6 ++--- src/jrd/ods.h | 10 ++++---- src/jrd/pag.cpp | 20 +++++++-------- src/jrd/pag.h | 42 ++++++++++++++++--------------- src/jrd/pag_proto.h | 2 +- src/jrd/recsrc/IndexTableScan.cpp | 2 +- src/jrd/tra.cpp | 4 +-- src/jrd/validation.cpp | 28 ++++++++++----------- src/jrd/vio.cpp | 4 +-- 26 files changed, 106 insertions(+), 105 deletions(-) diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index d14f6cfd77e..bee98054396 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -192,7 +192,7 @@ bool CreateAlterTablespaceNode::executeAlter(thread_db* tdbb, DsqlCompilerScratc Attachment* attachment = transaction->getAttachment(); AutoCacheRequest requestHandle(tdbb, drq_m_tablespace, DYN_REQUESTS); bool modified = false; - USHORT tableSpaceId = 0; + ULONG tableSpaceId = 0; FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) X IN RDB$TABLESPACES @@ -282,7 +282,7 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat AutoSavePoint savePoint(tdbb, transaction); bool found = false; - USHORT tableSpaceId = 0; + ULONG tableSpaceId = 0; string tableSpaceFileName; AutoCacheRequest requestHandle(tdbb, drq_e_tablespace, DYN_REQUESTS); diff --git a/src/jrd/Attachment.h b/src/jrd/Attachment.h index bf4b5703ca2..28df5922319 100644 --- a/src/jrd/Attachment.h +++ b/src/jrd/Attachment.h @@ -808,7 +808,7 @@ class Attachment : public pool_alloc att_batches.findAndRemove(b); } - Tablespace* getTablespace(USHORT id) + Tablespace* getTablespace(ULONG id) { // tablespace id is started from 1 if (id <= att_tablespaces.getCount()) @@ -833,7 +833,7 @@ class Attachment : public pool_alloc return NULL; } - void setTablespace(USHORT id, Tablespace* value) + void setTablespace(ULONG id, Tablespace* value) { if (id > att_tablespaces.getCount()) att_tablespaces.grow(id); @@ -842,7 +842,7 @@ class Attachment : public pool_alloc att_tablespaces[id - 1] = value; } - void delTablespace(USHORT id) + void delTablespace(ULONG id) { if (id <= att_tablespaces.getCount()) { diff --git a/src/jrd/Relation.cpp b/src/jrd/Relation.cpp index 20f83bbba41..8da99eb50bd 100644 --- a/src/jrd/Relation.cpp +++ b/src/jrd/Relation.cpp @@ -427,7 +427,7 @@ bool jrd_rel::acquireGCLock(thread_db* tdbb, int wait) return ret; } -void jrd_rel::setPageSpace(USHORT pageSpaceId) +void jrd_rel::setPageSpace(ULONG pageSpaceId) { rel_pages_base.rel_pg_space_id = pageSpaceId; } diff --git a/src/jrd/Relation.h b/src/jrd/Relation.h index f8008071ace..c610d56e949 100644 --- a/src/jrd/Relation.h +++ b/src/jrd/Relation.h @@ -87,7 +87,7 @@ class RelationPages ULONG rel_sec_data_space; // lowest pointer page with secondary data page space ULONG rel_last_free_pri_dp; // last primary data page found with space ULONG rel_last_free_blb_dp; // last blob data page found with space - USHORT rel_pg_space_id; + ULONG rel_pg_space_id; RelationPages(Firebird::MemoryPool& pool) : rel_pages(NULL), rel_instance_id(0), @@ -359,7 +359,7 @@ class jrd_rel : public pool_alloc void downgradeGCLock(thread_db* tdbb); bool acquireGCLock(thread_db* tdbb, int wait); - void setPageSpace(USHORT pageSpaceId); + void setPageSpace(ULONG pageSpaceId); // This guard is used by regular code to prevent online validation while // dead- or back- versions is removed from disk. diff --git a/src/jrd/Statement.cpp b/src/jrd/Statement.cpp index c5f8ab3bb22..190e2bc49c1 100644 --- a/src/jrd/Statement.cpp +++ b/src/jrd/Statement.cpp @@ -132,7 +132,7 @@ Statement::Statement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb) LCK_lock(tdbb, index->idl_lock, LCK_SR, LCK_WAIT); } } - const USHORT pageSpaceId = MET_index_pagespace(tdbb, relation, resource->rsc_id); + const ULONG pageSpaceId = MET_index_pagespace(tdbb, relation, resource->rsc_id); usedTablespaces[pageSpaceId]++; break; } @@ -167,7 +167,7 @@ Statement::Statement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb) } // Now let's lock all used tablespaces - for (USHORT i = DB_PAGE_SPACE + 1; i < TRANS_PAGE_SPACE; i++) + for (ULONG i = DB_PAGE_SPACE + 1; i < TRANS_PAGE_SPACE; i++) if (usedTablespaces[i] > 0) { // Tablespace is locking after the use in relation and indices. @@ -697,7 +697,7 @@ void Statement::release(thread_db* tdbb) if (!index->idl_count) LCK_release(tdbb, index->idl_lock); } - const USHORT pageSpaceId = MET_index_pagespace(tdbb, relation, resource->rsc_id); + const ULONG pageSpaceId = MET_index_pagespace(tdbb, relation, resource->rsc_id); usedTablespaces[pageSpaceId]++; break; } @@ -721,7 +721,7 @@ void Statement::release(thread_db* tdbb) } // Now let's release all used tablespaces - for (USHORT i = DB_PAGE_SPACE + 1; i < TRANS_PAGE_SPACE; i++) + for (ULONG i = DB_PAGE_SPACE + 1; i < TRANS_PAGE_SPACE; i++) if (usedTablespaces[i] > 0) { // Tablespace is locking after the use in relation and indices. diff --git a/src/jrd/Tablespace.h b/src/jrd/Tablespace.h index e0dd1c798b6..cd42442f0f3 100644 --- a/src/jrd/Tablespace.h +++ b/src/jrd/Tablespace.h @@ -52,7 +52,7 @@ namespace Jrd ~Tablespace(); - USHORT id; // tablespace id = pagespace id + ULONG id; // tablespace id = pagespace id MetaName name; // tablespace name Lock* existenceLock; // existence lock, if any bool modified; diff --git a/src/jrd/blb.cpp b/src/jrd/blb.cpp index 0cf895dead5..bde284c3522 100644 --- a/src/jrd/blb.cpp +++ b/src/jrd/blb.cpp @@ -81,7 +81,6 @@ typedef Ods::blob_page blob_page; static ArrayField* alloc_array(jrd_tra*, Ods::InternalArrayDesc*); //static blb* allocate_blob(thread_db*, jrd_tra*); static ISC_STATUS blob_filter(USHORT, BlobControl*); -//static blb* copy_blob(thread_db*, const bid*, bid*, USHORT, const UCHAR*, USHORT); //static void delete_blob(thread_db*, blb*, ULONG); //static void delete_blob_id(thread_db*, const bid*, ULONG, jrd_rel*); static ArrayField* find_array(jrd_tra*, const bid*); @@ -1089,7 +1088,7 @@ void blb::move(thread_db* tdbb, dsc* from_desc, dsc* to_desc, BLB_gen_bpb_from_descs(from_desc, to_desc, bpb); Database* dbb = tdbb->getDatabase(); - const USHORT pageSpace = dbb->readOnly() ? + const ULONG pageSpace = dbb->readOnly() ? dbb->dbb_page_manager.getTempPageSpaceID(tdbb) : DB_PAGE_SPACE; copy_blob(tdbb, source, destination, bpb.getCount(), bpb.begin(), pageSpace); @@ -1136,7 +1135,7 @@ void blb::move(thread_db* tdbb, dsc* from_desc, dsc* to_desc, BLB_gen_bpb_from_descs(from_desc, to_desc, bpb); Database* dbb = tdbb->getDatabase(); - const USHORT pageSpace = dbb->readOnly() ? + const ULONG pageSpace = dbb->readOnly() ? dbb->dbb_page_manager.getTempPageSpaceID(tdbb) : DB_PAGE_SPACE; copy_blob(tdbb, source, destination, bpb.getCount(), bpb.begin(), pageSpace); @@ -2124,7 +2123,7 @@ static ISC_STATUS blob_filter(USHORT action, BlobControl* control) blb* blb::copy_blob(thread_db* tdbb, const bid* source, bid* destination, USHORT bpb_length, const UCHAR* bpb, - USHORT destPageSpaceID) + ULONG destPageSpaceID) { /************************************** * @@ -2191,11 +2190,11 @@ void blb::delete_blob(thread_db* tdbb, ULONG prior_page) Database* const dbb = tdbb->getDatabase(); CHECK_DBB(dbb); - const USHORT pageSpaceID = blb_pg_space_id; + const ULONG pageSpaceID = blb_pg_space_id; if (dbb->readOnly()) { - const USHORT tempSpaceID = dbb->dbb_page_manager.getTempPageSpaceID(tdbb); + const ULONG tempSpaceID = dbb->dbb_page_manager.getTempPageSpaceID(tdbb); if (pageSpaceID != tempSpaceID) { @@ -2473,7 +2472,7 @@ void blb::insert_page(thread_db* tdbb) // Allocate a page for the now full blob data page. Move the page // image to the buffer, and release the page. - const USHORT pageSpaceID = blb_pg_space_id; + const ULONG pageSpaceID = blb_pg_space_id; WIN window(pageSpaceID, -1); blob_page* page = (blob_page*) DPM_allocate(tdbb, &window); diff --git a/src/jrd/blb.h b/src/jrd/blb.h index 26176b5e695..beba861e095 100644 --- a/src/jrd/blb.h +++ b/src/jrd/blb.h @@ -134,7 +134,7 @@ class blb : public pool_alloc private: static blb* allocate_blob(thread_db*, jrd_tra*); static blb* copy_blob(thread_db* tdbb, const bid* source, bid* destination, - USHORT bpb_length, const UCHAR* bpb, USHORT destPageSpaceID); + USHORT bpb_length, const UCHAR* bpb, ULONG destPageSpaceID); void delete_blob(thread_db*, ULONG); Ods::blob_page* get_next_page(thread_db*, win*); void insert_page(thread_db*); @@ -163,7 +163,7 @@ class blb : public pool_alloc USHORT blb_space_remaining; // Data space left USHORT blb_max_pages; // Max pages in vector USHORT blb_level; // Storage type - USHORT blb_pg_space_id; // page space + ULONG blb_pg_space_id; // page space USHORT blb_fragment_size; // Residual fragment size USHORT blb_max_segment; // Longest segment #ifdef CHECK_BLOB_FIELD_ACCESS_FOR_SELECT diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index e0a6bf7b6ff..c4c63142a1b 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -933,7 +933,7 @@ bool BTR_delete_index(thread_db* tdbb, WIN* window, USHORT id) else { index_root_page::irt_repeat* irt_desc = root->irt_rpt + id; - const USHORT pg_space_id = irt_desc->getRootPageSpaceId(); + const ULONG pg_space_id = irt_desc->getRootPageSpaceId(); if (PageSpace::isTablespace(pg_space_id)) { @@ -2723,7 +2723,7 @@ class IndexNodes int nullIndLen; }; -bool BTR_move_index(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, SLONG indexId, USHORT pageSpaceId, PageNumber& oldRootPage) +bool BTR_move_index(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, SLONG indexId, ULONG pageSpaceId, PageNumber& oldRootPage) { /************************************** * @@ -3937,7 +3937,7 @@ static ULONG fast_load(thread_db* tdbb, index_desc* const idx = creation.index; const USHORT key_length = creation.key_length; - const USHORT pageSpaceID = idx->idx_pg_space_id; + const ULONG pageSpaceID = idx->idx_pg_space_id; // leaf-page and pointer-page size limits, we always need to // leave room for the END_LEVEL node. @@ -5295,7 +5295,7 @@ static contents garbage_collect(thread_db* tdbb, WIN* window, ULONG parent_numbe const Database* dbb = tdbb->getDatabase(); CHECK_DBB(dbb); - const USHORT pageSpaceID = window->win_page.getPageSpaceID(); + const ULONG pageSpaceID = window->win_page.getPageSpaceID(); btree_page* gc_page = (btree_page*) window->win_buffer; contents result = contents_above_threshold; @@ -5953,7 +5953,7 @@ static ULONG insert_node(thread_db* tdbb, const Database* dbb = tdbb->getDatabase(); CHECK_DBB(dbb); - const USHORT pageSpaceID = window->win_page.getPageSpaceID(); + const ULONG pageSpaceID = window->win_page.getPageSpaceID(); // find the insertion point for the specified key btree_page* bucket = (btree_page*) window->win_buffer; diff --git a/src/jrd/btr.h b/src/jrd/btr.h index a3f45e28101..8788ed6f09b 100644 --- a/src/jrd/btr.h +++ b/src/jrd/btr.h @@ -73,7 +73,7 @@ struct index_desc Statement* idx_condition_statement; // stored statement for index condition float idx_fraction; // fraction of keys included in the index - USHORT idx_pg_space_id; // PageSpace of index pages + ULONG idx_pg_space_id; // PageSpace of index pages // This structure should exactly match IRTD structure for current ODS struct idx_repeat { diff --git a/src/jrd/btr_proto.h b/src/jrd/btr_proto.h index 92df987718f..c04a6b3e5a8 100644 --- a/src/jrd/btr_proto.h +++ b/src/jrd/btr_proto.h @@ -53,6 +53,6 @@ void BTR_remove(Jrd::thread_db*, Jrd::win*, Jrd::index_insertion*); void BTR_reserve_slot(Jrd::thread_db*, Jrd::IndexCreation&); void BTR_selectivity(Jrd::thread_db*, Jrd::jrd_rel*, USHORT, Jrd::SelectivityList&); bool BTR_types_comparable(const dsc& target, const dsc& source); -bool BTR_move_index(Jrd::thread_db*, Jrd::jrd_rel*, SLONG, USHORT, Jrd::PageNumber&); +bool BTR_move_index(Jrd::thread_db*, Jrd::jrd_rel*, SLONG, ULONG, Jrd::PageNumber&); #endif // JRD_BTR_PROTO_H diff --git a/src/jrd/cch.cpp b/src/jrd/cch.cpp index b55381cb42d..78a04d7c2b1 100644 --- a/src/jrd/cch.cpp +++ b/src/jrd/cch.cpp @@ -1793,7 +1793,7 @@ void CCH_must_write(thread_db* tdbb, WIN* window) void CCH_precedence(thread_db* tdbb, WIN* window, ULONG pageNum) { - const USHORT pageSpaceID = pageNum > FIRST_PIP_PAGE ? + const ULONG pageSpaceID = pageNum > FIRST_PIP_PAGE ? window->win_page.getPageSpaceID() : DB_PAGE_SPACE; CCH_precedence(tdbb, window, PageNumber(pageSpaceID, pageNum)); @@ -3199,7 +3199,7 @@ static void check_precedence(thread_db* tdbb, WIN* window, PageNumber page) // If this is really a transaction id, sort things out - const USHORT pageSpaceId = page.getPageSpaceID(); + const ULONG pageSpaceId = page.getPageSpaceID(); switch (pageSpaceId) { diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 56260ad4c51..50ac0504f72 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -2818,7 +2818,7 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* jrd_rel* relation = nullptr; CompilerScratch* csb = nullptr; - USHORT tableSpaceId = DB_PAGE_SPACE; + ULONG tableSpaceId = DB_PAGE_SPACE; const auto dbb = tdbb->getDatabase(); const auto attachment = tdbb->getAttachment(); @@ -3496,7 +3496,7 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ relation = NULL; idx.idx_flags = 0; - USHORT tableSpaceId = DB_PAGE_SPACE; + ULONG tableSpaceId = DB_PAGE_SPACE; // Fetch the information necessary to create the index. On the first // time thru, check to see if the index already exists. If so, delete @@ -7069,7 +7069,7 @@ static bool move_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tr break; } - const USHORT newPageSpaceId = MET_tablespace(tdbb, tableSpace)->id; + const ULONG newPageSpaceId = MET_tablespace(tdbb, tableSpace)->id; PageNumber oldRootPage; if (BTR_move_index(tdbb, relation, indexId, newPageSpaceId, oldRootPage)) diff --git a/src/jrd/dpm.epp b/src/jrd/dpm.epp index 5432a53f5b7..81301217115 100644 --- a/src/jrd/dpm.epp +++ b/src/jrd/dpm.epp @@ -77,7 +77,7 @@ using namespace Firebird; static void check_swept(thread_db*, record_param*); static USHORT compress(thread_db*, data_page*); -static void delete_tail(thread_db*, rhdf*, const USHORT, USHORT); +static void delete_tail(thread_db*, rhdf*, const ULONG, USHORT); static void fragment(thread_db*, record_param*, SSHORT, Compressor&, SSHORT, const jrd_tra*); static void extend_relation(thread_db*, jrd_rel*, WIN*, const Jrd::RecordStorageType type); static UCHAR* find_space(thread_db*, record_param*, SSHORT, PageStack&, Record*, const Jrd::RecordStorageType type); @@ -2697,7 +2697,7 @@ static USHORT compress(thread_db* tdbb, data_page* page) } -static void delete_tail(thread_db* tdbb, rhdf* header, const USHORT page_space, USHORT length) +static void delete_tail(thread_db* tdbb, rhdf* header, const ULONG page_space, USHORT length) { /************************************** * diff --git a/src/jrd/fields.h b/src/jrd/fields.h index 9c8213b83ae..e08302abf0a 100644 --- a/src/jrd/fields.h +++ b/src/jrd/fields.h @@ -235,7 +235,7 @@ FIELD(fld_par_workers , nam_par_workers , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_1) - FIELD(fld_ts_id , nam_ts_id , dtype_short , sizeof(SSHORT) , 0 , NULL , false , ODS_13_0) + FIELD(fld_ts_id , nam_ts_id , dtype_long , sizeof(SLONG) , 0 , NULL , false , ODS_13_0) FIELD(fld_ts_name , nam_ts_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) FIELD(fld_pp_number , nam_pp_number , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) diff --git a/src/jrd/jrd.h b/src/jrd/jrd.h index a4e5257948b..1523944d6a2 100644 --- a/src/jrd/jrd.h +++ b/src/jrd/jrd.h @@ -338,7 +338,7 @@ struct win explicit win(const PageNumber& wp) : win_page(wp), win_bdb(NULL), win_flags(0) {} - win(const USHORT pageSpaceID, const ULONG pageNum) + win(const ULONG pageSpaceID, const ULONG pageNum) : win_page(pageSpaceID, pageNum), win_bdb(NULL), win_flags(0) {} }; diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 0af5e9ea35f..8d0fd8d4363 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -3816,7 +3816,7 @@ jrd_rel* MET_relation(thread_db* tdbb, USHORT id) // reserved for system relations const USHORT max_sys_rel = USER_DEF_REL_INIT_ID - 1; - USHORT pageSpaceId = DB_PAGE_SPACE; + ULONG pageSpaceId = DB_PAGE_SPACE; if (id > max_sys_rel) pageSpaceId = MET_rel_pagespace(tdbb, id); @@ -5644,7 +5644,7 @@ TriState MET_get_ss_definer(Jrd::thread_db* tdbb) return r; } -USHORT MET_rel_pagespace(Jrd::thread_db* tdbb, USHORT rel_id) +ULONG MET_rel_pagespace(Jrd::thread_db* tdbb, USHORT rel_id) { /************************************** * @@ -5663,7 +5663,7 @@ USHORT MET_rel_pagespace(Jrd::thread_db* tdbb, USHORT rel_id) Database* dbb = tdbb->getDatabase(); CHECK_DBB(dbb); - USHORT pageSpaceId = DB_PAGE_SPACE; + ULONG pageSpaceId = DB_PAGE_SPACE; Attachment* attachment = tdbb->getAttachment(); AutoCacheRequest request(tdbb, irq_find_rel_ts, IRQ_REQUESTS); @@ -5679,7 +5679,7 @@ USHORT MET_rel_pagespace(Jrd::thread_db* tdbb, USHORT rel_id) return pageSpaceId; } -USHORT MET_index_pagespace(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, USHORT idx_id) +ULONG MET_index_pagespace(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, USHORT idx_id) { /************************************** * @@ -5703,7 +5703,7 @@ USHORT MET_index_pagespace(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, USHORT // Relation tablespace name must be in system table after index creation // If it's not so we shoud use the main DB page space. - USHORT pageSpaceId = DB_PAGE_SPACE; + ULONG pageSpaceId = DB_PAGE_SPACE; Attachment* attachment = tdbb->getAttachment(); AutoCacheRequest request(tdbb, irq_find_idx_ts, IRQ_REQUESTS); @@ -5720,7 +5720,7 @@ USHORT MET_index_pagespace(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, USHORT return pageSpaceId; } -Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id, bool open) +Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, ULONG id, bool open) { /************************************** * @@ -5798,7 +5798,7 @@ Tablespace* MET_tablespace_id(Jrd::thread_db* tdbb, USHORT id, bool open) tableSpace->name = tableSpaceName; Lock* lock = FB_NEW_RPT(*attachment->att_pool, 0) - Lock(tdbb, sizeof(SLONG), LCK_tablespace_exist, tableSpace); + Lock(tdbb, sizeof(ULONG), LCK_tablespace_exist, tableSpace); tableSpace->existenceLock = lock; lock->setKey(tableSpace->id); @@ -5877,7 +5877,7 @@ Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const MetaName& tableSpaceName) // Now we need to find tablespace in system table AutoCacheRequest request(tdbb, irq_find_ts, IRQ_REQUESTS); - USHORT pageSpaceId; + ULONG pageSpaceId; PathName file; bool found = false; @@ -5909,7 +5909,7 @@ Tablespace* MET_tablespace(Jrd::thread_db* tdbb, const MetaName& tableSpaceName) tableSpace->name = tableSpaceName; Lock* lock = FB_NEW_RPT(*attachment->att_pool, 0) - Lock(tdbb, sizeof(SLONG), LCK_tablespace_exist, tableSpace); + Lock(tdbb, sizeof(ULONG), LCK_tablespace_exist, tableSpace); tableSpace->existenceLock = lock; lock->setKey(tableSpace->id); diff --git a/src/jrd/met_proto.h b/src/jrd/met_proto.h index 3cbe7e3c692..ad749a624bb 100644 --- a/src/jrd/met_proto.h +++ b/src/jrd/met_proto.h @@ -150,9 +150,9 @@ void MET_store_dependencies(Jrd::thread_db*, Firebird::Array &files); void MET_scan_tablespaces(Jrd::thread_db*); diff --git a/src/jrd/ods.h b/src/jrd/ods.h index c6ec0f91215..8b8264c5db4 100644 --- a/src/jrd/ods.h +++ b/src/jrd/ods.h @@ -364,7 +364,7 @@ struct index_root_page { private: friend struct index_root_page; // to allow offset check for private members - USHORT irt_page_space_id; // page space of index root + ULONG irt_page_space_id; // page space of index root ULONG irt_root; // page number of index root if irt_in_progress is NOT set, or // highest 32 bit of transaction if irt_in_progress is set ULONG irt_transaction; // transaction in progress (lowest 32 bits) @@ -373,9 +373,9 @@ struct index_root_page UCHAR irt_keys; // number of keys in index UCHAR irt_flags; - USHORT getRootPageSpaceId() const; + ULONG getRootPageSpaceId() const; ULONG getRootPage() const; - void setRoot(USHORT pageSpaceId, ULONG page); + void setRoot(ULONG pageSpaceId, ULONG page); TraNumber getTransaction() const; void setTransaction(TraNumber traNumber); @@ -422,7 +422,7 @@ const USHORT irt_primary = 16; const USHORT irt_expression = 32; const USHORT irt_condition = 64; -inline USHORT index_root_page::irt_repeat::getRootPageSpaceId() const +inline ULONG index_root_page::irt_repeat::getRootPageSpaceId() const { return irt_page_space_id; } @@ -432,7 +432,7 @@ inline ULONG index_root_page::irt_repeat::getRootPage() const return (irt_flags & irt_in_progress) ? 0 : irt_root; } -inline void index_root_page::irt_repeat::setRoot(USHORT pageSpaceId, ULONG page) +inline void index_root_page::irt_repeat::setRoot(ULONG pageSpaceId, ULONG page) { irt_page_space_id = pageSpaceId; irt_root = page; diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index c8a957cad80..91ffc1e2c4d 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -1478,7 +1478,7 @@ void PAG_release_page(thread_db* tdbb, const PageNumber& number, const PageNumbe } -void PAG_release_pages(thread_db* tdbb, USHORT pageSpaceID, int cntRelease, +void PAG_release_pages(thread_db* tdbb, ULONG pageSpaceID, int cntRelease, const ULONG* pgNums, const ULONG prior_page) { /************************************** @@ -2258,7 +2258,7 @@ PageManager::PageManager(Database* aDbb, Firebird::MemoryPool& aPool) : addPageSpace(DB_PAGE_SPACE); } -PageSpace* PageManager::addPageSpace(const USHORT pageSpaceID) +PageSpace* PageManager::addPageSpace(const ULONG pageSpaceID) { WriteLockGuard guard(pageSpacesLock, FB_FUNCTION); @@ -2274,7 +2274,7 @@ PageSpace* PageManager::addPageSpace(const USHORT pageSpaceID) return newPageSpace; } -PageSpace* PageManager::findPageSpace(const USHORT pageSpace) const +PageSpace* PageManager::findPageSpace(const ULONG pageSpace) const { ReadLockGuard guard(pageSpacesLock, FB_FUNCTION); @@ -2286,7 +2286,7 @@ PageSpace* PageManager::findPageSpace(const USHORT pageSpace) const return 0; } -void PageManager::delPageSpace(const USHORT pageSpace) +void PageManager::delPageSpace(const ULONG pageSpace) { WriteLockGuard guard(pageSpacesLock, FB_FUNCTION); @@ -2323,12 +2323,12 @@ void PageManager::initTempPageSpace(thread_db* tdbb) if (!attachment->att_temp_pg_lock) { Lock* const lock = FB_NEW_RPT(*attachment->att_pool, 0) - Lock(tdbb, sizeof(SLONG), LCK_page_space); + Lock(tdbb, sizeof(ULONG), LCK_page_space); while (true) { - const double tmp = rand() * (MAX_USHORT - TEMP_PAGE_SPACE - 1.0) / (RAND_MAX + 1.0); - lock->setKey(static_cast(tmp) + TEMP_PAGE_SPACE + 1); + const double tmp = rand() * (MAX_PAGE_SPACE_ID - TEMP_PAGE_SPACE - 1.0) / (RAND_MAX + 1.0); + lock->setKey(static_cast(tmp) + TEMP_PAGE_SPACE + 1); if (LCK_lock(tdbb, lock, LCK_write, LCK_NO_WAIT)) break; fb_utils::init_status(tdbb->tdbb_status_vector); @@ -2337,7 +2337,7 @@ void PageManager::initTempPageSpace(thread_db* tdbb) attachment->att_temp_pg_lock = lock; } - tempPageSpaceID = (USHORT) attachment->att_temp_pg_lock->getKey(); + tempPageSpaceID = (ULONG) attachment->att_temp_pg_lock->getKey(); } else { @@ -2347,7 +2347,7 @@ void PageManager::initTempPageSpace(thread_db* tdbb) addPageSpace(tempPageSpaceID); } -USHORT PageManager::getTempPageSpaceID(thread_db* tdbb) +ULONG PageManager::getTempPageSpaceID(thread_db* tdbb) { fb_assert(tempPageSpaceID != 0); if (!tempFileCreated) @@ -2380,7 +2380,7 @@ USHORT PageManager::getTempPageSpaceID(thread_db* tdbb) } -void PageManager::allocTableSpace(thread_db* tdbb, USHORT tableSpaceID, bool create, const PathName& fileName) +void PageManager::allocTableSpace(thread_db* tdbb, ULONG tableSpaceID, bool create, const PathName& fileName) { /*** * NOTE: PageSpaceId of Tablespaces is equal to tablespace id diff --git a/src/jrd/pag.h b/src/jrd/pag.h index a1af4ff92c2..cf0322d694a 100644 --- a/src/jrd/pag.h +++ b/src/jrd/pag.h @@ -61,11 +61,13 @@ class PageControl : public pool_alloc // TEMP_PAGE_SPACE and page spaces above TEMP_PAGE_SPACE contain temporary pages // TRANS_PAGE_SPACE is pseudo space to store transaction numbers in precedence stack // INVALID_PAGE_SPACE is to ??? -const USHORT INVALID_PAGE_SPACE = 0; -const USHORT DB_PAGE_SPACE = 1; -// .. here all tablespace IDs. Keep TRANS_PAGE_SPACE right after DB_PAGE_SPACE -const USHORT TRANS_PAGE_SPACE = 255; // is not used for tablespace id -const USHORT TEMP_PAGE_SPACE = 256; +const ULONG INVALID_PAGE_SPACE = 0; +const ULONG DB_PAGE_SPACE = 1; +// .. here all tablespace IDs. Keep TRANS_PAGE_SPACE right after DB_PAGE_SPACE. +// Note that the max tablespace ID should be MAX_USHORT as long as dfw_id is USHORT. +const ULONG TRANS_PAGE_SPACE = MAX_USHORT + 1; // is not used for tablespace id +const ULONG TEMP_PAGE_SPACE = TRANS_PAGE_SPACE + 1; +const ULONG MAX_PAGE_SPACE_ID = MAX_ULONG; const USHORT PAGES_IN_EXTENT = 8; @@ -77,7 +79,7 @@ class PageManager; class PageSpace : public pool_alloc { public: - explicit PageSpace(Database* aDbb, USHORT aPageSpaceID) + explicit PageSpace(Database* aDbb, ULONG aPageSpaceID) { pageSpaceID = aPageSpaceID; pipHighWater = 0; @@ -92,7 +94,7 @@ class PageSpace : public pool_alloc ~PageSpace(); - USHORT pageSpaceID; + ULONG pageSpaceID; Firebird::AtomicCounter pipHighWater; // Lowest PIP with space Firebird::AtomicCounter pipWithExtent; // Lowest PIP with free extent ULONG pipFirst; // First pointer page @@ -100,7 +102,7 @@ class PageSpace : public pool_alloc jrd_file* file; - static inline bool isTemporary(USHORT aPageSpaceID) + static inline bool isTemporary(ULONG aPageSpaceID) { return (aPageSpaceID >= TEMP_PAGE_SPACE); } @@ -110,7 +112,7 @@ class PageSpace : public pool_alloc return isTemporary(pageSpaceID); } - static inline bool isTablespace(USHORT aPageSpaceID) + static inline bool isTablespace(ULONG aPageSpaceID) { return (aPageSpaceID > DB_PAGE_SPACE) && (aPageSpaceID < TRANS_PAGE_SPACE); } @@ -120,7 +122,7 @@ class PageSpace : public pool_alloc return isTablespace(pageSpaceID); } - static inline SLONG generate(const PageSpace* Item) + static inline ULONG generate(const PageSpace* Item) { return Item->pageSpaceID; } @@ -169,13 +171,13 @@ class PageManager : public pool_alloc delete pageSpacesLock; } - PageSpace* findPageSpace(const USHORT pageSpaceID) const; + PageSpace* findPageSpace(const ULONG pageSpaceID) const; void initTempPageSpace(thread_db* tdbb); - USHORT getTempPageSpaceID(thread_db* tdbb); + ULONG getTempPageSpaceID(thread_db* tdbb); - void allocTableSpace(thread_db* tdbb, USHORT tableSpaceID, bool create, const Firebird::PathName& fileName); - void delPageSpace(const USHORT pageSpaceID); + void allocTableSpace(thread_db* tdbb, ULONG tableSpaceID, bool create, const Firebird::PathName& fileName); + void delPageSpace(const ULONG pageSpaceID); void closeAll(); @@ -187,9 +189,9 @@ class PageManager : public pool_alloc private: typedef Firebird::SortedArray, - USHORT, PageSpace> PageSpaceArray; + ULONG, PageSpace> PageSpaceArray; - PageSpace* addPageSpace(const USHORT pageSpaceID); + PageSpace* addPageSpace(const ULONG pageSpaceID); Database* dbb; PageSpaceArray pageSpaces; @@ -204,7 +206,7 @@ class PageNumber { public: // CVC: To be completely in sync, the second param would have to be TraNumber - inline PageNumber(const USHORT aPageSpace, const ULONG aPageNum) + inline PageNumber(const ULONG aPageSpace, const ULONG aPageNum) : pageNum(aPageNum), pageSpaceID(aPageSpace) { // Some asserts are commented cause 0 was also used as 'does not matter' pagespace @@ -226,13 +228,13 @@ class PageNumber return pageNum; } - inline USHORT getPageSpaceID() const + inline ULONG getPageSpaceID() const { fb_assert(pageSpaceID != INVALID_PAGE_SPACE); return pageSpaceID; } - inline USHORT setPageSpaceID(const USHORT aPageSpaceID) + inline ULONG setPageSpaceID(const ULONG aPageSpaceID) { fb_assert(aPageSpaceID != INVALID_PAGE_SPACE); pageSpaceID = aPageSpaceID; @@ -321,7 +323,7 @@ class PageNumber private: ULONG pageNum; - USHORT pageSpaceID; + ULONG pageSpaceID; }; const PageNumber ZERO_PAGE_NUMBER(DB_PAGE_SPACE, 0); diff --git a/src/jrd/pag_proto.h b/src/jrd/pag_proto.h index dc9a4ae20d9..fc65245c374 100644 --- a/src/jrd/pag_proto.h +++ b/src/jrd/pag_proto.h @@ -52,7 +52,7 @@ void PAG_init(Jrd::thread_db*); void PAG_init2(Jrd::thread_db*, USHORT); SLONG PAG_last_page(Jrd::thread_db* tdbb); void PAG_release_page(Jrd::thread_db* tdbb, const Jrd::PageNumber&, const Jrd::PageNumber&); -void PAG_release_pages(Jrd::thread_db* tdbb, USHORT pageSpaceID, int cntRelease, +void PAG_release_pages(Jrd::thread_db* tdbb, ULONG pageSpaceID, int cntRelease, const ULONG* pgNums, const ULONG prior_page); void PAG_set_db_guid(Jrd::thread_db* tdbb, const Firebird::Guid&); void PAG_set_force_write(Jrd::thread_db* tdbb, bool); diff --git a/src/jrd/recsrc/IndexTableScan.cpp b/src/jrd/recsrc/IndexTableScan.cpp index e69bdbe2c1b..336da93137a 100644 --- a/src/jrd/recsrc/IndexTableScan.cpp +++ b/src/jrd/recsrc/IndexTableScan.cpp @@ -200,7 +200,7 @@ bool IndexTableScan::internalGetRecord(thread_db* tdbb) const index_desc* const idx = (index_desc*) ((SCHAR*) impure + m_offset); // find the last fetched position from the index - const USHORT pageSpaceID = idx->idx_pg_space_id; + const ULONG pageSpaceID = idx->idx_pg_space_id; win window(pageSpaceID, impure->irsb_nav_page); const IndexRetrieval* const retrieval = m_index->retrieval; diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index f13163d61c4..d139246afb3 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -1013,7 +1013,7 @@ void TRA_post_resources(thread_db* tdbb, jrd_tra* transaction, ResourceList& res } // Now let's lock all used tablespaces - for (USHORT i = DB_PAGE_SPACE + 1; i < TRANS_PAGE_SPACE; i++) + for (ULONG i = DB_PAGE_SPACE + 1; i < TRANS_PAGE_SPACE; i++) if (usedTablespaces[i] > 0) { // Tablespace is locking after the use in relation and indices. @@ -1305,7 +1305,7 @@ void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction, Jrd::TraceTr release_temp_tables(tdbb, transaction); // Now let's release all used tablespaces - for (USHORT i = DB_PAGE_SPACE + 1; i < TRANS_PAGE_SPACE; i++) + for (ULONG i = DB_PAGE_SPACE + 1; i < TRANS_PAGE_SPACE; i++) if (usedTablespaces[i] > 0) { // Tablespace is locking after the use in relation and indices. diff --git a/src/jrd/validation.cpp b/src/jrd/validation.cpp index 8f43ab8affc..fd84ca05581 100644 --- a/src/jrd/validation.cpp +++ b/src/jrd/validation.cpp @@ -1072,7 +1072,7 @@ bool Validation::run(thread_db* tdbb, USHORT flags) void Validation::cleanup() { - for (USHORT i = DB_PAGE_SPACE; i < TRANS_PAGE_SPACE; i++) + for (ULONG i = DB_PAGE_SPACE; i < TRANS_PAGE_SPACE; i++) { if (!vdr_page_bitmap[i]) continue; @@ -1242,7 +1242,7 @@ Validation::FETCH_CODE Validation::fetch_page(bool mark, PageNumber page_number, CCH_MARK(vdr_tdbb, window); } - const int pageSpaceId = page_number.getPageSpaceID(); + const ULONG pageSpaceId = page_number.getPageSpaceID(); const PageManager& pageMgr = dbb->dbb_page_manager; const PageSpace* pageSpace = pageMgr.findPageSpace(pageSpaceId); @@ -1337,7 +1337,7 @@ void Validation::garbage_collect() PageManager& pageSpaceMgr = dbb->dbb_page_manager; - for (USHORT pageSpaceId = DB_PAGE_SPACE; pageSpaceId < TRANS_PAGE_SPACE; pageSpaceId++) + for (ULONG pageSpaceId = DB_PAGE_SPACE; pageSpaceId < TRANS_PAGE_SPACE; pageSpaceId++) { if (!vdr_max_page[pageSpaceId]) continue; @@ -1495,7 +1495,7 @@ Validation::RTN Validation::walk_blob(jrd_rel* relation, const blh* header, USHO corrupt(VAL_BLOB_UNKNOWN_LEVEL, relation, number.getValue(), header->blh_level); } - const USHORT pageSpaceId = relation->getBasePages()->rel_pg_space_id; + const ULONG pageSpaceId = relation->getBasePages()->rel_pg_space_id; // Level 1 blobs are a little more complicated WIN window1(pageSpaceId, -1), window2(pageSpaceId, -1); window1.win_flags = window2.win_flags = WIN_garbage_collector; @@ -1563,7 +1563,7 @@ Validation::RTN Validation::walk_chain(jrd_rel* relation, const rhd* header, USHORT counter = 0; #endif - const USHORT pageSpaceId = relation->getBasePages()->rel_pg_space_id; + const ULONG pageSpaceId = relation->getBasePages()->rel_pg_space_id; ULONG page_number = header->rhd_b_page; USHORT line_number = header->rhd_b_line; @@ -1734,7 +1734,7 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number, **************************************/ Database* dbb = vdr_tdbb->getDatabase(); - const USHORT pageSpaceId = relation->getBasePages()->rel_pg_space_id; + const ULONG pageSpaceId = relation->getBasePages()->rel_pg_space_id; WIN window(pageSpaceId, -1); window.win_flags = WIN_garbage_collector; @@ -2471,7 +2471,7 @@ void Validation::walk_pip() MET_scan_tablespaces(vdr_tdbb); - for (USHORT pageSpaceId = DB_PAGE_SPACE; pageSpaceId < TRANS_PAGE_SPACE; pageSpaceId++) + for (ULONG pageSpaceId = DB_PAGE_SPACE; pageSpaceId < TRANS_PAGE_SPACE; pageSpaceId++) { const PageSpace* pageSpace = pageSpaceMgr.findPageSpace(pageSpaceId); if (!pageSpace) @@ -2609,7 +2609,7 @@ Validation::RTN Validation::walk_pointer_page(jrd_rel* relation, ULONG sequence) return corrupt(VAL_P_PAGE_LOST, relation, sequence); pointer_page* page = 0; - const USHORT pageSpaceId = relation->getBasePages()->rel_pg_space_id; + const ULONG pageSpaceId = relation->getBasePages()->rel_pg_space_id; WIN window(pageSpaceId, -1); window.win_flags = WIN_garbage_collector; @@ -2862,7 +2862,7 @@ Validation::RTN Validation::walk_record(jrd_rel* relation, const rhd* header, US data_page* page = 0; while (flags & rhd_incomplete) { - const USHORT pageSpaceId = relation->getBasePages()->rel_pg_space_id; + const ULONG pageSpaceId = relation->getBasePages()->rel_pg_space_id; WIN window(pageSpaceId, -1); window.win_flags = WIN_garbage_collector; @@ -2966,7 +2966,7 @@ void Validation::checkDPinPP(jrd_rel* relation, ULONG page_number) * Early in walk_chain we observed that this page in related to the relation so we skip such kind of check here. **************************************/ - const USHORT pageSpaceId = relation->getBasePages()->rel_pg_space_id; + const ULONG pageSpaceId = relation->getBasePages()->rel_pg_space_id; WIN window(pageSpaceId, page_number); data_page* dpage; @@ -3042,7 +3042,7 @@ void Validation::checkDPinPIP(jrd_rel* relation, ULONG page_number) Database* dbb = vdr_tdbb->getDatabase(); - const USHORT pageSpaceId = relation->getBasePages()->rel_pg_space_id; + const ULONG pageSpaceId = relation->getBasePages()->rel_pg_space_id; PageManager& pageMgr = dbb->dbb_page_manager; PageSpace* pageSpace = pageMgr.findPageSpace(pageSpaceId); fb_assert(pageSpace); @@ -3173,7 +3173,7 @@ Validation::RTN Validation::walk_relation(jrd_rel* relation) if (rs->fetch(vdr_tdbb)) { // Try to restore pages and check every page that it is a pointer page and belongs to the relation - const USHORT pageSpaceId = relation->getBasePages()->rel_pg_space_id; + const ULONG pageSpaceId = relation->getBasePages()->rel_pg_space_id; ULONG sequence = 0; while (pointerPage) { @@ -3323,7 +3323,7 @@ Validation::RTN Validation::walk_root(jrd_rel* relation, bool getInfo) if (!relPages->rel_index_root) return corrupt(VAL_INDEX_ROOT_MISSING, relation); - const USHORT pageSpaceId = relPages->rel_pg_space_id; + const ULONG pageSpaceId = relPages->rel_pg_space_id; index_root_page* page = 0; WIN window(pageSpaceId, -1); fetch_page(!getInfo, PageNumber(pageSpaceId, relPages->rel_index_root), pag_root, &window, &page); @@ -3445,7 +3445,7 @@ Validation::RTN Validation::walk_scns() PageManager& pageMgr = dbb->dbb_page_manager; - for (USHORT pageSpaceId = DB_PAGE_SPACE; pageSpaceId < TRANS_PAGE_SPACE; pageSpaceId++) + for (ULONG pageSpaceId = DB_PAGE_SPACE; pageSpaceId < TRANS_PAGE_SPACE; pageSpaceId++) { PageSpace* pageSpace = pageMgr.findPageSpace(pageSpaceId); if (!pageSpace) diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index 28cfaa8f76f..4ed5ad5f597 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -6348,7 +6348,7 @@ static PrepareResult prepare_update(thread_db* tdbb, jrd_tra* transaction, TraNu } { - const USHORT pageSpaceID = temp->getWindow(tdbb).win_page.getPageSpaceID(); + const ULONG pageSpaceID = temp->getWindow(tdbb).win_page.getPageSpaceID(); stack.push(PageNumber(pageSpaceID, temp->rpb_page)); } return PrepareResult::SUCCESS; @@ -6923,7 +6923,7 @@ void VIO_update_in_place(thread_db* tdbb, if (stack) { - const USHORT pageSpaceID = temp2.getWindow(tdbb).win_page.getPageSpaceID(); + const ULONG pageSpaceID = temp2.getWindow(tdbb).win_page.getPageSpaceID(); stack->push(PageNumber(pageSpaceID, temp2.rpb_page)); } } From 63e24184c046187194d3467a9c7f67473ad2023c Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Wed, 18 May 2022 16:24:29 +0300 Subject: [PATCH 73/97] Temporarily reduce the maximum amount of tablespaces --- src/jrd/pag.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/jrd/pag.h b/src/jrd/pag.h index cf0322d694a..c380c787810 100644 --- a/src/jrd/pag.h +++ b/src/jrd/pag.h @@ -65,7 +65,8 @@ const ULONG INVALID_PAGE_SPACE = 0; const ULONG DB_PAGE_SPACE = 1; // .. here all tablespace IDs. Keep TRANS_PAGE_SPACE right after DB_PAGE_SPACE. // Note that the max tablespace ID should be MAX_USHORT as long as dfw_id is USHORT. -const ULONG TRANS_PAGE_SPACE = MAX_USHORT + 1; // is not used for tablespace id +//const ULONG TRANS_PAGE_SPACE = MAX_USHORT + 1; // is not used for tablespace id +const ULONG TRANS_PAGE_SPACE = 255; const ULONG TEMP_PAGE_SPACE = TRANS_PAGE_SPACE + 1; const ULONG MAX_PAGE_SPACE_ID = MAX_ULONG; From 3d51bcb10d0c0a195bc400f47f573d3a3131170a Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 20 May 2022 11:14:23 +0300 Subject: [PATCH 74/97] Create ObjectsArray in the default memory pool instead of the dbb permanent memory pool because the last one will be destroyed below in this function before ~ObjectsArray call --- src/jrd/jrd.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 5164de28639..7ba9d131d1d 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -3459,7 +3459,10 @@ void JAttachment::internalDropDatabase(CheckStatusWrapper* user_status) Ods::header_page* header = NULL; XThreadEnsureUnlock threadGuard(dbb->dbb_thread_mutex, FB_FUNCTION); - ObjectsArray tsFiles; + // Use the default memory pool instead of the dbb permanent memory pool + // because the last one will be destroyed below in this function + // before ~ObjectsArray call. + ObjectsArray tsFiles(*getDefaultMemoryPool()); try { From 3a7b98010a05c100e3cb6b16e39cc04a9e23f6d5 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Tue, 21 Jun 2022 14:58:26 +0300 Subject: [PATCH 75/97] Do not store tablespaces privileges in RDB$USER_PRIVILEGES because they are not implemented yet --- src/dsql/TablespaceNodes.epp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index bee98054396..449d7031382 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -179,8 +179,6 @@ void CreateAlterTablespaceNode::executeCreate(thread_db* tdbb, DsqlCompilerScrat } } - storePrivileges(tdbb, transaction, name, obj_tablespace, ALL_PRIVILEGES); - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_TABLESPACE, name, NULL); } From c31777e02db7f83e543aab4138c9129e5c67f163 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Wed, 8 Jun 2022 12:34:08 +0300 Subject: [PATCH 76/97] Add apply_tablespaces_ddl parameter to replication.conf If disabled, tablespaces-related DDL statements and clauses in CREATE/ALTER TABLE/INDEX will not be applied to the replica. --- builds/install/misc/replication.conf | 25 +++++++++++++++---------- src/dsql/DdlNodes.epp | 12 +++++++++--- src/dsql/Nodes.h | 6 ++++++ src/dsql/TablespaceNodes.epp | 6 ++++++ src/jrd/Database.cpp | 4 +++- src/jrd/replication/Config.cpp | 21 ++++++++++++++++++--- src/jrd/replication/Config.h | 3 +++ src/jrd/replication/Publisher.cpp | 2 +- 8 files changed, 61 insertions(+), 18 deletions(-) diff --git a/builds/install/misc/replication.conf b/builds/install/misc/replication.conf index 54bf02da664..a4daf718a60 100644 --- a/builds/install/misc/replication.conf +++ b/builds/install/misc/replication.conf @@ -14,12 +14,12 @@ database # Pattern (regular expression) that defines what tables must be included into # replication. By default, all tables are replicated. # - # include_filter = + # include_filter = # Pattern (regular expression) that defines what tables must be excluded from # replication. By default, all tables are replicated. # - # exclude_filter = + # exclude_filter = # Boolean parameters describing how replication errors must be handled. # @@ -42,20 +42,20 @@ database # Directory to store replication journal files. # - # journal_directory = + # journal_directory = # Prefix for replication journal file names. It will be automatically suffixed # with an ordinal sequential number. If not specified, database filename # (without path) is used as a prefix. # - # journal_file_prefix = + # journal_file_prefix = # Maximum allowed size for a single replication segment. # # journal_segment_size = 16777216 # 16MB # Maximum allowed number of full replication segments. Once this limit is reached, - # the replication process is temporarily delayed to allow the archiving to catch up. + # the replication process is temporarily delayed to allow the archiving to catch up. # If any of the full segments is not archived during one minute, # the replication fails with an error. # @@ -76,7 +76,7 @@ database # Directory to store archived replication segments. # It also defines the $(archpathname) substitution macro (see below). # - # journal_archive_directory = + # journal_archive_directory = # Program (complete command line with arguments) that is executed when some # replication segment gets full and needs archiving. @@ -97,7 +97,7 @@ database # or # Windows: "copy $(pathname) $(archivepathname)" # - # journal_archive_command = + # journal_archive_command = # Timeout, in seconds, to wait until incomplete segment is scheduled for archiving. # It allows to minimize the replication gap if the database is modified rarely. @@ -121,7 +121,7 @@ database # # Multiple entries are allowed (for different synchronous replicas). # - # sync_replica = + # sync_replica = ### REPLICA SIDE SETTINGS @@ -135,13 +135,13 @@ database # Directory to search for the journal files to be replicated. # - # journal_source_directory = + # journal_source_directory = # Filter to limit replication to the particular source database (based on its GUID). # Expected format: "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" # Note that double quotes are mandatory, as well as curly braces. # - # source_guid = + # source_guid = # If enabled, replication.log contains the detailed log of operations performed # by the replication server. Otherwise (by default), only errors and warnings are logged. @@ -162,6 +162,11 @@ database # then reconnects back and tries to re-apply the latest segments from the point of failure. # # apply_error_timeout = 60 + + # If disabled, tablespaces-related DDL statements and clauses in + # CREATE/ALTER TABLE/INDEX will not be applied to the replica. + # + # apply_tablespaces_ddl = true } # diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 0cbe206e08a..137c27cf301 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -6249,7 +6249,7 @@ void RelationNode::FieldDefinition::store(thread_db* tdbb, jrd_tra* transaction) baseField.c_str(), RFR.RDB$FIELD_SOURCE); } - if (tableSpace.hasData()) + if (tableSpace.hasData() && applyTablespacesDdl(tdbb)) { if (!checkObjectExist(tdbb, transaction, tableSpace, obj_tablespaces)) status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << tableSpace.c_str()); @@ -7571,7 +7571,7 @@ void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat REL.RDB$VIEW_SOURCE.NULL = TRUE; REL.RDB$EXTERNAL_FILE.NULL = TRUE; - if (tableSpace.hasData() && tableSpace != PRIMARY_TABLESPACE_NAME) + if (tableSpace.hasData() && tableSpace != PRIMARY_TABLESPACE_NAME && applyTablespacesDdl(tdbb)) { if (!checkObjectExist(tdbb, transaction, tableSpace, obj_tablespaces)) status_exception::raise(Arg::Gds(isc_dyn_ts_not_found) << tableSpace.c_str()); @@ -8073,6 +8073,9 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc { fb_assert(tableSpace.hasData()); + if (!applyTablespacesDdl(tdbb)) + break; + const bool primary_ts = (tableSpace == PRIMARY_TABLESPACE_NAME); if (!primary_ts && !checkObjectExist(tdbb, transaction, tableSpace, obj_tablespaces)) @@ -9840,7 +9843,7 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam IDX.RDB$INDEX_TYPE = SSHORT(definition.descending.asBool()); } - if (definition.tableSpace.hasData()) + if (definition.tableSpace.hasData() && applyTablespacesDdl(tdbb)) { if (temporary) status_exception::raise(Arg::Gds(isc_dyn_cant_set_ts_index) << IDX.RDB$INDEX_NAME); @@ -10309,6 +10312,9 @@ void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, fb_assert(op == OP_SET_TABLESPACE); fb_assert(tableSpace.hasData()); + if (!applyTablespacesDdl(tdbb)) + break; + const bool primary_ts = (tableSpace == PRIMARY_TABLESPACE_NAME); if (!primary_ts && !checkObjectExist(tdbb, transaction, tableSpace, obj_tablespaces)) diff --git a/src/dsql/Nodes.h b/src/dsql/Nodes.h index 5bbb59a4465..5ff5bf3ee70 100644 --- a/src/dsql/Nodes.h +++ b/src/dsql/Nodes.h @@ -192,6 +192,12 @@ class DdlNode : public Node static void deletePrivilegesByRelName(thread_db* tdbb, jrd_tra* transaction, const MetaName& name, int type); + static inline bool applyTablespacesDdl(thread_db* tdbb) + { + return !(tdbb->tdbb_flags & TDBB_replicator) || + tdbb->getDatabase()->replConfig()->applyTablespacesDdl; + } + public: // Check permission on DDL operation. Return true if everything is OK. // Raise an exception for bad permission. diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index 449d7031382..cbf31c32f72 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -81,6 +81,9 @@ void CreateAlterTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* ds { fb_assert(create || alter); + if (!applyTablespacesDdl(tdbb)) + return; + PathUtils::fixupSeparators(fileName); if (PathUtils::isRelative(fileName)) @@ -276,6 +279,9 @@ void DropTablespaceNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { + if (!applyTablespacesDdl(tdbb)) + return; + // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); diff --git a/src/jrd/Database.cpp b/src/jrd/Database.cpp index e24efbb3646..711ddb26bce 100644 --- a/src/jrd/Database.cpp +++ b/src/jrd/Database.cpp @@ -393,7 +393,9 @@ namespace Jrd bool Database::isReplicating(thread_db* tdbb) { - if (!replConfig()) + const auto config = replConfig(); + + if (!config || !config->isMaster()) return false; Sync sync(&dbb_repl_sync, FB_FUNCTION); diff --git a/src/jrd/replication/Config.cpp b/src/jrd/replication/Config.cpp index f4e868ca990..4e5dff06e87 100644 --- a/src/jrd/replication/Config.cpp +++ b/src/jrd/replication/Config.cpp @@ -126,7 +126,8 @@ Config::Config() logErrors(true), reportErrors(false), disableOnError(true), - cascadeReplication(false) + cascadeReplication(false), + applyTablespacesDdl(true) { } @@ -152,7 +153,8 @@ Config::Config(const Config& other) logErrors(other.logErrors), reportErrors(other.reportErrors), disableOnError(other.disableOnError), - cascadeReplication(other.cascadeReplication) + cascadeReplication(other.cascadeReplication), + applyTablespacesDdl(other.applyTablespacesDdl) { } @@ -288,6 +290,10 @@ Config* Config::get(const PathName& lookupName) { parseBoolean(value, config->cascadeReplication); } + else if (key == "apply_tablespaces_ddl") + { + parseBoolean(value, config->applyTablespacesDdl); + } } if (exactMatch) @@ -299,7 +305,7 @@ Config* Config::get(const PathName& lookupName) if (config->pluginName.hasData()) return config.release(); - if (config->journalDirectory.hasData() || config->syncReplicas.hasData()) + if (config->isMaster()) { // If either journal_directory or sync_replicas is specified, // then replication is enabled @@ -405,6 +411,10 @@ void Config::enumerate(ReplicaList& replicas) { parseLong(value, config->applyErrorTimeout); } + else if (key == "apply_tablespaces_ddl") + { + parseBoolean(value, config->applyTablespacesDdl); + } } if (dbName.hasData() && config->sourceDirectory.hasData()) @@ -427,3 +437,8 @@ void Config::enumerate(ReplicaList& replicas) logReplicaStatus(dbName, &localStatus); } } + +bool Config::isMaster() const +{ + return journalDirectory.hasData() || syncReplicas.hasData(); +} diff --git a/src/jrd/replication/Config.h b/src/jrd/replication/Config.h index 72f29080c3e..24bd44c890c 100644 --- a/src/jrd/replication/Config.h +++ b/src/jrd/replication/Config.h @@ -43,6 +43,8 @@ namespace Replication static Config* get(const Firebird::PathName& dbName); static void enumerate(ReplicaList& replicas); + bool isMaster() const; + Firebird::PathName dbName; ULONG bufferSize; Firebird::string includeFilter; @@ -66,6 +68,7 @@ namespace Replication bool reportErrors; bool disableOnError; bool cascadeReplication; + bool applyTablespacesDdl; }; }; diff --git a/src/jrd/replication/Publisher.cpp b/src/jrd/replication/Publisher.cpp index dd141d55dc5..1386a4ed969 100644 --- a/src/jrd/replication/Publisher.cpp +++ b/src/jrd/replication/Publisher.cpp @@ -398,7 +398,7 @@ void REPL_attach(thread_db* tdbb, bool cleanupTransactions) const auto attachment = tdbb->getAttachment(); const auto replConfig = dbb->replConfig(); - if (!replConfig) + if (!replConfig || !replConfig->isMaster()) return; fb_assert(!attachment->att_repl_matcher); From d8be9fe8280b21bbcfc58c02d4f5016b760ca4ac Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 8 Jul 2022 11:04:18 +0300 Subject: [PATCH 77/97] Always enable replication if a plugin name is specified in replication.conf --- src/jrd/Database.cpp | 2 +- src/jrd/replication/Publisher.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jrd/Database.cpp b/src/jrd/Database.cpp index 711ddb26bce..1983f91b03d 100644 --- a/src/jrd/Database.cpp +++ b/src/jrd/Database.cpp @@ -395,7 +395,7 @@ namespace Jrd { const auto config = replConfig(); - if (!config || !config->isMaster()) + if (!config || (!config->isMaster() && config->pluginName.isEmpty())) return false; Sync sync(&dbb_repl_sync, FB_FUNCTION); diff --git a/src/jrd/replication/Publisher.cpp b/src/jrd/replication/Publisher.cpp index 1386a4ed969..ddfb10e4f2f 100644 --- a/src/jrd/replication/Publisher.cpp +++ b/src/jrd/replication/Publisher.cpp @@ -398,7 +398,7 @@ void REPL_attach(thread_db* tdbb, bool cleanupTransactions) const auto attachment = tdbb->getAttachment(); const auto replConfig = dbb->replConfig(); - if (!replConfig || !replConfig->isMaster()) + if (!replConfig || (!replConfig->isMaster() && replConfig->pluginName.isEmpty())) return; fb_assert(!attachment->att_repl_matcher); From 2f1a46b213ec9b77c81093a7bca7aab714084867 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Mon, 16 Jan 2023 11:03:35 +0300 Subject: [PATCH 78/97] Add a missing argument to gfix message about inconsistent flags --- src/jrd/validation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jrd/validation.cpp b/src/jrd/validation.cpp index fd84ca05581..ddbe81023d0 100644 --- a/src/jrd/validation.cpp +++ b/src/jrd/validation.cpp @@ -2684,7 +2684,7 @@ Validation::RTN Validation::walk_pointer_page(jrd_rel* relation, ULONG sequence) corrupt(VAL_P_PAGE_WRONG_BITS, relation, pageSpaceId, page->ppg_header.pag_pageno, sequence, pp_bits, s_pp.c_str(), - *pages, seq, new_pp_bits, s_dp.c_str()); + pageSpaceId, *pages, seq, new_pp_bits, s_dp.c_str()); if ((vdr_flags & VDR_update)) { From 97530887b5e3d8e9228856b85382c162aec3dd5b Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Mon, 9 Oct 2023 17:43:21 +0300 Subject: [PATCH 79/97] Fix an ambiguity in the parser which causes the server to crash due to out of memory A clause (tablespace_name_clause) should not be optional if it's used in another optional clause (table_attributes). Example of a statement with the issue: execute statement 'create table test_table(id int); a'; --- src/dsql/parse-conflicts.txt | 2 +- src/dsql/parse.y | 29 +++++++++++++++++------------ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/dsql/parse-conflicts.txt b/src/dsql/parse-conflicts.txt index 10e43bf848e..522dee2236d 100644 --- a/src/dsql/parse-conflicts.txt +++ b/src/dsql/parse-conflicts.txt @@ -1 +1 @@ -121 shift/reduce conflicts, 28 reduce/reduce conflicts. +101 shift/reduce conflicts, 56 reduce/reduce conflicts. diff --git a/src/dsql/parse.y b/src/dsql/parse.y index b02b52e4647..77940c43e9e 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -1566,7 +1566,7 @@ create_clause node->relation = $7; $$ = node; } - index_definition(static_cast($8)) tablespace_name_clause + index_definition(static_cast($8)) tablespace_name_clause_opt { if ($10) static_cast($8)->tableSpace = *$10; @@ -2662,7 +2662,7 @@ column_constraint($addColumnClause) constraint.check = $1; } | REFERENCES symbol_table_name column_parens_opt - referential_trigger_action constraint_index_opt tablespace_name_clause + referential_trigger_action constraint_index_opt tablespace_name_clause_opt { RelationNode::AddConstraintClause& constraint = $addColumnClause->constraints.add(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_FK; @@ -2685,7 +2685,7 @@ column_constraint($addColumnClause) if ($6) constraint.tableSpace = *$6; } - | UNIQUE constraint_index_opt tablespace_name_clause + | UNIQUE constraint_index_opt tablespace_name_clause_opt { RelationNode::AddConstraintClause& constraint = $addColumnClause->constraints.add(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_UNIQUE; @@ -2694,7 +2694,7 @@ column_constraint($addColumnClause) if ($3) constraint.tableSpace = *$3; } - | PRIMARY KEY constraint_index_opt tablespace_name_clause + | PRIMARY KEY constraint_index_opt tablespace_name_clause_opt { RelationNode::AddConstraintClause& constraint = $addColumnClause->constraints.add(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_PK; @@ -2726,7 +2726,7 @@ constraint_name_opt %type table_constraint() table_constraint($relationNode) - : UNIQUE column_parens constraint_index_opt tablespace_name_clause + : UNIQUE column_parens constraint_index_opt tablespace_name_clause_opt { RelationNode::AddConstraintClause& constraint = *newNode(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_UNIQUE; @@ -2745,7 +2745,7 @@ table_constraint($relationNode) $relationNode->clauses.add(&constraint); $$ = &constraint; } - | PRIMARY KEY column_parens constraint_index_opt tablespace_name_clause + | PRIMARY KEY column_parens constraint_index_opt tablespace_name_clause_opt { RelationNode::AddConstraintClause& constraint = *newNode(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_PK; @@ -2765,7 +2765,7 @@ table_constraint($relationNode) $$ = &constraint; } | FOREIGN KEY column_parens REFERENCES symbol_table_name column_parens_opt - referential_trigger_action constraint_index_opt tablespace_name_clause + referential_trigger_action constraint_index_opt tablespace_name_clause_opt { RelationNode::AddConstraintClause& constraint = *newNode(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_FK; @@ -5286,7 +5286,7 @@ without_time_zone_opt %type blob_type blob_type - : BLOB { $$ = newNode(); } blob_subtype(NOTRIAL($2)) blob_segsize charset_clause /*tablespace_name_clause*/ + : BLOB { $$ = newNode(); } blob_subtype(NOTRIAL($2)) blob_segsize charset_clause /*tablespace_name_clause_opt*/ { $$ = $2; $$->dtype = dtype_blob; @@ -5301,7 +5301,7 @@ blob_type //if ($6) // $$->fld_ts_name = *$6; } - | BLOB '(' unsigned_short_integer ')' /*tablespace_name_clause*/ + | BLOB '(' unsigned_short_integer ')' /*tablespace_name_clause_opt*/ { $$ = newNode(); $$->dtype = dtype_blob; @@ -5312,7 +5312,7 @@ blob_type //if ($5) // $$->fld_ts_name = *$5; } - | BLOB '(' unsigned_short_integer ',' signed_short_integer ')' /*tablespace_name_clause*/ + | BLOB '(' unsigned_short_integer ',' signed_short_integer ')' /*tablespace_name_clause_opt*/ { $$ = newNode(); $$->dtype = dtype_blob; @@ -5324,7 +5324,7 @@ blob_type //if ($7) // $$->fld_ts_name = *$7; } - | BLOB '(' ',' signed_short_integer ')' /*tablespace_name_clause*/ + | BLOB '(' ',' signed_short_integer ')' /*tablespace_name_clause_opt*/ { $$ = newNode(); $$->dtype = dtype_blob; @@ -8003,8 +8003,13 @@ replace_tablespace_clause %type tablespace_name_clause tablespace_name_clause + : in_opt TABLESPACE symbol_tablespace_name { $$ = $3; } + ; + +%type tablespace_name_clause_opt +tablespace_name_clause_opt : /* nothing */ { $$ = NULL; } - | in_opt TABLESPACE symbol_tablespace_name { $$ = $3; } + | tablespace_name_clause { $$ = $1; } ; %type drop_tablespace_clause From cdacf7ab7654dec9730b5aed4559ad3248ad912a Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Wed, 30 Mar 2022 15:32:54 +0300 Subject: [PATCH 80/97] Flush only pages from a page space of a tablespace which is being altered or dropped --- src/jrd/cch.cpp | 45 +++++++++++++++++++++++++-------------------- src/jrd/cch_proto.h | 2 +- src/jrd/dfw.epp | 6 +++--- src/jrd/pag.h | 1 - 4 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/jrd/cch.cpp b/src/jrd/cch.cpp index 78a04d7c2b1..1f30b933220 100644 --- a/src/jrd/cch.cpp +++ b/src/jrd/cch.cpp @@ -188,7 +188,7 @@ static inline void removeDirty(BufferControl* bcb, BufferDesc* bdb) } static void flushDirty(thread_db* tdbb, SLONG transaction_mask, const bool sys_only); -static void flushAll(thread_db* tdbb, USHORT flush_flag); +static void flushAll(thread_db* tdbb, USHORT flush_flag, ULONG page_space_id); static void flushPages(thread_db* tdbb, USHORT flush_flag, BufferDesc** begin, FB_SIZE_T count); static void recentlyUsed(BufferDesc* bdb); @@ -1178,7 +1178,7 @@ void CCH_fini(thread_db* tdbb) } -void CCH_flush(thread_db* tdbb, USHORT flush_flag, TraNumber tra_number) +void CCH_flush(thread_db* tdbb, USHORT flush_flag, TraNumber tra_number, ULONG page_space_id) { /************************************** * @@ -1220,7 +1220,7 @@ void CCH_flush(thread_db* tdbb, USHORT flush_flag, TraNumber tra_number) flushDirty(tdbb, transaction_mask, sys_only); } else - flushAll(tdbb, flush_flag); + flushAll(tdbb, flush_flag, page_space_id); // // Check if flush needed @@ -2709,7 +2709,7 @@ static void flushDirty(thread_db* tdbb, SLONG transaction_mask, const bool sys_o // Collect pages modified by garbage collector or all dirty pages or release page // locks - depending of flush_flag, and write it to disk. // See also comments in flushPages. -static void flushAll(thread_db* tdbb, USHORT flush_flag) +static void flushAll(thread_db* tdbb, USHORT flush_flag, ULONG page_space_id) { SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); @@ -2732,28 +2732,33 @@ static void flushAll(thread_db* tdbb, USHORT flush_flag) { BufferDesc* bdb = &blk.m_bdbs[i]; - if (bdb->bdb_flags & (BDB_db_dirty | BDB_dirty)) + if (page_space_id == INVALID_PAGE_SPACE || + bdb->bdb_page.getPageSpaceID() == page_space_id) { - if (bdb->bdb_flags & BDB_dirty) - flush.add(bdb); - else if (bdb->bdb_flags & BDB_db_dirty) - { - // pages modified by sweep\garbage collector are not in dirty list - const bool dirty_list = (bdb->bdb_dirty.que_forward != &bdb->bdb_dirty); - if (all_flag || (sweep_flag && !dirty_list)) + if (bdb->bdb_flags & (BDB_db_dirty | BDB_dirty)) + { + if (bdb->bdb_flags & BDB_dirty) flush.add(bdb); + else if (bdb->bdb_flags & BDB_db_dirty) + { + // pages modified by sweep\garbage collector are not in dirty list + const bool dirty_list = (bdb->bdb_dirty.que_forward != &bdb->bdb_dirty); + + if (all_flag || (sweep_flag && !dirty_list)) + flush.add(bdb); + } } - } - else if (release_flag) - { - bdb->addRef(tdbb, SYNC_EXCLUSIVE); + else if (release_flag) + { + bdb->addRef(tdbb, SYNC_EXCLUSIVE); - if (bdb->bdb_use_count > 1) - BUGCHECK(210); // msg 210 page in use during flush + if (bdb->bdb_use_count > 1) + BUGCHECK(210); // msg 210 page in use during flush - PAGE_LOCK_RELEASE(tdbb, bcb, bdb->bdb_lock); - bdb->release(tdbb, false); + PAGE_LOCK_RELEASE(tdbb, bcb, bdb->bdb_lock); + bdb->release(tdbb, false); + } } } } diff --git a/src/jrd/cch_proto.h b/src/jrd/cch_proto.h index eec794bb6b2..bd1cb7df151 100644 --- a/src/jrd/cch_proto.h +++ b/src/jrd/cch_proto.h @@ -51,7 +51,7 @@ LockState CCH_fetch_lock(Jrd::thread_db*, Jrd::win*, int, int, SCHAR); void CCH_fetch_page(Jrd::thread_db*, Jrd::win*, const bool); void CCH_fini(Jrd::thread_db*); void CCH_forget_page(Jrd::thread_db*, Jrd::win*); -void CCH_flush(Jrd::thread_db* tdbb, USHORT flush_flag, TraNumber tra_number); +void CCH_flush(Jrd::thread_db* tdbb, USHORT flush_flag, TraNumber tra_number, ULONG page_space_id = Jrd::INVALID_PAGE_SPACE); bool CCH_free_page(Jrd::thread_db*); SLONG CCH_get_incarnation(Jrd::win*); void CCH_get_related(Jrd::thread_db*, Jrd::PageNumber, Jrd::PagesArray&); diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 50ac0504f72..e86012370aa 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -6745,7 +6745,7 @@ static bool create_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, { if (dbb->dbb_page_manager.findPageSpace(work->dfw_id)) { - CCH_flush(tdbb, FLUSH_ALL, 0); + CCH_flush(tdbb, FLUSH_ALL, 0, work->dfw_id); dbb->dbb_page_manager.delPageSpace(work->dfw_id); unlink(TS.RDB$FILE_NAME); } @@ -6837,7 +6837,7 @@ static bool drop_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, j case 3: return true; case 4: - CCH_flush(tdbb, FLUSH_ALL, 0); + CCH_flush(tdbb, FLUSH_ALL, 0, work->dfw_id); dbb->dbb_page_manager.delPageSpace(work->dfw_id); LCK_release(tdbb, tablespace->existenceLock); @@ -6895,7 +6895,7 @@ static bool modify_tablespace(thread_db* tdbb, SSHORT phase, DeferredWork* work, case 3: return true; case 4: - CCH_flush(tdbb, FLUSH_ALL, 0); + CCH_flush(tdbb, FLUSH_ALL, 0, work->dfw_id); dbb->dbb_page_manager.delPageSpace(work->dfw_id); LCK_release(tdbb, tablespace->existenceLock); diff --git a/src/jrd/pag.h b/src/jrd/pag.h index c380c787810..8b4adc01b70 100644 --- a/src/jrd/pag.h +++ b/src/jrd/pag.h @@ -231,7 +231,6 @@ class PageNumber inline ULONG getPageSpaceID() const { - fb_assert(pageSpaceID != INVALID_PAGE_SPACE); return pageSpaceID; } From 9adb4866c8502b2fb0b7b9b19308344dc64f9b20 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Mon, 5 Sep 2022 15:58:57 +0300 Subject: [PATCH 81/97] Delete indexes after tables during DROP TABLESPACE INCLUDING CONTENTS to prevent dependency issues (see RS-78271) --- src/dsql/TablespaceNodes.epp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index cbf31c32f72..48db9b1a8ee 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -313,22 +313,21 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat SLONG total = 0; - // Find all indices - requestHandle.reset(tdbb, drq_ts_drop_idx_dfw, DYN_REQUESTS); + // Find all tables + requestHandle.reset(tdbb, drq_ts_drop_rel_dfw, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) - X IN RDB$INDICES + X IN RDB$RELATIONS WITH X.RDB$TABLESPACE_NAME EQ name.c_str() { if (dropDependencies) { - if (X.RDB$EXPRESSION_BLR.NULL && !DropIndexNode::deleteSegmentRecords(tdbb, transaction, X.RDB$INDEX_NAME)) - { - // msg 50: "No segments found for index" - status_exception::raise(Arg::PrivateDyn(50)); - } + MetaName relationName(X.RDB$RELATION_NAME); + jrd_rel* rel_drop = MET_lookup_relation(tdbb, relationName); + if (rel_drop) + MET_scan_relation(tdbb, rel_drop); - ERASE X; + DropRelationNode::dropRelation(tdbb, dsqlScratch, transaction, false, rel_drop, relationName); } else { @@ -337,21 +336,22 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat } END_FOR - // Find all tables - requestHandle.reset(tdbb, drq_ts_drop_rel_dfw, DYN_REQUESTS); + // Find all indices + requestHandle.reset(tdbb, drq_ts_drop_idx_dfw, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) - X IN RDB$RELATIONS + X IN RDB$INDICES WITH X.RDB$TABLESPACE_NAME EQ name.c_str() { if (dropDependencies) { - MetaName relationName(X.RDB$RELATION_NAME); - jrd_rel* rel_drop = MET_lookup_relation(tdbb, relationName); - if (rel_drop) - MET_scan_relation(tdbb, rel_drop); + if (X.RDB$EXPRESSION_BLR.NULL && !DropIndexNode::deleteSegmentRecords(tdbb, transaction, X.RDB$INDEX_NAME)) + { + // msg 50: "No segments found for index" + status_exception::raise(Arg::PrivateDyn(50)); + } - DropRelationNode::dropRelation(tdbb, dsqlScratch, transaction, false, rel_drop, relationName); + ERASE X; } else { From 8a3436aec767acd5394b9ffea6f69f3536f5322c Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Mon, 5 Sep 2022 17:58:58 +0300 Subject: [PATCH 82/97] Do not execute DDL triggers for a table when it's deleted during DROP TABLESPACE INCLUDING CONTENTS (see RS-78271) --- src/dsql/DdlNodes.epp | 66 ++++++++++++++++-------------------- src/dsql/DdlNodes.h | 2 +- src/dsql/TablespaceNodes.epp | 2 +- 3 files changed, 32 insertions(+), 38 deletions(-) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 137c27cf301..8429e325a3c 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -8687,7 +8687,7 @@ void DropRelationNode::deleteGlobalField(thread_db* tdbb, jrd_tra* transaction, } -void DropRelationNode::dropRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, bool view, jrd_rel* rel_drop, const MetaName& name) +void DropRelationNode::dropRelation(thread_db* tdbb, jrd_tra* transaction, bool view, jrd_rel* rel_drop, const MetaName& name) { if (!view && rel_drop) { @@ -8698,24 +8698,7 @@ void DropRelationNode::dropRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlSc DPM_scan_pages(tdbb, pag_root, rel_drop->rel_id); } - const int ddlTriggerAction = (view ? DDL_TRIGGER_DROP_VIEW : DDL_TRIGGER_DROP_TABLE); - - // run all statements under savepoint control - AutoSavePoint savePoint(tdbb, transaction); - - AutoCacheRequest request(tdbb, drq_l_relation, DYN_REQUESTS); - bool found = false; - - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - R IN RDB$RELATIONS - WITH R.RDB$RELATION_NAME EQ name.c_str() - { - executeDdlTrigger(tdbb, transaction, DTW_BEFORE, ddlTriggerAction, name, NULL, *dsqlScratch->getDsqlStatement()->getSqlText()); - found = true; - } - END_FOR - - request.reset(tdbb, drq_e_rel_con2, DYN_REQUESTS); + AutoCacheRequest request(tdbb, drq_e_rel_con2, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) CRT IN RDB$RELATION_CONSTRAINTS @@ -8812,12 +8795,6 @@ void DropRelationNode::dropRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlSc } END_FOR - if (!found) - { - // msg 61: "Relation not found" - status_exception::raise(Arg::PrivateDyn(61)); - } - // Triggers must be deleted after check constraints MetaName triggerName; @@ -8871,16 +8848,6 @@ void DropRelationNode::dropRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlSc } END_FOR - if (found) - executeDdlTrigger(tdbb, transaction, DTW_AFTER, ddlTriggerAction, name, NULL, *dsqlScratch->getDsqlStatement()->getSqlText()); - else - { - // msg 61: "Relation not found" - status_exception::raise(Arg::PrivateDyn(61)); - } - - savePoint.release(); // everything is ok - METD_drop_relation(transaction, name.c_str()); MET_dsql_cache_release(tdbb, SYM_relation, name); } @@ -8940,7 +8907,34 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch } } - dropRelation(tdbb, dsqlScratch, transaction, view, rel_drop, name); + const int ddlTriggerAction = (view ? DDL_TRIGGER_DROP_VIEW : DDL_TRIGGER_DROP_TABLE); + + // run all statements under savepoint control + AutoSavePoint savePoint(tdbb, transaction); + + AutoCacheRequest request(tdbb, drq_l_relation, DYN_REQUESTS); + bool found = false; + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + R IN RDB$RELATIONS + WITH R.RDB$RELATION_NAME EQ name.c_str() + { + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, ddlTriggerAction, name, NULL); + found = true; + } + END_FOR + + if (!found) + { + // msg 61: "Relation not found" + status_exception::raise(Arg::PrivateDyn(61)); + } + + dropRelation(tdbb, transaction, view, rel_drop, name); + + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, ddlTriggerAction, name, NULL); + + savePoint.release(); // everything is ok } diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index 80f9025a0e8..2a73b5291bb 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -1656,7 +1656,7 @@ class DropRelationNode : public DdlNode static void deleteGlobalField(thread_db* tdbb, jrd_tra* transaction, const MetaName& globalName); - static void dropRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, bool view, jrd_rel* rel_drop, const MetaName& name); + static void dropRelation(thread_db* tdbb, jrd_tra* transaction, bool view, jrd_rel* rel_drop, const MetaName& name); public: virtual Firebird::string internalPrint(NodePrinter& printer) const; diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index 48db9b1a8ee..da25e9389bf 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -327,7 +327,7 @@ void DropTablespaceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat if (rel_drop) MET_scan_relation(tdbb, rel_drop); - DropRelationNode::dropRelation(tdbb, dsqlScratch, transaction, false, rel_drop, relationName); + DropRelationNode::dropRelation(tdbb, transaction, false, rel_drop, relationName); } else { From bbebeaaa8e0151665e77cd309d0dc60f43227ee9 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Fri, 9 Sep 2022 12:43:30 +0300 Subject: [PATCH 83/97] Disable INCLUDING CONTENTS clause in DROP TABLESPACE because it still has limitations and issues that need to be solved (see RS-78271) --- src/dsql/parse.y | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 77940c43e9e..7f3b2504a95 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -8019,13 +8019,12 @@ drop_tablespace_clause DropTablespaceNode* node = newNode(*$1); $$ = node; } - | symbol_tablespace_name INCLUDING CONTENTS - { - - DropTablespaceNode* node = newNode(*$1); - node->dropDependencies = true; - $$ = node; - } +// | symbol_tablespace_name INCLUDING CONTENTS +// { +// DropTablespaceNode* node = newNode(*$1); +// node->dropDependencies = true; +// $$ = node; +// } ; // value types From b3ffd1c8b431f9f873417a2eec82ddc417fac765 Mon Sep 17 00:00:00 2001 From: Alexander Zhdanov Date: Wed, 17 Jul 2024 01:01:12 +0300 Subject: [PATCH 84/97] fix after tablespace porting --- src/jrd/btr.cpp | 2 +- src/jrd/replication/Config.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index c4c63142a1b..2bf5a93d837 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -4055,7 +4055,7 @@ static ULONG fast_load(thread_db* tdbb, // Get the next record in sorted order. UCHAR* record; - creation.sort->get(tdbb, reinterpret_cast(&record)); + scb->get(tdbb, reinterpret_cast(&record)); if (!record || creation.duplicates.value()) break; diff --git a/src/jrd/replication/Config.cpp b/src/jrd/replication/Config.cpp index 4e5dff06e87..56e77dff9e8 100644 --- a/src/jrd/replication/Config.cpp +++ b/src/jrd/replication/Config.cpp @@ -319,9 +319,9 @@ Config* Config::get(const PathName& lookupName) PathUtils::splitLastComponent(db_directory, db_filename, config->dbName); config->filePrefix = db_filename; } - - return config.release(); } + + return config.release(); } catch (const Exception& ex) { From 55d3f606524c7e62e6d58eba7e1c0dd82f9f8c0c Mon Sep 17 00:00:00 2001 From: Alexander Zhdanov Date: Mon, 5 Aug 2024 12:44:47 +0300 Subject: [PATCH 85/97] Added ability to comment on tablespaces --- src/dsql/DdlNodes.epp | 11 +++++++++++ src/dsql/parse.y | 1 + src/isql/show.epp | 16 ++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 8429e325a3c..c0ba188f8f5 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -1457,6 +1457,11 @@ void CommentOnNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) SCL_check_package(tdbb, &dscName, SCL_alter); break; + case obj_tablespace: + dscName.makeText(objNameStr.length(), CS_METADATA, (UCHAR*) objName.identifier.c_str()); + SCL_check_tablespace(tdbb, &dscName, SCL_alter); + break; + default: fb_assert(false); } @@ -1604,6 +1609,12 @@ void CommentOnNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, status << Arg::Gds(isc_dyn_package_not_found) << Arg::Str(objNameStr); break; + case obj_tablespace: + tableClause = "rdb$tablespaces"; + columnClause = "rdb$tablespace_name"; + status << Arg::Gds(isc_dyn_ts_not_found) << Arg::Str(objNameStr); + break; + default: fb_assert(false); return; diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 7f3b2504a95..616d8f28efa 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -6149,6 +6149,7 @@ ddl_type1 | CHARACTER SET { $$ = obj_charset; } | COLLATION { $$ = obj_collation; } | PACKAGE { $$ = obj_package_header; } + | TABLESPACE { $$ = obj_tablespace; } /*** | SECURITY CLASS { $$ = ddl_sec_class; } ***/ diff --git a/src/isql/show.epp b/src/isql/show.epp index bf96a8b4d99..69911cbfe09 100644 --- a/src/isql/show.epp +++ b/src/isql/show.epp @@ -3586,6 +3586,22 @@ static processing_state show_comments(const commentMode showextract, const char* return ps_ERR; END_ERROR } + + if (isqlGlob.major_ods >= ODS_VERSION13) + { + FOR TS IN RDB$TABLESPACES + WITH TS.RDB$DESCRIPTION NOT MISSING + SORTED BY TS.RDB$TABLESPACE_NAME + + show_comment("TABLESPACE", NULL, TS.RDB$TABLESPACE_NAME, NULL, &TS.RDB$DESCRIPTION, + showextract, first ? banner : 0); + first = false; + END_FOR + ON_ERROR + ISQL_errmsg(fbStatus); + return ps_ERR; + END_ERROR + } return first ? OBJECT_NOT_FOUND : SKIP; } From 39553b7817ce3dbc8c149fdef58acc1d9504bcc9 Mon Sep 17 00:00:00 2001 From: Alexander Zhdanov Date: Mon, 5 Aug 2024 12:55:24 +0300 Subject: [PATCH 86/97] Added "IF EXISTS" for drop clause for tablespace --- src/dsql/parse.y | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 616d8f28efa..62880de12e5 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -5078,8 +5078,12 @@ drop_clause node->silentDrop = $3; $$ = node; } - | TABLESPACE drop_tablespace_clause - { $$ = $2; } + | TABLESPACE if_exists_opt drop_tablespace_clause + { + const auto node = $3; + node->silent = $2; + $$ = node; + } ; %type if_exists_opt From 785a411041d1f02f5ff7a397604c0831cb628e43 Mon Sep 17 00:00:00 2001 From: Alexander Zhdanov Date: Mon, 5 Aug 2024 14:56:10 +0300 Subject: [PATCH 87/97] Added CREATE IF NOT EXISTS for tablespaces --- src/dsql/TablespaceNodes.epp | 5 +++++ src/dsql/TablespaceNodes.h | 1 + src/dsql/parse.y | 7 ++++++- src/include/firebird/impl/msg/dyn.h | 1 + src/include/gen/Firebird.pas | 1 + src/jrd/drq.h | 1 + src/jrd/dyn_util.epp | 13 +++++++++++++ 7 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/dsql/TablespaceNodes.epp b/src/dsql/TablespaceNodes.epp index da25e9389bf..d6df9a782d0 100644 --- a/src/dsql/TablespaceNodes.epp +++ b/src/dsql/TablespaceNodes.epp @@ -126,9 +126,14 @@ void CreateAlterTablespaceNode::executeCreate(thread_db* tdbb, DsqlCompilerScrat const MetaName& userName = attachment->att_user->getUserName(); + if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_tablespace)) + return; + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_TABLESPACE, name, NULL); + DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_tablespace); + AutoCacheRequest requestHandle(tdbb, drq_s_tablespace, DYN_REQUESTS); int faults = 0; diff --git a/src/dsql/TablespaceNodes.h b/src/dsql/TablespaceNodes.h index ca74805ff63..ce7f9c1849a 100644 --- a/src/dsql/TablespaceNodes.h +++ b/src/dsql/TablespaceNodes.h @@ -69,6 +69,7 @@ class CreateAlterTablespaceNode : public DdlNode bool alter; bool offline; bool readonly; + bool createIfNotExistsOnly = false; }; diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 62880de12e5..015d5b622c0 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -1677,7 +1677,12 @@ create_clause node->createIfNotExistsOnly = $3; $$ = node; } - | TABLESPACE tablespace_clause { $$ = $2; } + | TABLESPACE if_not_exists_opt tablespace_clause + { + const auto node = $3; + node->createIfNotExistsOnly = $2; + $$ = node; + } ; diff --git a/src/include/firebird/impl/msg/dyn.h b/src/include/firebird/impl/msg/dyn.h index 5a86721f482..4cdd9c59d42 100644 --- a/src/include/firebird/impl/msg/dyn.h +++ b/src/include/firebird/impl/msg/dyn.h @@ -306,3 +306,4 @@ FB_IMPL_MSG_SYMBOL(DYN, 313, dyn_dup_package, "Package @1 already exists") FB_IMPL_MSG(DYN, 314, dyn_ts_not_found, -901, "42", "000", "Tablespace @1 not found") FB_IMPL_MSG(DYN, 315, dyn_cant_set_ts_table, -901, "42", "000", "Cannot set tablespace for temporary table @1") FB_IMPL_MSG(DYN, 316, dyn_cant_set_ts_index, -901, "42", "000", "Cannot set tablespace for temporary index @1") +FB_IMPL_MSG(DYN, 317, dyn_ts_already_exists, -901, "42", "000", "Tablespace @1 already exists") diff --git a/src/include/gen/Firebird.pas b/src/include/gen/Firebird.pas index 2b688002324..7830145bcce 100644 --- a/src/include/gen/Firebird.pas +++ b/src/include/gen/Firebird.pas @@ -5892,6 +5892,7 @@ IProfilerStatsImpl = class(IProfilerStats) isc_dyn_ts_not_found = 336068922; isc_dyn_cant_set_ts_table = 336068923; isc_dyn_cant_set_ts_index = 336068924; + isc_dyn_ts_already_exists = 336068925; isc_gbak_unknown_switch = 336330753; isc_gbak_page_size_missing = 336330754; isc_gbak_page_size_toobig = 336330755; diff --git a/src/jrd/drq.h b/src/jrd/drq.h index cb62d1fc11c..78b8f3a47e5 100644 --- a/src/jrd/drq.h +++ b/src/jrd/drq.h @@ -260,6 +260,7 @@ enum drq_type_t drq_l_pkg_name, // lookup package name drq_l_rel_con, // lookup relation constraint drq_l_rel_fld_name, // lookup relation field name + drq_l_ts_name, // lookup tablespace name drq_ts_drop_idx_dfw, // find index of tablespace in dfw for drop drq_ts_drop_rel_dfw, // find relation of tablespace in dfw for drop diff --git a/src/jrd/dyn_util.epp b/src/jrd/dyn_util.epp index 4aa1d2569e6..e5797f417c3 100644 --- a/src/jrd/dyn_util.epp +++ b/src/jrd/dyn_util.epp @@ -220,6 +220,19 @@ bool DYN_UTIL_check_unique_name_nothrow(thread_db* tdbb, jrd_tra* transaction, break; + case obj_tablespace: + request.reset(tdbb, drq_l_ts_name, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + TS IN RDB$TABLESPACES + WITH TS.RDB$TABLESPACE_NAME EQ object_name.c_str() + { + *errorCode = 317; + } + END_FOR + + break; + default: fb_assert(false); } From 5747e47441840b374be9d1b905949d820b2e3770 Mon Sep 17 00:00:00 2001 From: Alexander Zhdanov Date: Mon, 28 Oct 2024 12:34:13 +0300 Subject: [PATCH 88/97] Fix the show tablespace TS command error --- src/isql/show.epp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/isql/show.epp b/src/isql/show.epp index 6856200872e..2b5dd59ca3e 100644 --- a/src/isql/show.epp +++ b/src/isql/show.epp @@ -2150,7 +2150,7 @@ processing_state SHOW_metadata(const SCHAR* const* cmd, SCHAR** lcmd) {ShowOptions::schema, "SCHEMAS", 4}, {ShowOptions::map, "MAPPING", 3}, {ShowOptions::publication, "PUBLICATIONS", 3}, - {ShowOptions::tablespace, "TABLESPACES", 0} + {ShowOptions::tablespace, "TABLESPACES", 10} }; const ShowOptions showoptions(options, FB_NELEM(options), ShowOptions::wrong); From 794912a3d2c56c1f840226bb735991ffa527f346 Mon Sep 17 00:00:00 2001 From: Alexander Zhdanov Date: Thu, 19 Sep 2024 17:47:14 +0300 Subject: [PATCH 89/97] Fix inability to create TS after BEGIN BACKUP --- src/jrd/pag.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index c52ac250d3c..75af2696c49 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -2434,6 +2434,16 @@ void PageManager::allocTableSpace(thread_db* tdbb, ULONG tableSpaceID, bool crea if (create) { newPageSpace->file = PIO_create(tdbb, fileName, false, false); + // When opening an existing TS, a pointer to this PageSpace can be added to pageSpaces at the end of the method. + // When creating a new TS, there is a need to add a new PageSpace to pageSpaces earlier. + // Because of the need to update the SCN (if the database SCN is greater than zero) during the creation of new TS pages. + // This early addition of a pointer to PageSpace will not create a race anywhere + // (due to the fact that there is a pointer to an incompletely constructed object for some time), + // because the TS metadata is not yet in the system table and no one can access this TS. + { + WriteLockGuard writeGuard(pageSpacesLock, FB_FUNCTION); + pageSpaces.add(newPageSpace); + } PAG_format_pip(tdbb, *newPageSpace); } else @@ -2445,12 +2455,20 @@ void PageManager::allocTableSpace(thread_db* tdbb, ULONG tableSpaceID, bool crea } catch (...) { + if (create) + { + WriteLockGuard writeGuard(pageSpacesLock, FB_FUNCTION); + pageSpaces.findAndRemove(tableSpaceID); + } delete newPageSpace; throw; } - WriteLockGuard writeGuard(pageSpacesLock, FB_FUNCTION); - pageSpaces.add(newPageSpace); + if (!create) + { + WriteLockGuard writeGuard(pageSpacesLock, FB_FUNCTION); + pageSpaces.add(newPageSpace); + } } } From 47d48a2934b32e3562f908a7bd5590a96ce93072 Mon Sep 17 00:00:00 2001 From: Alexander Zhdanov Date: Mon, 28 Oct 2024 16:29:13 +0300 Subject: [PATCH 90/97] Fix create/alter TS clauses after merge --- src/dsql/parse.y | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 0b969f6b00c..ee5d248bf3a 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -1557,22 +1557,21 @@ create_clause node->createIfNotExistsOnly = $2; $$ = node; } - | unique_opt order_direction INDEX if_not_exists_opt symbol_index_name index_active_opt ON simple_table_name + | unique_opt order_direction INDEX if_not_exists_opt symbol_index_name ON simple_table_name { const auto node = newNode(*$5); - node->active = $6; node->unique = $1; node->descending = $2; node->createIfNotExistsOnly = $4; - node->relation = $8; + node->relation = $7; $$ = node; } - index_definition(static_cast($9)) tablespace_name_clause_opt + index_definition(static_cast($8)) tablespace_name_clause_opt { if ($10) - static_cast($9)->tableSpace = *$11; + static_cast($8)->tableSpace = *$10; - $$ = $9; + $$ = $8; } | FUNCTION if_not_exists_opt function_clause { @@ -1777,12 +1776,6 @@ alter_exception_clause // CREATE INDEX -%type index_active_opt -index_active_opt - : /* nothing */ { $$ = true; } - | index_active { $$ = $1; } - ; - %type unique_opt unique_opt : /* nothing */ { $$ = false; } @@ -4737,7 +4730,8 @@ drop_behaviour %type alter_index_clause alter_index_clause - : symbol_index_name index_active { $$ = newNode(*$1, $2); } + : symbol_index_name ACTIVE { $$ = newNode(*$1, AlterIndexNode::OP_ACTIVE); } + | symbol_index_name INACTIVE { $$ = newNode(*$1, AlterIndexNode::OP_INACTIVE); } | symbol_index_name SET TABLESPACE to_opt symbol_tablespace_name { AlterIndexNode* node = newNode(*$1, AlterIndexNode::OP_SET_TABLESPACE); @@ -4746,12 +4740,6 @@ alter_index_clause } ; -%type index_active -index_active - : ACTIVE { $$ = AlterIndexNode::OP_ACTIVE; } - | INACTIVE { $$ = AlterIndexNode::OP_INACTIVE; } - ; - %type alter_udf_clause alter_udf_clause : symbol_UDF_name entry_op module_op From cabcf28ac95af8a7b1f732476f5534ea84f76c20 Mon Sep 17 00:00:00 2001 From: Alexander Zhdanov Date: Thu, 7 Nov 2024 13:57:34 +0300 Subject: [PATCH 91/97] fix restore TS error: validation error for column RDB$TABLESPACE_ID value null --- src/jrd/fields.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jrd/fields.h b/src/jrd/fields.h index e08302abf0a..a284a96cec4 100644 --- a/src/jrd/fields.h +++ b/src/jrd/fields.h @@ -235,7 +235,7 @@ FIELD(fld_par_workers , nam_par_workers , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_1) - FIELD(fld_ts_id , nam_ts_id , dtype_long , sizeof(SLONG) , 0 , NULL , false , ODS_13_0) + FIELD(fld_ts_id , nam_ts_id , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) FIELD(fld_ts_name , nam_ts_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) FIELD(fld_pp_number , nam_pp_number , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) From ac941024c245b232a0cf35a922ffb59975163b2d Mon Sep 17 00:00:00 2001 From: Alexander Zhdanov Date: Mon, 11 Nov 2024 15:33:34 +0300 Subject: [PATCH 92/97] Increase ODS version for FB 6.0 --- src/burp/OdsDetection.epp | 2 +- src/burp/OdsDetection.h | 1 + src/burp/backup.epp | 6 ++++-- src/burp/burp.h | 2 +- src/burp/restore.epp | 2 +- src/isql/extract.epp | 2 +- src/isql/show.epp | 4 ++-- src/jrd/fields.h | 8 ++++---- src/jrd/relations.h | 30 +++++++++++++++--------------- src/jrd/trig.h | 2 +- 10 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/burp/OdsDetection.epp b/src/burp/OdsDetection.epp index f899606bfe6..2725e42aa22 100644 --- a/src/burp/OdsDetection.epp +++ b/src/burp/OdsDetection.epp @@ -45,7 +45,7 @@ namespace {"RDB$ROLES", 0, DB_VERSION_DDL9}, // IB5 {"RDB$PACKAGES", 0, DB_VERSION_DDL12}, // FB3 {"RDB$PUBLICATIONS", 0, DB_VERSION_DDL13}, // FB4 - {"RDB$TABLESPACES", 0, DB_VERSION_DDL13}, + {"RDB$TABLESPACES", 0, DB_VERSION_DDL14}, // FB6 {0, 0, 0} }; diff --git a/src/burp/OdsDetection.h b/src/burp/OdsDetection.h index 5abaf298520..61f99be03f4 100644 --- a/src/burp/OdsDetection.h +++ b/src/burp/OdsDetection.h @@ -69,6 +69,7 @@ const int DB_VERSION_DDL11_2 = 112; // ods11.2 db, FB2.5 const int DB_VERSION_DDL12 = 120; // ods12.0 db, FB3.0 const int DB_VERSION_DDL13 = 130; // ods13.0 db, FB4.0 const int DB_VERSION_DDL13_1 = 131; // ods13.1 db, FB5.0 +const int DB_VERSION_DDL14 = 140; // ods14.0 db, FB6.0 const int DB_VERSION_OLDEST_SUPPORTED = DB_VERSION_DDL8; // IB4.0 is ods8 diff --git a/src/burp/backup.epp b/src/burp/backup.epp index d2f357decb8..65aa6891d4e 100644 --- a/src/burp/backup.epp +++ b/src/burp/backup.epp @@ -403,7 +403,7 @@ int BACKUP_backup(const TEXT* dbb_file, const TEXT* file_name) write_packages(); } - if (tdgbl->runtimeODS >= DB_VERSION_DDL13) + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) { // Write tablespaces BURP_verbose(411); // msg 411 writing tablespaces @@ -1695,6 +1695,7 @@ void put_index( burp_rel* relation) if (!X.RDB$FOREIGN_KEY.NULL) PUT_TEXT (att_index_foreign_key, X.RDB$FOREIGN_KEY); + // ODS 14 if (!X.RDB$TABLESPACE_NAME.NULL) PUT_TEXT (att_index_tablespace_name, X.RDB$TABLESPACE_NAME); @@ -1775,7 +1776,8 @@ void put_index( burp_rel* relation) if (!X.RDB$FOREIGN_KEY.NULL) PUT_TEXT (att_index_foreign_key, X.RDB$FOREIGN_KEY); - if (!X.RDB$TABLESPACE_NAME.NULL) // For old versions I expect it will be NULL here. Right? + // ODS 14 + if (!X.RDB$TABLESPACE_NAME.NULL) // For old versions I expect it will be NULL here. PUT_TEXT (att_index_tablespace_name, X.RDB$TABLESPACE_NAME); put(tdgbl, att_end); diff --git a/src/burp/burp.h b/src/burp/burp.h index 0566c285332..6af63656198 100644 --- a/src/burp/burp.h +++ b/src/burp/burp.h @@ -209,7 +209,7 @@ Version 11: FB4.0. SQL SECURITY feature, tables RDB$PUBLICATIONS/RDB$PUBLICATION_TABLES. */ -const int ATT_BACKUP_FORMAT = 12; +const int ATT_BACKUP_FORMAT = 13; // max array dimension diff --git a/src/burp/restore.epp b/src/burp/restore.epp index 75d07edb271..644ad516fa3 100644 --- a/src/burp/restore.epp +++ b/src/burp/restore.epp @@ -6927,7 +6927,7 @@ bool get_tablespace(BurpGlobals* tdgbl) SSHORT len; scan_attr_t scan_next_attr; - if (tdgbl->RESTORE_format < 12) // Probably this check is not needed + if (tdgbl->RESTORE_format < 13) // Probably this check is not needed return false; // Firebird::ITransaction* local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans; diff --git a/src/isql/extract.epp b/src/isql/extract.epp index 79ea400f477..bc580de11a2 100644 --- a/src/isql/extract.epp +++ b/src/isql/extract.epp @@ -3631,7 +3631,7 @@ static void list_tablespaces() * **************************************/ - if (isqlGlob.major_ods < ODS_VERSION13) + if (isqlGlob.major_ods < ODS_VERSION14) return; bool first = true; diff --git a/src/isql/show.epp b/src/isql/show.epp index 2b5dd59ca3e..e804fef91d6 100644 --- a/src/isql/show.epp +++ b/src/isql/show.epp @@ -3587,7 +3587,7 @@ static processing_state show_comments(const commentMode showextract, const char* END_ERROR } - if (isqlGlob.major_ods >= ODS_VERSION13) + if (isqlGlob.major_ods >= ODS_VERSION14) { FOR TS IN RDB$TABLESPACES WITH TS.RDB$DESCRIPTION NOT MISSING @@ -5092,7 +5092,7 @@ static processing_state show_tablespaces(const SCHAR* tablespace_name) * Functional description * Show all tablespaces or the named tablespace ************************************/ - if (isqlGlob.major_ods < ODS_VERSION13) + if (isqlGlob.major_ods < ODS_VERSION14) return OBJECT_NOT_FOUND; bool first = true; diff --git a/src/jrd/fields.h b/src/jrd/fields.h index a284a96cec4..5ee6636f139 100644 --- a/src/jrd/fields.h +++ b/src/jrd/fields.h @@ -235,9 +235,9 @@ FIELD(fld_par_workers , nam_par_workers , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_1) - FIELD(fld_ts_id , nam_ts_id , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) - FIELD(fld_ts_name , nam_ts_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_ts_id , nam_ts_id , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_14_0) + FIELD(fld_ts_name , nam_ts_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_14_0) - FIELD(fld_pp_number , nam_pp_number , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) - FIELD(fld_idx_number , nam_idx_number , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_0) + FIELD(fld_pp_number , nam_pp_number , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_14_0) + FIELD(fld_idx_number , nam_idx_number , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_14_0) diff --git a/src/jrd/relations.h b/src/jrd/relations.h index 513efbbff69..eb3fba992c3 100644 --- a/src/jrd/relations.h +++ b/src/jrd/relations.h @@ -99,7 +99,7 @@ RELATION(nam_indices, rel_indices, ODS_8_0, rel_persistent) FIELD(f_idx_exp_blr, nam_exp_blr, fld_value, 1, ODS_8_0) FIELD(f_idx_exp_source, nam_exp_source, fld_source, 1, ODS_8_0) FIELD(f_idx_statistics, nam_statistics, fld_statistics, 1, ODS_8_0) - FIELD(f_idx_ts_name, nam_ts_name, fld_ts_name, 1, ODS_13_0) + FIELD(f_idx_ts_name, nam_ts_name, fld_ts_name, 1, ODS_14_0) FIELD(f_idx_cond_blr, nam_cond_blr, fld_value, 1, ODS_13_1) FIELD(f_idx_cond_source, nam_cond_source, fld_source, 1, ODS_13_1) END_RELATION @@ -127,7 +127,7 @@ RELATION(nam_r_fields, rel_rfr, ODS_8_0, rel_persistent) FIELD(f_rfr_coll_id, nam_collate_id, fld_collate_id, 1, ODS_8_0) FIELD(f_rfr_gen_name, nam_gen_name, fld_gen_name, 1, ODS_12_0) FIELD(f_rfr_identity_type, nam_identity_type, fld_identity_type, 1, ODS_12_0) - FIELD(f_rfr_ts_name, nam_ts_name, fld_ts_name, 1, ODS_13_0) + FIELD(f_rfr_ts_name, nam_ts_name, fld_ts_name, 1, ODS_14_0) END_RELATION // Relation 6 (RDB$RELATIONS) @@ -150,9 +150,9 @@ RELATION(nam_relations, rel_relations, ODS_8_0, rel_persistent) FIELD(f_rel_flags, nam_flags, fld_flag_nullable, 0, ODS_8_0) FIELD(f_rel_type, nam_r_type, fld_r_type, 0, ODS_11_1) FIELD(f_rel_sql_security, nam_sql_security, fld_b_sql_security, 1, ODS_13_0) - FIELD(f_rel_ts_name, nam_ts_name, fld_ts_name, 1, ODS_13_0) - FIELD(f_rel_first_pp, nam_pp_number, fld_pp_number, 0, ODS_13_0) - FIELD(f_rel_idx_root, nam_idx_number, fld_idx_number, 0, ODS_13_0) + FIELD(f_rel_ts_name, nam_ts_name, fld_ts_name, 1, ODS_14_0) + FIELD(f_rel_first_pp, nam_pp_number, fld_pp_number, 0, ODS_14_0) + FIELD(f_rel_idx_root, nam_idx_number, fld_idx_number, 0, ODS_14_0) END_RELATION // Relation 7 (RDB$VIEW_RELATIONS) @@ -765,14 +765,14 @@ RELATION(nam_mon_compiled_statements, rel_mon_compiled_statements, ODS_13_1, rel END_RELATION // Relation 56 (RDB$TABLESPACES) -RELATION(nam_tablespaces, rel_tablespaces, ODS_13_0, rel_persistent) - FIELD(f_ts_id, nam_ts_id, fld_ts_id, 0, ODS_13_0) - FIELD(f_ts_name, nam_ts_name, fld_ts_name, 1, ODS_13_0) - FIELD(f_ts_class, nam_class, fld_class, 1, ODS_13_0) - FIELD(f_ts_sys_flag, nam_sys_flag, fld_flag, 1, ODS_13_0) - FIELD(f_ts_desc, nam_description, fld_description, 1, ODS_13_0) - FIELD(f_ts_owner, nam_owner, fld_user, 1, ODS_13_0) - FIELD(f_ts_file, nam_file_name, fld_file_name, 1, ODS_13_0) - FIELD(f_ts_offline, nam_ts_offline, fld_bool, 1, ODS_13_0) - FIELD(f_ts_readonly, nam_ts_readonly, fld_bool, 1, ODS_13_0) +RELATION(nam_tablespaces, rel_tablespaces, ODS_14_0, rel_persistent) + FIELD(f_ts_id, nam_ts_id, fld_ts_id, 0, ODS_14_0) + FIELD(f_ts_name, nam_ts_name, fld_ts_name, 1, ODS_14_0) + FIELD(f_ts_class, nam_class, fld_class, 1, ODS_14_0) + FIELD(f_ts_sys_flag, nam_sys_flag, fld_flag, 1, ODS_14_0) + FIELD(f_ts_desc, nam_description, fld_description, 1, ODS_14_0) + FIELD(f_ts_owner, nam_owner, fld_user, 1, ODS_14_0) + FIELD(f_ts_file, nam_file_name, fld_file_name, 1, ODS_14_0) + FIELD(f_ts_offline, nam_ts_offline, fld_bool, 1, ODS_14_0) + FIELD(f_ts_readonly, nam_ts_readonly, fld_bool, 1, ODS_14_0) END_RELATION diff --git a/src/jrd/trig.h b/src/jrd/trig.h index 4645501364e..b8750683c77 100644 --- a/src/jrd/trig.h +++ b/src/jrd/trig.h @@ -82,7 +82,7 @@ static const Jrd::gen generators[] = { "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 }, - { "RDB$TABLESPACES", 12, "Tablespace ID", ODS_13_0 }, + { "RDB$TABLESPACES", 12, "Tablespace ID", ODS_14_0 }, { nullptr, 0, nullptr, 0 } }; From 55c7d8186c68d5da783ad716a6153256ac76a218 Mon Sep 17 00:00:00 2001 From: Alexander Zhdanov Date: Mon, 11 Nov 2024 19:39:04 +0300 Subject: [PATCH 93/97] Add small fixes after the TS porting branch update --- builds/install/misc/replication.conf | 20 ++++++++++---------- src/dsql/parse-conflicts.txt | 2 +- src/dsql/parse.y | 25 +++++++++++++++++++------ 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/builds/install/misc/replication.conf b/builds/install/misc/replication.conf index a4daf718a60..f1a1b4e19c6 100644 --- a/builds/install/misc/replication.conf +++ b/builds/install/misc/replication.conf @@ -14,12 +14,12 @@ database # Pattern (regular expression) that defines what tables must be included into # replication. By default, all tables are replicated. # - # include_filter = + # include_filter = # Pattern (regular expression) that defines what tables must be excluded from # replication. By default, all tables are replicated. # - # exclude_filter = + # exclude_filter = # Boolean parameters describing how replication errors must be handled. # @@ -42,20 +42,20 @@ database # Directory to store replication journal files. # - # journal_directory = + # journal_directory = # Prefix for replication journal file names. It will be automatically suffixed # with an ordinal sequential number. If not specified, database filename # (without path) is used as a prefix. # - # journal_file_prefix = + # journal_file_prefix = # Maximum allowed size for a single replication segment. # # journal_segment_size = 16777216 # 16MB # Maximum allowed number of full replication segments. Once this limit is reached, - # the replication process is temporarily delayed to allow the archiving to catch up. + # the replication process is temporarily delayed to allow the archiving to catch up. # If any of the full segments is not archived during one minute, # the replication fails with an error. # @@ -76,7 +76,7 @@ database # Directory to store archived replication segments. # It also defines the $(archpathname) substitution macro (see below). # - # journal_archive_directory = + # journal_archive_directory = # Program (complete command line with arguments) that is executed when some # replication segment gets full and needs archiving. @@ -97,7 +97,7 @@ database # or # Windows: "copy $(pathname) $(archivepathname)" # - # journal_archive_command = + # journal_archive_command = # Timeout, in seconds, to wait until incomplete segment is scheduled for archiving. # It allows to minimize the replication gap if the database is modified rarely. @@ -121,7 +121,7 @@ database # # Multiple entries are allowed (for different synchronous replicas). # - # sync_replica = + # sync_replica = ### REPLICA SIDE SETTINGS @@ -135,13 +135,13 @@ database # Directory to search for the journal files to be replicated. # - # journal_source_directory = + # journal_source_directory = # Filter to limit replication to the particular source database (based on its GUID). # Expected format: "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" # Note that double quotes are mandatory, as well as curly braces. # - # source_guid = + # source_guid = # If enabled, replication.log contains the detailed log of operations performed # by the replication server. Otherwise (by default), only errors and warnings are logged. diff --git a/src/dsql/parse-conflicts.txt b/src/dsql/parse-conflicts.txt index 522dee2236d..5d4c5bae211 100644 --- a/src/dsql/parse-conflicts.txt +++ b/src/dsql/parse-conflicts.txt @@ -1 +1 @@ -101 shift/reduce conflicts, 56 reduce/reduce conflicts. +121 shift/reduce conflicts, 23 reduce/reduce conflicts. diff --git a/src/dsql/parse.y b/src/dsql/parse.y index af3f4600de4..93da09c4da8 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -1557,21 +1557,22 @@ create_clause node->createIfNotExistsOnly = $2; $$ = node; } - | unique_opt order_direction INDEX if_not_exists_opt symbol_index_name ON simple_table_name + | unique_opt order_direction INDEX if_not_exists_opt symbol_index_name index_active_opt ON simple_table_name { const auto node = newNode(*$5); + node->active = $6; node->unique = $1; node->descending = $2; node->createIfNotExistsOnly = $4; - node->relation = $7; + node->relation = $8; $$ = node; } - index_definition(static_cast($8)) tablespace_name_clause_opt + index_definition(static_cast($9)) tablespace_name_clause_opt { - if ($10) - static_cast($8)->tableSpace = *$10; + if ($11) + static_cast($9)->tableSpace = *$11; - $$ = $8; + $$ = $9; } | FUNCTION if_not_exists_opt function_clause { @@ -1777,6 +1778,12 @@ alter_exception_clause // CREATE INDEX +%type index_active_opt +index_active_opt + : /* nothing */ { $$ = true; } + | index_active { $$ = $1; } + ; + %type unique_opt unique_opt : /* nothing */ { $$ = false; } @@ -4748,6 +4755,12 @@ alter_index_clause } ; +%type index_active +index_active + : ACTIVE { $$ = true; } + | INACTIVE { $$ = false; } + ; + %type alter_udf_clause alter_udf_clause : symbol_UDF_name entry_op module_op From 362ee8d9e2275032d43462473599b77a7f4a3811 Mon Sep 17 00:00:00 2001 From: Alexander Zhdanov Date: Tue, 12 Nov 2024 15:38:28 +0300 Subject: [PATCH 94/97] Try to fix windows build for tablespaces --- builds/win32/msvc15/engine_static.vcxproj | 2 ++ builds/win32/msvc15/engine_static.vcxproj.filters | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/builds/win32/msvc15/engine_static.vcxproj b/builds/win32/msvc15/engine_static.vcxproj index 646d4074ee4..2b77348508b 100644 --- a/builds/win32/msvc15/engine_static.vcxproj +++ b/builds/win32/msvc15/engine_static.vcxproj @@ -167,6 +167,7 @@ + @@ -354,6 +355,7 @@ + diff --git a/builds/win32/msvc15/engine_static.vcxproj.filters b/builds/win32/msvc15/engine_static.vcxproj.filters index 8c43e58799d..5abafbb904b 100644 --- a/builds/win32/msvc15/engine_static.vcxproj.filters +++ b/builds/win32/msvc15/engine_static.vcxproj.filters @@ -480,6 +480,9 @@ JRD files + + JRD files + JRD files @@ -1106,6 +1109,9 @@ Header files + + Header files + Header files From 9c87830ebb2a41750fb2f41ea97a852f18ba3338 Mon Sep 17 00:00:00 2001 From: Alexander Zhdanov Date: Tue, 12 Nov 2024 16:29:08 +0300 Subject: [PATCH 95/97] Try to fix macos build for tablespaces --- src/jrd/os/posix/unix.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/jrd/os/posix/unix.cpp b/src/jrd/os/posix/unix.cpp index 2b6b0009db3..d1ccb8c9dc9 100644 --- a/src/jrd/os/posix/unix.cpp +++ b/src/jrd/os/posix/unix.cpp @@ -1196,6 +1196,17 @@ static SLONG pwrite(int fd, SCHAR* buf, SLONG nbytes, SLONG offset) #endif // !(HAVE_PREAD && HAVE_PWRITE) +bool PIO_file_exists(const Firebird::PathName& fileName) +{ + const int fd = openFile(fileName.c_str(), false, false, true); + if (fd == -1) + return false; + + close(fd); + return true; +} + + #ifdef SUPPORT_RAW_DEVICES int PIO_unlink(const PathName& file_name) { @@ -1235,17 +1246,6 @@ bool PIO_on_raw_device(const PathName& file_name) } -bool PIO_file_exists(const Firebird::PathName& fileName) -{ - const int fd = openFile(fileName.c_str(), false, false, true); - if (fd == -1) - return false; - - close(fd); - return true; -} - - static bool raw_devices_validate_database(int desc, const PathName& file_name) { /************************************** From c94f003f4fd29deca62861d2312ea10add287168 Mon Sep 17 00:00:00 2001 From: Alexander Zhdanov Date: Thu, 20 Mar 2025 18:36:52 +0300 Subject: [PATCH 96/97] Add readme.tablespaces --- doc/README.tablespaces | 187 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 doc/README.tablespaces diff --git a/doc/README.tablespaces b/doc/README.tablespaces new file mode 100644 index 00000000000..1dcc5cb8139 --- /dev/null +++ b/doc/README.tablespaces @@ -0,0 +1,187 @@ +----------------- +TABLESPACES +----------------- + + Goals: + Tablespaces allow you to organize the logic of placing database object files in the file system. It allows: + 1) Extend the current limits on database size + 2) Keep non active parts of a database on slow disks (having big volume) + 3) Split indices from the database + +----------------- +SYNTAX +----------------- + + 1. TABLESPACE + CREATE TABLESPACE [IF NOT EXISTS] FILE '/path/to/file' + ALTER TABLESPACE SET FILE [TO] '/path/to/file' + You can specify either an absolute path or a relative path (relative to the database file) + + DROP TABLESPACE [IF EXISTS] + The development of the INCLUDING CONTENTS option has been postponed. + + For an existing tablespace, it is possible to add a comment using the COMMENT ON statement. + COMMENT ON TABLESPACE IS {'text' | NULL} + + 2. TABLE + "PRIMARY" keyword + The PRIMARY keyword can be used as a tablespace name if you want to reference the main database file. + + CREATE TABLE ... + [[IN] TABLESPACE { | PRIMARY}] + + It is also possible to specify a tablespace when creating a column or table constraint (unique, primary key, references): + + ::= ... UNIQUE ... [[IN] TABLESPACE { | PRIMARY}] | PRIMARY ... [[IN] TABLESPACE { | PRIMARY}] | REFERENCES ... [[IN] TABLESPACE { | PRIMARY}] ... + + ALTER TABLE SET TABLESPACE [TO] { | PRIMARY} + + The table data will be moved to the specified tablespace or to the main database. + + 3. INDEX + CREATE INDEX ... + [[IN] TABLESPACE { | PRIMARY}] + + By default, table indexes are created in the same tablespace as the table itself. + + ALTER INDEX ... + [SET TABLESPACE [TO] { | PRIMARY}] + + The index data will be moved to the specified tablespace or to the main database. + +----------------- +SECURITY +----------------- + + Only administrators and users with the “CREATE TABLESPACE” privilege can create tablespaces (CREATE TABLESPACE). + Only administrators and users with the “ALTER ANY TABLESPACE” privilege can change tablespaces file paths (ALTER TABLESPACE SET FILE [TO] ). + Only administrators, domain owners, or users with the ALTER ANY TABLESPACE privilege can comment (COMMENT ON) tablespaces. + Only administrators and users with the “DROP ANY TABLESPACE” privilege can delete tablespaces (DROP TABLESPACE). + +----------------- +ODS CHANGES +----------------- + + A new table RDB$TABLESPACES: + RDB$TABLESPACE_ID - INTEGER # internally it will be pagespaceid. + RDB$TABLESPACE_NAME - CHAR (63) # name of a tablespace + RDB$SECURITY_CLASS - CHAR (63) # security class for tablespace + RDB$SYSTEM_FLAG - SMALLINT # reserved for future + RDB$DESCRIPTION - BLOB TEXT # description of a tablespace + RDB$OWNER_NAME - CHAR (63) # owner of a tablespace + RDB$FILE_NAME - VARCHAR (255) # file where a tablespace data are located + RDB$OFFLINE - BOOLEAN # reserved for future + RDB$READ_ONLY - BOOLEAN # reserved for future + + New field in RDB$INDICES: + RDB$TABLESPACE_NAME - CHAR (63) + + New field in RDB$RELATION_FIELDS: + RDB$TABLESPACE_NAME - CHAR (63) + + New fields in RDB$RELATIONS: + RDB$TABLESPACE_NAME - CHAR (63) + RDB$POINTER_PAGE - INTEGER # a number of the first pointer page of a relation + RDB$ROOT_PAGE - INTEGER # a number of the root page of a relation + + These fields are necessary for reliable implementation of moving data pages to another tablespace. + It's a dfw operation with EX database lock. So there are no concurrent changes. + 1) copy all data pages + 2) switch RDB$POINTER_PAGE and RDB$ROOT_PAGE transactionally + 3) Rebuild RDB$PAGES + 4) clear old data pages (as post-dfw operation) + It can be interrupted but not resumed. + +----------------- +UTILITIES +----------------- + + 1. Logical backup + gbak -b works as usual for now. It gets data from a database transparently working with tablespaces. + + 2. Logical restore + gbak -c + + -ts_map[ping] + option is required for correct database restore if its backup contains tables or indexes saved in tablespaces. + To do this, specify the path to file, which consists of lines with two values: the first column is the name of the tablespace, + the second column is the new location of the tablespace. You can specify either an absolute path or a relative path. + TS1 /path/to/tablespace1.dat + TS2 /path/to/tablespace2.dat + + -ts + allows you to specify the path for the tablespace. You can specify either an absolute path or a relative path. + The option can be used as many times as required. It can also be used together with -ts_map. + + -ts_orig[inal_paths] + To restore tablespaces to the original paths they were on when the backup was created. + It is still possible to override paths for some tablespaces using the -ts and -ts_map options. + This is an explicit option, not a default action. + The option does not overwrite existing files. + + If you do not specify the above options, when restoring a database that has tablespaces, + an error about the inability to determine the path to restore tablespaces will occur. + + 3. Show + SHOW {TABLESPACES | TABLESPACE } + Displays a list of all tablespaces names in alphabetical order or information about the specified tablespace. + + 4. Replication + There is an apply_tablespaces_ddl parameter for replication. + If this parameter is disabled, tablespaces-related DDL statements and CREATE/ALTER TABLE/INDEX clauses will not be applied to the replica. + This is used if the replica has its own set of tablespaces or none at all. + +----------------- +DETAILS +----------------- + + pag_header in every tablespace is reserved and may be replaced by a + new page type. + pag_scns and pag_pip are located in every tablespace. + pag_root is located in the tablespace where a table is located. + + An algorithm for moving data to another tablespace: + First, you have to move all the pages to another tablespace: + The main steps are: + - allocate necessary number of pointer pages by extents. + - allocate the rest of pointer pages by pages. + - walking through PPs allocate DPs by pages or extents. + - fix every PP by correcting DP numbers and ppg_next pointer and build a map + - walking through the map and copy every DP to the new one by fixing + b_page and f_page numbers. + At the end of work replace records in RDB$PAGES. + + Then you need to update first pointer page and root page in RDB$RELATIONS transactionally. + + RDB$POINTER_PAGE and RDB$ROOT_PAGE are updated in a transaction because: + Moving table pages to another tablespace occurs in DFW. In case of failure, we can get the old values of RDB$POINTER_PAGE and RDB$ROOT_PAGE fields. + + Then we delete all from RDB$PAGES about the relation to have an ability to understand that we need to restore pages + if transaction won't be able to finish successfully. + + Then post commit work will clean up old pages. It must be done exactly after commit. + If crash is happend the metadata will point to the old page space and new ones will be garbage. Right after commit old pages will be garbage. + + +----------------- +CONSTRAINTS +----------------- + + It's possible to create up to 253 tablespaces. + Operators to move an index or table to a tablespace require an exclusive database lock. + +----------------- +PLANS +----------------- + + 1. Add the main database file to the RDB$TABLESPACES table. Designate it as PRIMARY. + The RDB$TABLESPACE_NAME field contained in the system tables of tables, indexes will have the value “PRIMARY” instead of NULL. + 2. Add an option to transfer tablespace to the main DB file when restoring. + 3. TEMPORARY predefined tablespaces. + 4. Grouping page counters by tablespace (For output in trace and monitoring). + 5. New header page for tablespaces + 6. NBACKUP support for tablespaces + 7. Moving blobs to separate tablespaces (The RDB$TABLESPACE_NAME column in RDB$RELATION_FIELDS is reserved for this purpose). + 8. Possibility to introduce UNDO tablespace in future versions + 9. The ability to set default tablespaces for tables, indexes and BLOBs at the database or schema level. + From c84ca58ea1969a8ea35c62ceca537883655ebbeb Mon Sep 17 00:00:00 2001 From: Alexander Zhdanov Date: Thu, 20 Mar 2025 19:09:37 +0300 Subject: [PATCH 97/97] Add the ability to move the contents of a tablespace to PRIMARY during restore --- doc/README.tablespaces | 18 +++-- src/burp/restore.epp | 177 +++++++++++++++++++++++++++-------------- 2 files changed, 129 insertions(+), 66 deletions(-) diff --git a/doc/README.tablespaces b/doc/README.tablespaces index 1dcc5cb8139..2a23382ae24 100644 --- a/doc/README.tablespaces +++ b/doc/README.tablespaces @@ -112,6 +112,9 @@ UTILITIES -ts allows you to specify the path for the tablespace. You can specify either an absolute path or a relative path. The option can be used as many times as required. It can also be used together with -ts_map. + + If you specify “PRIMARY” instead of the path for the new tablespace, the contents of the tablespace will be moved to the PRIMARY tablespace. + The tablespace will not be created. -ts_orig[inal_paths] To restore tablespaces to the original paths they were on when the backup was created. @@ -176,12 +179,11 @@ PLANS 1. Add the main database file to the RDB$TABLESPACES table. Designate it as PRIMARY. The RDB$TABLESPACE_NAME field contained in the system tables of tables, indexes will have the value “PRIMARY” instead of NULL. - 2. Add an option to transfer tablespace to the main DB file when restoring. - 3. TEMPORARY predefined tablespaces. - 4. Grouping page counters by tablespace (For output in trace and monitoring). - 5. New header page for tablespaces - 6. NBACKUP support for tablespaces - 7. Moving blobs to separate tablespaces (The RDB$TABLESPACE_NAME column in RDB$RELATION_FIELDS is reserved for this purpose). - 8. Possibility to introduce UNDO tablespace in future versions - 9. The ability to set default tablespaces for tables, indexes and BLOBs at the database or schema level. + 2. TEMPORARY predefined tablespaces. + 3. Grouping page counters by tablespace (For output in trace and monitoring). + 4. New header page for tablespaces + 5. NBACKUP support for tablespaces + 6. Moving blobs to separate tablespaces (The RDB$TABLESPACE_NAME column in RDB$RELATION_FIELDS is reserved for this purpose). + 7. Possibility to introduce UNDO tablespace in future versions + 8. The ability to set default tablespaces for tables, indexes and BLOBs at the database or schema level. diff --git a/src/burp/restore.epp b/src/burp/restore.epp index 644ad516fa3..9192f69719e 100644 --- a/src/burp/restore.epp +++ b/src/burp/restore.epp @@ -3939,9 +3939,12 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation) // ODS 14 case att_field_tablespace_name: + { GET_TEXT(X.RDB$TABLESPACE_NAME); - X.RDB$TABLESPACE_NAME.NULL = FALSE; + const auto str = tdgbl->tablespace_mapping.get(X.RDB$TABLESPACE_NAME); + X.RDB$TABLESPACE_NAME.NULL = str ? str->equals(PRIMARY_TABLESPACE_NAME) : FALSE; break; + } default: bad_attribute(scan_next_attr, attribute, 84); @@ -6662,9 +6665,12 @@ bool get_index(BurpGlobals* tdgbl, const burp_rel* relation) // ODS 14 case att_index_tablespace_name: + { GET_TEXT(X.RDB$TABLESPACE_NAME); - X.RDB$TABLESPACE_NAME.NULL = FALSE; + const auto str = tdgbl->tablespace_mapping.get(X.RDB$TABLESPACE_NAME); + X.RDB$TABLESPACE_NAME.NULL = str ? str->equals(PRIMARY_TABLESPACE_NAME) : FALSE; break; + } default: bad_attribute(scan_next_attr, attribute, 93); @@ -6922,77 +6928,129 @@ bool get_tablespace(BurpGlobals* tdgbl) * Reconstruct a tablespace. * **************************************/ + if (tdgbl->RESTORE_format < 13) // Probably this check is not needed + return false; + + ISC_QUAD tablespace_desc = fbBlobNull; + bool tablespace_desc_null = true; + GDS_NAME owner_name; + SLONG sys_flag = fb_sysflag_user; + FB_BOOLEAN offline = FB_FALSE; + FB_BOOLEAN read_only = FB_FALSE; + + BASED_ON RDB$TABLESPACES.RDB$TABLESPACE_NAME tablespace_name; + tablespace_name[0] = '\0'; + + BASED_ON RDB$TABLESPACES.RDB$SECURITY_CLASS security_class; + security_class[0] = '\0'; + bool security_class_null = true; + + BASED ON RDB$TABLESPACES.RDB$FILE_NAME tablespace_file; + tablespace_file[0] = '\0'; + att_type attribute; - TEXT temp[GDS_NAME_LEN]; - SSHORT len; scan_attr_t scan_next_attr; - if (tdgbl->RESTORE_format < 13) // Probably this check is not needed - return false; + bool moveToPrimary = false; + + skip_init(&scan_next_attr); + while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end) + { + switch (attribute) + { + case att_ts_name: + { + TEXT temp[GDS_NAME_LEN]; + SSHORT len = GET_TEXT(tablespace_name); + MISC_terminate(tablespace_name, temp, len, sizeof(temp)); + + const auto str = tdgbl->tablespace_mapping.get(tablespace_name); + if (str && str->equals(PRIMARY_TABLESPACE_NAME)) + moveToPrimary = true; // Move the contents of this TS to PRIMARY + else + BURP_verbose(1019, temp); // msg 1019 restoring tablespace %s + break; + } + case att_ts_security_class: + if (moveToPrimary) + eat_text(tdgbl); + else + { + GET_TEXT(security_class); + fix_security_class_name(tdgbl, security_class, false); + } + break; + + case att_ts_description: + if (moveToPrimary) + eat_blob(tdgbl); + else + { + tablespace_desc_null = false; + get_source_blob(tdgbl, tablespace_desc, true); + } + break; + + case att_ts_owner_name: + if (moveToPrimary) + eat_text(tdgbl); + else + GET_TEXT(owner_name); + break; + + case att_ts_file: + if (moveToPrimary) + eat_text(tdgbl); + else + GET_TEXT(tablespace_file); + break; + + case att_ts_offline: + offline = get_boolean(tdgbl, false); + break; + + case att_ts_readonly: + read_only = get_boolean(tdgbl, false); + break; + + default: + bad_attribute(scan_next_attr, attribute, 1020); // msg 1020 tablespace + break; + } + } + + // Do not add a tablespace if its contents are moved to the PRIMARY when restoring it + if (moveToPrimary) + return true; // Firebird::ITransaction* local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans; STORE (REQUEST_HANDLE tdgbl->handles_get_ts_req_handle1) X IN RDB$TABLESPACES { - X.RDB$TABLESPACE_NAME.NULL = TRUE; - X.RDB$SECURITY_CLASS.NULL = TRUE; - X.RDB$SYSTEM_FLAG = 0; - X.RDB$SYSTEM_FLAG.NULL = FALSE; - X.RDB$DESCRIPTION.NULL = TRUE; - X.RDB$OWNER_NAME.NULL = TRUE; - X.RDB$FILE_NAME.NULL = TRUE; - X.RDB$OFFLINE.NULL = TRUE; - X.RDB$READ_ONLY.NULL = TRUE; + X.RDB$TABLESPACE_NAME.NULL = FALSE; + strcpy(X.RDB$TABLESPACE_NAME, tablespace_name); - skip_init(&scan_next_attr); - while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end) - { - switch (attribute) - { - case att_ts_name: - len = GET_TEXT(X.RDB$TABLESPACE_NAME); - X.RDB$TABLESPACE_NAME.NULL = FALSE; - MISC_terminate(X.RDB$TABLESPACE_NAME, temp, len, sizeof(temp)); - BURP_verbose(413, temp); // msg 413 restoring tablespace %s - break; - - case att_ts_security_class: - GET_TEXT(X.RDB$SECURITY_CLASS); - fix_security_class_name(tdgbl, X.RDB$SECURITY_CLASS, false); - X.RDB$SECURITY_CLASS.NULL = FALSE; - break; + X.RDB$SECURITY_CLASS.NULL = security_class_null; + strcpy(X.RDB$SECURITY_CLASS, security_class); - case att_ts_description: - get_source_blob(tdgbl, X.RDB$DESCRIPTION, true); - X.RDB$DESCRIPTION.NULL = FALSE; - break; + X.RDB$SYSTEM_FLAG.NULL = FALSE; + X.RDB$SYSTEM_FLAG = sys_flag; - case att_ts_owner_name: - GET_TEXT(X.RDB$OWNER_NAME); - X.RDB$OWNER_NAME.NULL = FALSE; - break; + X.RDB$DESCRIPTION.NULL = tablespace_desc_null; + X.RDB$DESCRIPTION = tablespace_desc; - case att_ts_file: - GET_TEXT(X.RDB$FILE_NAME); - X.RDB$FILE_NAME.NULL = FALSE; - break; + X.RDB$OWNER_NAME.NULL = FALSE; + strcpy(X.RDB$OWNER_NAME, owner_name); - case att_ts_offline: - X.RDB$OFFLINE = (USHORT) get_boolean(tdgbl, false); - X.RDB$OFFLINE.NULL = FALSE; - break; + X.RDB$FILE_NAME.NULL = FALSE; + strcpy(X.RDB$FILE_NAME, tablespace_file); - case att_ts_readonly: - X.RDB$READ_ONLY = (USHORT) get_boolean(tdgbl, false); - X.RDB$READ_ONLY.NULL = FALSE; - break; + X.RDB$OFFLINE.NULL = FALSE; + X.RDB$OFFLINE = (USHORT) offline; - default: - bad_attribute(scan_next_attr, attribute, 414); // msg 414 tablespace - break; - } - } + X.RDB$READ_ONLY.NULL = FALSE; + X.RDB$READ_ONLY = (USHORT) read_only; Firebird::string newFile; if (tdgbl->tablespace_mapping.get(X.RDB$TABLESPACE_NAME, newFile)) @@ -8048,9 +8106,12 @@ bool get_relation(BurpGlobals* tdgbl, Coordinator* coord, RestoreRelationTask* t break; case att_relation_tablespace_name: - tableSpaceNull = false; + { GET_TEXT(tableSpace); + const auto str = tdgbl->tablespace_mapping.get(tableSpace); + tableSpaceNull = str ? str->equals(PRIMARY_TABLESPACE_NAME) : FALSE; break; + } default: bad_attribute(scan_next_attr, attribute, 111);