From 8a8d7787d0061da64b7a45e5735c68df47f29531 Mon Sep 17 00:00:00 2001 From: Dimitry Sibiryakov Date: Thu, 31 Oct 2019 10:59:37 +0100 Subject: [PATCH] CORE-5538 implementation (#229) * CORE-5538 implementation --- doc/README.gbak | 19 ++++++++ src/burp/burp.cpp | 66 ++++++++++++++++++++++++-- src/burp/burp.h | 2 + src/burp/burpswi.h | 4 ++ src/common/classes/ClumpletReader.cpp | 1 + src/include/firebird/impl/consts_pub.h | 2 + src/msgs/facilities2.sql | 2 +- src/msgs/messages2.sql | 3 ++ src/utilities/fbsvcmgr/fbsvcmgr.cpp | 2 + 9 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 doc/README.gbak diff --git a/doc/README.gbak b/doc/README.gbak new file mode 100644 index 0000000000..678880d12d --- /dev/null +++ b/doc/README.gbak @@ -0,0 +1,19 @@ +In Firebird 4.0 a new switch was added to gbak: -INCLUDE(_DATA). + +It takes one parameter which is "similar like" pattern matching +table names in a case-insensitive way. + +This switch, if provided, limit tables for which data is stored +or restored in/from backup file. + +Interaction between -INCLUDE_DATA and -SKIP_DATA switches for +a table is following: ++--------------------------------------------------+ +| | INCLUDE_DATA | +| |--------------------------------------| +| SKIP_DATA | NOT SET | MATCH | NOT MATCH | ++-----------+------------+------------+------------+ +| NOT SET | included | included | excluded | +| MATCH | excluded | excluded | excluded | +| NOT MATCH | excluded | included | excluded | ++-----------+------------+------------+------------+ diff --git a/src/burp/burp.cpp b/src/burp/burp.cpp index 2b863a9b9e..c8bc046f6e 100644 --- a/src/burp/burp.cpp +++ b/src/burp/burp.cpp @@ -703,6 +703,14 @@ int gbak(Firebird::UtilSvc* uSvc) } tdgbl->setupSkipData(argv[itr]); break; + case IN_SW_BURP_INCLUDE_DATA: + if (++itr >= argc) + { + BURP_error(389, true); + // missing regular expression to include tables + } + tdgbl->setupIncludeData(argv[itr]); + break; case IN_SW_BURP_ROLE: if (++itr >= argc) { @@ -2540,6 +2548,38 @@ void BurpGlobals::setupSkipData(const Firebird::string& regexp) } } +void BurpGlobals::setupIncludeData(const Firebird::string& regexp) +{ + if (includeDataMatcher) + { + BURP_error(390, true); + // msg 390 regular expression to include tables was already set + } + + // Compile include relation expressions + try + { + if (regexp.hasData()) + { + Firebird::string filter(regexp); + if (!uSvc->utf8FileNames()) + ISC_systemToUtf8(filter); + + BurpGlobals* tdgbl = BurpGlobals::getSpecific(); + + includeDataMatcher.reset(FB_NEW_POOL(tdgbl->getPool()) Firebird::SimilarToRegex( + tdgbl->getPool(), Firebird::SimilarToFlag::CASE_INSENSITIVE, + filter.c_str(), filter.length(), + "\\", 1)); + } + } + catch (const Firebird::Exception&) + { + Firebird::fatal_exception::raiseFmt( + "error while compiling regular expression \"%s\"", regexp.c_str()); + } +} + Firebird::string BurpGlobals::toSystem(const Firebird::PathName& from) { Firebird::string to = from.ToString(); @@ -2548,15 +2588,35 @@ Firebird::string BurpGlobals::toSystem(const Firebird::PathName& from) return to; } +namespace // for local symbols +{ + enum Pattern { NOT_SET = 0, MATCH = 1, NOT_MATCH = 2 }; + + Pattern checkPattern(Firebird::AutoPtr& matcher, + const char* name) + { + if (!matcher) + return NOT_SET; + + return matcher->matches(name, strlen(name))? MATCH : NOT_MATCH; + } +} + bool BurpGlobals::skipRelation(const char* name) { if (gbl_sw_meta) return true; - if (!skipDataMatcher) - return false; + // Fine-grained table controlling cases when data must be skipped for a table + static const bool result[3][3] = { + // Include filter + // NS M NM S + { false, false, true}, // NS k + { true, true, true}, // M i + { false, false, true} // NM p + }; - return skipDataMatcher->matches(name, strlen(name)); + return result[checkPattern(skipDataMatcher, name)][checkPattern(includeDataMatcher, name)]; } void BurpGlobals::read_stats(SINT64* stats) diff --git a/src/burp/burp.h b/src/burp/burp.h index 53947dde1b..c4eb6e18b9 100644 --- a/src/burp/burp.h +++ b/src/burp/burp.h @@ -1139,6 +1139,7 @@ public: ThreadData::restoreSpecific(); } void setupSkipData(const Firebird::string& regexp); + void setupIncludeData(const Firebird::string& regexp); bool skipRelation(const char* name); char veryEnd; @@ -1155,6 +1156,7 @@ public: bool firstMap; // this is the first time we entered get_mapping() bool stdIoMode; // stdin or stdout is used as backup file Firebird::AutoPtr skipDataMatcher; + Firebird::AutoPtr includeDataMatcher; public: Firebird::string toSystem(const Firebird::PathName& from); diff --git a/src/burp/burpswi.h b/src/burp/burpswi.h index 2cfc6e7758..97ba37fac4 100644 --- a/src/burp/burpswi.h +++ b/src/burp/burpswi.h @@ -96,6 +96,8 @@ const int IN_SW_BURP_KEYHOLD = 49; // name of KeyHolder plugin 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 + /**************************************************************************/ static const char* const BURP_SW_MODE_RO = "READ_ONLY"; @@ -175,6 +177,8 @@ static const Switches::in_sw_tab_t reference_burp_in_sw_table[] = // msg 277: @1SE(RVICE) use services manager {IN_SW_BURP_SKIP_DATA, isc_spb_res_skip_data, "SKIP_DATA", 0, 0, 0, false, false, 355, 6, NULL, boGeneral}, // msg 355: @1SKIP_DATA skip data for table + {IN_SW_BURP_INCLUDE_DATA, isc_spb_res_include_data, "INCLUDE_DATA", 0, 0, 0, false, false, 388, 7, NULL, boGeneral}, + // msg 388: @1INCLUDE(_DATA) backup data of table(s) {IN_SW_BURP_STATS, isc_spb_bkp_stat, "STATISTICS", 0, 0, 0, false, false, 361, 2, NULL, boGeneral}, // msg 361: @1ST(ATISTICS) TDRW show statistics: {-1, 0, " ", 0, 0, 0, false, false, 362, 0, NULL, boGeneral}, diff --git a/src/common/classes/ClumpletReader.cpp b/src/common/classes/ClumpletReader.cpp index d20ed8c5ee..cc420d0ae1 100644 --- a/src/common/classes/ClumpletReader.cpp +++ b/src/common/classes/ClumpletReader.cpp @@ -335,6 +335,7 @@ ClumpletReader::ClumpletType ClumpletReader::getClumpletType(UCHAR tag) const case isc_spb_res_fix_fss_metadata: case isc_spb_bkp_stat: case isc_spb_bkp_skip_data: + case isc_spb_bkp_include_data: case isc_spb_bkp_keyholder: case isc_spb_bkp_keyname: case isc_spb_bkp_crypt: diff --git a/src/include/firebird/impl/consts_pub.h b/src/include/firebird/impl/consts_pub.h index 9f34fc29f6..78417c986d 100644 --- a/src/include/firebird/impl/consts_pub.h +++ b/src/include/firebird/impl/consts_pub.h @@ -406,6 +406,7 @@ #define isc_spb_bkp_keyholder 16 #define isc_spb_bkp_keyname 17 #define isc_spb_bkp_crypt 18 +#define isc_spb_bkp_include_data 19 #define isc_spb_bkp_ignore_checksums 0x01 #define isc_spb_bkp_ignore_limbo 0x02 #define isc_spb_bkp_metadata_only 0x04 @@ -513,6 +514,7 @@ *****************************************/ #define isc_spb_res_skip_data isc_spb_bkp_skip_data +#define isc_spb_res_include_data isc_spb_bkp_include_data #define isc_spb_res_buffers 9 #define isc_spb_res_page_size 10 #define isc_spb_res_length 11 diff --git a/src/msgs/facilities2.sql b/src/msgs/facilities2.sql index bcf03c80dd..e6de13afef 100644 --- a/src/msgs/facilities2.sql +++ b/src/msgs/facilities2.sql @@ -9,7 +9,7 @@ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUM ('2018-06-22 11:46:00', 'DYN', 8, 309) ('1996-11-07 13:39:40', 'INSTALL', 10, 1) ('1996-11-07 13:38:41', 'TEST', 11, 4) -('2018-04-26 20:40:00', 'GBAK', 12, 388) +('2018-04-26 20:40:00', 'GBAK', 12, 391) ('2019-04-13 21:10:00', 'SQLERR', 13, 1047) ('1996-11-07 13:38:42', 'SQLWARN', 14, 613) ('2018-02-27 14:50:31', 'JRD_BUGCHK', 15, 308) diff --git a/src/msgs/messages2.sql b/src/msgs/messages2.sql index 5963594b59..dbeb5f4343 100644 --- a/src/msgs/messages2.sql +++ b/src/msgs/messages2.sql @@ -2545,6 +2545,9 @@ ERROR: Backup incomplete', NULL, NULL); (NULL, NULL, 'restore.epp', NULL, 12, 385, NULL, 'Invalid reply from getInfo() when waiting for DB encryption', NULL, NULL); (NULL, NULL, 'restore.epp', NULL, 12, 386, NULL, 'Problems with just created database encryption', NULL, NULL); (NULL, 'get_trigger', 'restore.epp', NULL, 12, 387, NULL, 'Skipped trigger @1 on system table @2', NULL, NULL); +(NULL, 'burp_usage', 'burp.c', NULL, 12, 388, NULL, ' @1INCLUDE(_DATA) backup data of table(s)', NULL, NULL); +(NULL, NULL, 'burp.cpp', NULL, 12, 389, NULL, 'missing regular expression to include tables', NULL, NULL); +(NULL, NULL, 'burp.cpp', NULL, 12, 390, NULL, 'regular expression to include tables was already set', 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); diff --git a/src/utilities/fbsvcmgr/fbsvcmgr.cpp b/src/utilities/fbsvcmgr/fbsvcmgr.cpp index cb1bd5286f..6f2abc3fc7 100644 --- a/src/utilities/fbsvcmgr/fbsvcmgr.cpp +++ b/src/utilities/fbsvcmgr/fbsvcmgr.cpp @@ -404,6 +404,7 @@ const SvcSwitches backupOptions[] = {"bkp_no_triggers", putOption, 0, isc_spb_bkp_no_triggers, 0}, {"verbint", putIntArgument, 0, isc_spb_verbint, 0}, {"bkp_skip_data", putStringArgument, 0, isc_spb_bkp_skip_data, 0}, + {"bkp_include_data", putStringArgument, 0, isc_spb_bkp_include_data, 0}, {"bkp_stat", putStringArgument, 0, isc_spb_bkp_stat, 0 }, {"bkp_keyholder", putStringArgument, 0, isc_spb_bkp_keyholder, 0 }, {"bkp_keyname", putStringArgument, 0, isc_spb_bkp_keyname, 0 }, @@ -433,6 +434,7 @@ const SvcSwitches restoreOptions[] = {"res_metadata_only", putOption, 0, isc_spb_res_metadata_only, 0}, {"verbint", putIntArgument, 0, isc_spb_verbint, 0}, {"res_skip_data", putStringArgument, 0, isc_spb_res_skip_data, 0}, + {"res_include_data", putStringArgument, 0, isc_spb_res_include_data, 0}, {"res_stat", putStringArgument, 0, isc_spb_res_stat, 0 }, {"res_keyholder", putStringArgument, 0, isc_spb_res_keyholder, 0 }, {"res_keyname", putStringArgument, 0, isc_spb_res_keyname, 0 },