From c356791b02cdae178d89a4b2c602a0e2fd256e41 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Mon, 24 Sep 2018 13:16:38 +0300 Subject: [PATCH] Fixed CORE-5758: Database is corrupted when conflicting "starting at page" values is specified for secondary files (#147) * Fixed issue: Database is corrupted when conflicting "starting at page" values is specified for secondary files * Raise error when conflicting "starting at page" values is specified for secondary database files --- lang_helpers/gds_codes.ftn | 2 ++ lang_helpers/gds_codes.pas | 2 ++ 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/dfw.epp | 37 ++++++++++++++++++++++--------------- src/msgs/facilities2.sql | 2 +- src/msgs/messages2.sql | 1 + src/msgs/system_errors2.sql | 1 + 11 files changed, 37 insertions(+), 18 deletions(-) diff --git a/lang_helpers/gds_codes.ftn b/lang_helpers/gds_codes.ftn index 93d8d2f144..7268453c4f 100644 --- a/lang_helpers/gds_codes.ftn +++ b/lang_helpers/gds_codes.ftn @@ -1834,6 +1834,8 @@ C -- PARAMETER (GDS__plugin_name = 335545210) INTEGER*4 GDS__parameter_name PARAMETER (GDS__parameter_name = 335545211) + INTEGER*4 GDS__file_starting_page_err + PARAMETER (GDS__file_starting_page_err = 335545212) 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 f065d4dc34..6a38cc700c 100644 --- a/lang_helpers/gds_codes.pas +++ b/lang_helpers/gds_codes.pas @@ -1829,6 +1829,8 @@ const gds_plugin_name = 335545210; isc_parameter_name = 335545211; gds_parameter_name = 335545211; + isc_file_starting_page_err = 335545212; + gds_file_starting_page_err = 335545212; isc_gfix_db_name = 335740929; gds_gfix_db_name = 335740929; isc_gfix_invalid_sw = 335740930; diff --git a/src/include/gen/codetext.h b/src/include/gen/codetext.h index deed5760b3..15ab85256f 100644 --- a/src/include/gen/codetext.h +++ b/src/include/gen/codetext.h @@ -913,6 +913,7 @@ static const struct { {"ses_reset_tran_rollback", 335545209}, {"plugin_name", 335545210}, {"parameter_name", 335545211}, + {"file_starting_page_err", 335545212}, {"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 c3f004d5a0..5ffa687ab9 100644 --- a/src/include/gen/iberror.h +++ b/src/include/gen/iberror.h @@ -947,6 +947,7 @@ const ISC_STATUS isc_ses_reset_warn = 335545208L; const ISC_STATUS isc_ses_reset_tran_rollback = 335545209L; const ISC_STATUS isc_plugin_name = 335545210L; const ISC_STATUS isc_parameter_name = 335545211L; +const ISC_STATUS isc_file_starting_page_err = 335545212L; const ISC_STATUS isc_gfix_db_name = 335740929L; const ISC_STATUS isc_gfix_invalid_sw = 335740930L; const ISC_STATUS isc_gfix_incmp_sw = 335740932L; @@ -1421,7 +1422,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 = 1365; +const ISC_STATUS isc_err_max = 1366; #else /* c definitions */ @@ -2338,6 +2339,7 @@ const ISC_STATUS isc_err_max = 1365; #define isc_ses_reset_tran_rollback 335545209L #define isc_plugin_name 335545210L #define isc_parameter_name 335545211L +#define isc_file_starting_page_err 335545212L #define isc_gfix_db_name 335740929L #define isc_gfix_invalid_sw 335740930L #define isc_gfix_incmp_sw 335740932L @@ -2812,7 +2814,7 @@ const ISC_STATUS isc_err_max = 1365; #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 1365 +#define isc_err_max 1366 #endif diff --git a/src/include/gen/msgs.h b/src/include/gen/msgs.h index fa91c6b2e4..3140fc9e23 100644 --- a/src/include/gen/msgs.h +++ b/src/include/gen/msgs.h @@ -916,6 +916,7 @@ Data source : @4"}, /* eds_statement */ {335545209, "Transaction is rolled back due to session reset, all changes are lost"}, /* ses_reset_tran_rollback */ {335545210, "Plugin @1:"}, /* plugin_name */ {335545211, "PARAMETER @1"}, /* parameter_name */ + {335545212, "Starting page number for file @1 must be @2 or greater"}, /* file_starting_page_err */ {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 b6c0ef540d..792f2a72b5 100644 --- a/src/include/gen/sql_code.h +++ b/src/include/gen/sql_code.h @@ -912,6 +912,7 @@ static const struct { {335545209, -901}, /* 889 ses_reset_tran_rollback */ {335545210, -901}, /* 890 plugin_name */ {335545211, -901}, /* 891 parameter_name */ + {335545212, -901}, /* 892 file_starting_page_err */ {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 ebdd29e3d2..1e12fabdb3 100644 --- a/src/include/gen/sql_state.h +++ b/src/include/gen/sql_state.h @@ -912,6 +912,7 @@ static const struct { {335545209, "01102"}, // 889 ses_reset_tran_rollback {335545210, "00000"}, // 890 plugin_name {335545211, "42000"}, // 891 parameter_name + {335545212, "HY000"}, // 892 file_starting_page_err {335740929, "00000"}, // 1 gfix_db_name {335740930, "00000"}, // 2 gfix_invalid_sw {335740932, "00000"}, // 4 gfix_incmp_sw diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 69f03c17d9..e3fc632bba 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -1841,7 +1841,7 @@ static bool add_file(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* * **************************************/ USHORT section, shadow_number; - SLONG start, max; + SLONG start, min_start; SET_TDBB(tdbb); Database* const dbb = tdbb->getDatabase(); @@ -1863,7 +1863,7 @@ static bool add_file(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* case 4: CCH_flush(tdbb, FLUSH_FINI, 0); - max = PageSpace::maxAlloc(dbb) + 1; + start = PageSpace::maxAlloc(dbb) + 1; AutoRequest handle; AutoRequest handle2; @@ -1891,24 +1891,31 @@ static bool add_file(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* END_MODIFY } - // If there is no starting position specified, or if it is - // too low a value, make a stab at assigning one based on - // the indicated preference for the previous file length. - - if ((start = X.RDB$FILE_START) < max) + // Check the previous file length + FOR(REQUEST_HANDLE handle2 TRANSACTION_HANDLE transaction) + FIRST 1 Y IN RDB$FILES + WITH Y.RDB$SHADOW_NUMBER EQ X.RDB$SHADOW_NUMBER + AND Y.RDB$FILE_SEQUENCE NOT MISSING + SORTED BY DESCENDING Y.RDB$FILE_SEQUENCE { - FOR(REQUEST_HANDLE handle2 TRANSACTION_HANDLE transaction) - FIRST 1 Y IN RDB$FILES - WITH Y.RDB$SHADOW_NUMBER EQ X.RDB$SHADOW_NUMBER - AND Y.RDB$FILE_SEQUENCE NOT MISSING - SORTED BY DESCENDING Y.RDB$FILE_SEQUENCE + if (!Y.RDB$FILE_START.NULL && !Y.RDB$FILE_LENGTH.NULL) { - start = Y.RDB$FILE_START + Y.RDB$FILE_LENGTH; + min_start = Y.RDB$FILE_START + (Y.RDB$FILE_LENGTH ? Y.RDB$FILE_LENGTH : 1); + start = MAX(min_start, start); } - END_FOR + } + END_FOR + + // If there is no starting position specified, or if it is + // too low a value, raise the error. + if (X.RDB$FILE_START < start) + { + ERR_post(Arg::Gds(isc_file_starting_page_err) << + Arg::Str(X.RDB$FILE_NAME) << Arg::Num(start)); } - start = MAX(max, start); + start = X.RDB$FILE_START; + shadow_number = X.RDB$SHADOW_NUMBER; if ((shadow_number && (section = SDW_add_file(tdbb, X.RDB$FILE_NAME, start, shadow_number))) || diff --git a/src/msgs/facilities2.sql b/src/msgs/facilities2.sql index 4096f25721..f7a61fb410 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 (?, ?, ?, ?); -- -('2018-08-31 12:44:00', 'JRD', 0, 892) +('2018-08-31 12:44:00', 'JRD', 0, 893) ('2015-03-17 18:33:00', 'QLI', 1, 533) ('2015-01-07 18:01:51', 'GFIX', 3, 134) ('1996-11-07 13:39:40', 'GPRE', 4, 1) diff --git a/src/msgs/messages2.sql b/src/msgs/messages2.sql index aa0a300712..7dc77e640c 100644 --- a/src/msgs/messages2.sql +++ b/src/msgs/messages2.sql @@ -999,6 +999,7 @@ Data source : @4', NULL, NULL) ('ses_reset_tran_rollback', NULL, 'Attachment.cpp', NULL, 0, 889, NULL, 'Transaction is rolled back due to session reset, all changes are lost', NULL, NULL); ('plugin_name', NULL, 'CryptoManager.cpp', NULL, 0, 890, NULL, 'Plugin @1:', NULL, NULL); ('parameter_name', 'ProcedureManager::checkDependencies', 'dfw.e', NULL, 0, 891, NULL, 'PARAMETER @1', NULL, NULL); +('file_starting_page_err', 'add_file', 'dfw.epp', NULL, 0, 892, NULL, 'Starting page number for file @1 must be @2 or greater', 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 8f4145dd6c..0340005b84 100644 --- a/src/msgs/system_errors2.sql +++ b/src/msgs/system_errors2.sql @@ -898,6 +898,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA (-901, '01', '102', 0, 889, 'ses_reset_tran_rollback', NULL, 'WARNING') (-901, '00', '000', 0, 890, 'plugin_name', NULL, NULL) (-901, '42', '000', 0, 891, 'parameter_name', NULL, NULL) +(-901, 'HY', '000', 0, 892, 'file_starting_page_err', NULL, NULL) -- GFIX (-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL) (-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)