diff --git a/builds/install/misc/replication.conf b/builds/install/misc/replication.conf index f9cf1c37f8..eb580d6afe 100644 --- a/builds/install/misc/replication.conf +++ b/builds/install/misc/replication.conf @@ -11,15 +11,25 @@ database # # plugin = + # Pattern (regular expression) that defines what schemas must be included into + # replication. By default, tables from all schemas are replicated. + # + # include_schema_filter = + + # Pattern (regular expression) that defines what schemas must be excluded from + # replication. By default, tables from all schemas are replicated. + # + # exclude_schema_filter = + # 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 +52,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 +86,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 +107,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 +131,7 @@ database # # Multiple entries are allowed (for different synchronous replicas). # - # sync_replica = + # sync_replica = # # It's also possible to configure replicas as separate sub-sections, e.g.: # @@ -175,13 +185,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. @@ -202,6 +212,14 @@ database # then reconnects back and tries to re-apply the latest segments from the point of failure. # # apply_error_timeout = 60 + + # Schema search path for compatibility with Firebird versions below 6.0 + # + # Firebird master databases below v6 has no schemas, so use this search path in the replica to + # locate the objects. + # Used only with asynchronous replication. + # + # schema_search_path = } # diff --git a/builds/win32/msvc15/common.vcxproj b/builds/win32/msvc15/common.vcxproj index 18c9bbba9d..73eb3cbb94 100644 --- a/builds/win32/msvc15/common.vcxproj +++ b/builds/win32/msvc15/common.vcxproj @@ -144,7 +144,7 @@ - + diff --git a/builds/win32/msvc15/common.vcxproj.filters b/builds/win32/msvc15/common.vcxproj.filters index b0e5eebb49..dfe049bf3b 100644 --- a/builds/win32/msvc15/common.vcxproj.filters +++ b/builds/win32/msvc15/common.vcxproj.filters @@ -449,7 +449,7 @@ headers - + headers diff --git a/builds/win32/msvc15/common_test.vcxproj b/builds/win32/msvc15/common_test.vcxproj index 8ba6d3fc3e..85d411e994 100644 --- a/builds/win32/msvc15/common_test.vcxproj +++ b/builds/win32/msvc15/common_test.vcxproj @@ -181,7 +181,11 @@ + + + + @@ -197,4 +201,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/common_test.vcxproj.filters b/builds/win32/msvc15/common_test.vcxproj.filters index 3e8ce6deae..cf423d69fd 100644 --- a/builds/win32/msvc15/common_test.vcxproj.filters +++ b/builds/win32/msvc15/common_test.vcxproj.filters @@ -30,11 +30,23 @@ source + + source + source + + source + + + source + + + source + source - \ No newline at end of file + diff --git a/doc/README.replication.md b/doc/README.replication.md index 4d7ee04996..3fc48f6d13 100644 --- a/doc/README.replication.md +++ b/doc/README.replication.md @@ -47,7 +47,8 @@ ALTER DATABASE EXCLUDE ALL FROM PUBLICATION -- to disable replication of specific tables: ALTER DATABASE EXCLUDE TABLE T1, T2, T3 FROM PUBLICATION -Tables enabled for replicated can be additionally filtered using two settings in the configuration file: include\_filter and exclude\_filter. They are regular expressions that are applied to table names and define rules for inclusion table\(s\) into the replication set or excluding them from the replication set. +Tables enabled for replicated can be additionally filtered using four settings in the configuration file: include\_schema\_filter, exclude\_schema\_filter, include\_filter and exclude\_filter. +They are regular expressions that are applied to schema and table names and define rules for inclusion table\(s\) into the replication set or excluding them from the replication set. Synchronous replication can be turned on using the sync\_replica setting \(multiple entries are allowed\). It must specify a connection string to the replica database, prefixed with username/password. In SuperServer and SuperClassic architectures, replica database is being internally attached when the first user gets connected to the master database and detached when the last user disconnects from the master database. In Classic Server architecture, every server process keeps an active connection to the replica database. diff --git a/doc/sql.extensions/README.ddl_triggers.txt b/doc/sql.extensions/README.ddl_triggers.txt index 1ddcd8c1ba..a146f94a33 100644 --- a/doc/sql.extensions/README.ddl_triggers.txt +++ b/doc/sql.extensions/README.ddl_triggers.txt @@ -119,6 +119,7 @@ DDL_TRIGGER context namespace: - EVENT_TYPE: event type (CREATE, ALTER, DROP) - OBJECT_TYPE: object type (TABLE, VIEW, etc) - DDL_EVENT: event name (), where is EVENT_TYPE || ' ' || OBJECT_TYPE + - SCHEMA_NAME: object's schema name - OBJECT_NAME: metadata object name - OLD_OBJECT_NAME: metadata object name before a rename - NEW_OBJECT_NAME: metadata object name after a rename @@ -294,51 +295,51 @@ commit; select id, ddl_event, object_name, old_object_name, new_object_name, sql_text, ok from ddl_log order by id; - ID DDL_EVENT OBJECT_NAME OLD_OBJECT_NAME NEW_OBJECT_NAME SQL_TEXT OK -===================== ========================= =============================== =============================== =============================== ================= ====== - 2 CREATE TABLE T1 80:0 Y + ID DDL_EVENT OBJECT_NAME OLD_OBJECT_NAME NEW_OBJECT_NAME SQL_TEXT OK +===================== ========================= =============================== =============================== =============================== ================= ====== + 2 CREATE TABLE T1 80:0 Y ============================================================================== -SQL_TEXT: +SQL_TEXT: recreate table t1 ( n1 integer, n2 integer ) ============================================================================== - 3 CREATE TABLE T1 80:1 N + 3 CREATE TABLE T1 80:1 N ============================================================================== -SQL_TEXT: +SQL_TEXT: create table t1 ( n1 integer, n2 integer ) ============================================================================== - 4 DROP TABLE T1 80:2 Y + 4 DROP TABLE T1 80:2 Y ============================================================================== -SQL_TEXT: +SQL_TEXT: recreate table t1 ( n integer ) ============================================================================== - 5 CREATE TABLE T1 80:3 Y + 5 CREATE TABLE T1 80:3 Y ============================================================================== -SQL_TEXT: +SQL_TEXT: recreate table t1 ( n integer ) ============================================================================== - 6 CREATE DOMAIN DOM1 80:4 Y + 6 CREATE DOMAIN DOM1 80:4 Y ============================================================================== -SQL_TEXT: +SQL_TEXT: create domain dom1 as integer ============================================================================== - 7 ALTER DOMAIN DOM1 80:5 Y + 7 ALTER DOMAIN DOM1 80:5 Y ============================================================================== -SQL_TEXT: +SQL_TEXT: alter domain dom1 type bigint ============================================================================== - 8 ALTER DOMAIN DOM1 DOM1 DOM2 80:6 Y + 8 ALTER DOMAIN DOM1 DOM1 DOM2 80:6 Y ============================================================================== -SQL_TEXT: +SQL_TEXT: alter domain dom1 to dom2 ============================================================================== diff --git a/doc/sql.extensions/README.profiler.md b/doc/sql.extensions/README.profiler.md index 3d74055442..ecdb2e3845 100644 --- a/doc/sql.extensions/README.profiler.md +++ b/doc/sql.extensions/README.profiler.md @@ -109,6 +109,8 @@ execute procedure rdb$profiler.finish_session(true); -- Data analysis +set search_path to plg$profiler, public, system; + set transaction read committed; select * from plg$prof_sessions; @@ -243,7 +245,9 @@ Input parameters: # Snapshot tables -Snapshot tables (as well views and sequence) are automatically created in the first usage of the profiler. They are owned by the database owner, with read/write permissions for `PUBLIC`. +The profiler schema, snapshot tables, views and sequence are automatically created in the first usage of the profiler. + +They are owned by the database owner, with usage/read/write permissions for the RDB$PROFILER role, granted by default to `PUBLIC`. When a session is deleted, the related data in other profiler snapshot tables are automatically deleted too through foreign keys with `DELETE CASCADE` option. diff --git a/doc/sql.extensions/README.sql_package.md b/doc/sql.extensions/README.sql_package.md index 676b000f0b..3f2140b5c3 100644 --- a/doc/sql.extensions/README.sql_package.md +++ b/doc/sql.extensions/README.sql_package.md @@ -17,6 +17,7 @@ Output parameters: - `RECORD_SOURCE_ID` type `BIGINT NOT NULL` - record source id - `PARENT_RECORD_SOURCE_ID` type `BIGINT` - parent record source id - `LEVEL` type `INTEGER NOT NULL` - indentation level (may have gaps in relation to parent's level) +- `SCHEMA_NAME` type `RDB$SCHEMA_NAME` - schema name of a stored procedure - `PACKAGE_NAME` type `RDB$PACKAGE_NAME` - package name of a stored procedure - `OBJECT_NAME` type `RDB$RELATION_NAME` - object (table, procedure) name - `ALIAS` type `RDB$SHORT_DESCRIPTION` - alias name diff --git a/examples/replication/fbSampleReplicator.cpp b/examples/replication/fbSampleReplicator.cpp index fcf59537b2..84dc3037c8 100644 --- a/examples/replication/fbSampleReplicator.cpp +++ b/examples/replication/fbSampleReplicator.cpp @@ -35,7 +35,8 @@ public: void setAttachment(IAttachment* attachment) override; IReplicatedTransaction* startTransaction(ITransaction* transaction, ISC_INT64 number) override; FB_BOOLEAN cleanupTransaction(ISC_INT64 number) override; - FB_BOOLEAN setSequence(const char* name, ISC_INT64 value) override; + FB_BOOLEAN deprecatedSetSequence(const char* name, ISC_INT64 value) override; + FB_BOOLEAN setSequence2(const char* schemaName, const char* genName, ISC_INT64 value) override; private: friend class ReplTransaction; @@ -64,11 +65,17 @@ public: FB_BOOLEAN startSavepoint() override; FB_BOOLEAN releaseSavepoint() override; FB_BOOLEAN rollbackSavepoint() override; - FB_BOOLEAN insertRecord(const char* name, IReplicatedRecord* record) override; - FB_BOOLEAN updateRecord(const char* name, IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) override; - FB_BOOLEAN deleteRecord(const char* name, IReplicatedRecord* record) override; - FB_BOOLEAN executeSql(const char* sql) override; - FB_BOOLEAN executeSqlIntl(unsigned charset, const char* sql) override; + FB_BOOLEAN deprecatedInsertRecord(const char* name, IReplicatedRecord* record) override; + FB_BOOLEAN insertRecord2(const char* schemaName, const char* tableName, IReplicatedRecord* record) override; + FB_BOOLEAN deprecatedUpdateRecord(const char* name, + IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) override; + FB_BOOLEAN updateRecord2(const char* schemaName, const char* tableName, + IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) override; + FB_BOOLEAN deprecatedDeleteRecord(const char* name, IReplicatedRecord* record) override; + FB_BOOLEAN deleteRecord2(const char* schemaName, const char* tableName, IReplicatedRecord* record) override; + FB_BOOLEAN deprecatedExecuteSql(const char* sql) override; + FB_BOOLEAN deprecatedExecuteSqlIntl(unsigned charset, const char* sql) override; + FB_BOOLEAN executeSqlIntl2(unsigned charset, const char* schemaSearchPath, const char* sql) override; private: ReplPlugin* parent; @@ -245,9 +252,15 @@ FB_BOOLEAN ReplPlugin::cleanupTransaction(ISC_INT64 number) return FB_TRUE; } -FB_BOOLEAN ReplPlugin::setSequence(const char* name, ISC_INT64 value) +FB_BOOLEAN ReplPlugin::deprecatedSetSequence(const char* name, ISC_INT64 value) { - WriteLog(log, "%p\tsetSequence(%s, %lld)\n", this, name, value); + WriteLog(log, "%p\tdeprecatedSetSequence(%s, %lld)\n", this, name, value); + return FB_TRUE; +} + +FB_BOOLEAN ReplPlugin::setSequence2(const char* schemaName, const char* genName, ISC_INT64 value) +{ + WriteLog(log, "%p\tsetSequence2(%s.%s, %lld)\n", this, schemaName, genName, value); return FB_TRUE; } @@ -506,9 +519,9 @@ bool ReplTransaction::dumpData(IReplicatedRecord* record) return true; } -FB_BOOLEAN ReplTransaction::insertRecord(const char* name, IReplicatedRecord* record) +FB_BOOLEAN ReplTransaction::deprecatedInsertRecord(const char* name, IReplicatedRecord* record) { - WriteLog(parent->log, "%p\tInsert record into %s\n", this, name); + WriteLog(parent->log, "%p\tdeprecated Insert record into %s\n", this, name); try { return dumpData(record) ? FB_TRUE : FB_FALSE; @@ -520,9 +533,24 @@ FB_BOOLEAN ReplTransaction::insertRecord(const char* name, IReplicatedRecord* re } } -FB_BOOLEAN ReplTransaction::updateRecord(const char* name, IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) +FB_BOOLEAN ReplTransaction::insertRecord2(const char* schemaName, const char* tableName, IReplicatedRecord* record) { - WriteLog(parent->log, "%p\tUpdate %s\nOldData:\n", this, name); + WriteLog(parent->log, "%p\tInsert record into %s.%s\n", this, schemaName, tableName); + try + { + return dumpData(record) ? FB_TRUE : FB_FALSE; + } + catch (const int) + { + parent->status->setErrors(err); + return FB_FALSE; + } +} + +FB_BOOLEAN ReplTransaction::deprecatedUpdateRecord(const char* name, + IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) +{ + WriteLog(parent->log, "%p\tdeprecated Update %s\nOldData:\n", this, name); try { if (!dumpData(orgRecord)) @@ -538,9 +566,28 @@ FB_BOOLEAN ReplTransaction::updateRecord(const char* name, IReplicatedRecord* or } } -FB_BOOLEAN ReplTransaction::deleteRecord(const char* name, IReplicatedRecord* record) +FB_BOOLEAN ReplTransaction::updateRecord2(const char* schemaName, const char* tableName, + IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) { - WriteLog(parent->log, "%p\tDelete from %s\n", this, name); + WriteLog(parent->log, "%p\tUpdate %s.%s\nOldData:\n", this, schemaName, tableName); + try + { + if (!dumpData(orgRecord)) + return FB_FALSE; + + WriteLog(parent->log, "NewData:\n"); + return dumpData(newRecord) ? FB_TRUE : FB_FALSE; + } + catch (const int) + { + parent->status->setErrors(err); + return FB_FALSE; + } +} + +FB_BOOLEAN ReplTransaction::deprecatedDeleteRecord(const char* name, IReplicatedRecord* record) +{ + WriteLog(parent->log, "%p\tdeprecated Delete from %s\n", this, name); try { return dumpData(record) ? FB_TRUE : FB_FALSE; @@ -552,14 +599,34 @@ FB_BOOLEAN ReplTransaction::deleteRecord(const char* name, IReplicatedRecord* re } } -FB_BOOLEAN ReplTransaction::executeSql(const char* sql) +FB_BOOLEAN ReplTransaction::deleteRecord2(const char* schemaName, const char* tableName, IReplicatedRecord* record) { - WriteLog(parent->log, "%p\tExecuteSql(%s)\n", this, sql); + WriteLog(parent->log, "%p\tDelete from %s.%s\n", this, schemaName, tableName); + try + { + return dumpData(record) ? FB_TRUE : FB_FALSE; + } + catch (const int) + { + parent->status->setErrors(err); + return FB_FALSE; + } +} + +FB_BOOLEAN ReplTransaction::deprecatedExecuteSql(const char* sql) +{ + WriteLog(parent->log, "%p\tdeprecatedExecuteSql(%s)\n", this, sql); return FB_TRUE; } -FB_BOOLEAN ReplTransaction::executeSqlIntl(unsigned charset, const char* sql) +FB_BOOLEAN ReplTransaction::deprecatedExecuteSqlIntl(unsigned charset, const char* sql) { - WriteLog(parent->log, "%p\tExecuteSqlIntl(%u, %s)\n", this, charset, sql); + WriteLog(parent->log, "%p\tdeprecatedExecuteSqlIntl(%u, %s)\n", this, charset, sql); + return FB_TRUE; +} + +FB_BOOLEAN ReplTransaction::executeSqlIntl2(unsigned charset, const char* schemaSearchPath, const char* sql) +{ + WriteLog(parent->log, "%p\tExecuteSqlIntl2(%u, %s, %s)\n", this, charset, schemaSearchPath, sql); return FB_TRUE; } diff --git a/src/alice/exe.cpp b/src/alice/exe.cpp index bd56dc06e6..43c4c93f5b 100644 --- a/src/alice/exe.cpp +++ b/src/alice/exe.cpp @@ -202,6 +202,7 @@ static void buildDpb(Firebird::ClumpletWriter& dpb, const SINT64 switches) dpb.reset(isc_dpb_version1); dpb.insertTag(isc_dpb_gfix_attach); tdgbl->uSvc->fillDpb(dpb); + dpb.insertString(isc_dpb_search_path, SYSTEM_SCHEMA, fb_strlen(SYSTEM_SCHEMA)); if (switches & sw_sweep) { dpb.insertByte(isc_dpb_sweep, isc_dpb_records); diff --git a/src/auth/SecureRemotePassword/manage/SrpManagement.cpp b/src/auth/SecureRemotePassword/manage/SrpManagement.cpp index db795d0312..7264d9addd 100644 --- a/src/auth/SecureRemotePassword/manage/SrpManagement.cpp +++ b/src/auth/SecureRemotePassword/manage/SrpManagement.cpp @@ -68,28 +68,28 @@ private: void prepareDataStructures() { const char* script[] = { - "CREATE TABLE PLG$SRP (PLG$USER_NAME SEC$USER_NAME NOT NULL PRIMARY KEY, " + "CREATE TABLE PUBLIC.PLG$SRP (PLG$USER_NAME SYSTEM.SEC$USER_NAME NOT NULL PRIMARY KEY, " "PLG$VERIFIER VARCHAR(128) CHARACTER SET OCTETS NOT NULL, " "PLG$SALT VARCHAR(32) CHARACTER SET OCTETS NOT NULL, " - "PLG$COMMENT RDB$DESCRIPTION, PLG$FIRST SEC$NAME_PART, " - "PLG$MIDDLE SEC$NAME_PART, PLG$LAST SEC$NAME_PART, " - "PLG$ATTRIBUTES RDB$DESCRIPTION, " + "PLG$COMMENT SYSTEM.RDB$DESCRIPTION, PLG$FIRST SYSTEM.SEC$NAME_PART, " + "PLG$MIDDLE SYSTEM.SEC$NAME_PART, PLG$LAST SYSTEM.SEC$NAME_PART, " + "PLG$ATTRIBUTES SYSTEM.RDB$DESCRIPTION, " "PLG$ACTIVE BOOLEAN)" , - "CREATE VIEW PLG$SRP_VIEW AS " + "CREATE VIEW PUBLIC.PLG$SRP_VIEW AS " "SELECT PLG$USER_NAME, PLG$VERIFIER, PLG$SALT, PLG$COMMENT, " " PLG$FIRST, PLG$MIDDLE, PLG$LAST, PLG$ATTRIBUTES, PLG$ACTIVE " - "FROM PLG$SRP WHERE RDB$SYSTEM_PRIVILEGE(USER_MANAGEMENT) " + "FROM PUBLIC.PLG$SRP WHERE RDB$SYSTEM_PRIVILEGE(USER_MANAGEMENT) " " OR CURRENT_USER = PLG$SRP.PLG$USER_NAME" , - "GRANT ALL ON PLG$SRP TO VIEW PLG$SRP_VIEW" + "GRANT ALL ON PUBLIC.PLG$SRP TO VIEW PUBLIC.PLG$SRP_VIEW" , - "GRANT SELECT ON PLG$SRP_VIEW TO PUBLIC" + "GRANT SELECT ON PUBLIC.PLG$SRP_VIEW TO PUBLIC" , "GRANT UPDATE(PLG$VERIFIER, PLG$SALT, PLG$FIRST, PLG$MIDDLE, PLG$LAST, " - " PLG$COMMENT, PLG$ATTRIBUTES) ON PLG$SRP_VIEW TO PUBLIC" + " PLG$COMMENT, PLG$ATTRIBUTES) ON PUBLIC.PLG$SRP_VIEW TO PUBLIC" , - "GRANT ALL ON PLG$SRP_VIEW TO SYSTEM PRIVILEGE USER_MANAGEMENT" + "GRANT ALL ON PUBLIC.PLG$SRP_VIEW TO SYSTEM PRIVILEGE USER_MANAGEMENT" , NULL }; @@ -160,7 +160,7 @@ private: Firebird::string userName2(user->userName()->get()); prepareName(userName2, '\''); Firebird::string selGrantor; - selGrantor.printf("SELECT RDB$GRANTOR FROM RDB$USER_PRIVILEGES " + selGrantor.printf("SELECT RDB$GRANTOR FROM SYSTEM.RDB$USER_PRIVILEGES " "WHERE RDB$USER = '%s' AND RDB$RELATION_NAME = '%s' AND RDB$PRIVILEGE = 'M'", userName2.c_str(), ADMIN_ROLE); Message out; @@ -353,7 +353,7 @@ public: case Firebird::IUser::OP_USER_ADD: { const char* insert = - "INSERT INTO plg$srp_view(PLG$USER_NAME, PLG$VERIFIER, PLG$SALT, PLG$FIRST, PLG$MIDDLE, PLG$LAST," + "INSERT INTO public.plg$srp_view(PLG$USER_NAME, PLG$VERIFIER, PLG$SALT, PLG$FIRST, PLG$MIDDLE, PLG$LAST," "PLG$COMMENT, PLG$ATTRIBUTES, PLG$ACTIVE) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)"; Firebird::IStatement* stmt = NULL; @@ -455,7 +455,7 @@ public: case Firebird::IUser::OP_USER_MODIFY: { - Firebird::string update = "UPDATE plg$srp_view SET "; + Firebird::string update = "UPDATE public.plg$srp_view SET "; Firebird::AutoPtr verifier, slt; if (user->password()->entered()) @@ -558,7 +558,7 @@ public: case Firebird::IUser::OP_USER_DELETE: { - const char* del = "DELETE FROM plg$srp_view WHERE PLG$USER_NAME=?"; + const char* del = "DELETE FROM public.plg$srp_view WHERE PLG$USER_NAME=?"; Firebird::IStatement* stmt = NULL; try { @@ -601,11 +601,11 @@ public: case Firebird::IUser::OP_USER_DISPLAY: { Firebird::string disp = - "WITH ADMINS AS (SELECT RDB$USER FROM RDB$USER_PRIVILEGES " + "WITH ADMINS AS (SELECT RDB$USER FROM SYSTEM.RDB$USER_PRIVILEGES " " WHERE RDB$RELATION_NAME = 'RDB$ADMIN' AND RDB$PRIVILEGE = 'M' GROUP BY RDB$USER) " "SELECT PLG$USER_NAME, PLG$FIRST, PLG$MIDDLE, PLG$LAST, PLG$COMMENT, PLG$ATTRIBUTES, " " CASE WHEN RDB$USER IS NULL THEN FALSE ELSE TRUE END, PLG$ACTIVE " - "FROM PLG$SRP_VIEW LEFT JOIN ADMINS " + "FROM SYSTEM.PLG$SRP_VIEW LEFT JOIN ADMINS " " ON PLG$SRP_VIEW.PLG$USER_NAME = ADMINS.RDB$USER "; if (user->userName()->entered()) { diff --git a/src/auth/SecureRemotePassword/server/SrpServer.cpp b/src/auth/SecureRemotePassword/server/SrpServer.cpp index 3d7abb15f7..f88efbace0 100644 --- a/src/auth/SecureRemotePassword/server/SrpServer.cpp +++ b/src/auth/SecureRemotePassword/server/SrpServer.cpp @@ -196,7 +196,7 @@ public: HANDSHAKE_DEBUG(fprintf(stderr, "Srv: SRP1: started transaction\n")); const char* sql = - "SELECT PLG$VERIFIER, PLG$SALT FROM PLG$SRP WHERE PLG$USER_NAME = ? AND PLG$ACTIVE"; + "SELECT PLG$VERIFIER, PLG$SALT FROM PUBLIC.PLG$SRP WHERE PLG$USER_NAME = ? AND PLG$ACTIVE"; stmt = att->prepare(&status, tra, 0, sql, 3, IStatement::PREPARE_PREFETCH_METADATA); if (status->getState() & IStatus::STATE_ERRORS) { diff --git a/src/auth/SecurityDatabase/LegacyManagement.epp b/src/auth/SecurityDatabase/LegacyManagement.epp index 80cbc070dc..fb57ace891 100644 --- a/src/auth/SecurityDatabase/LegacyManagement.epp +++ b/src/auth/SecurityDatabase/LegacyManagement.epp @@ -129,6 +129,7 @@ void SecurityDatabaseManagement::start(Firebird::CheckStatusWrapper* st, Firebir Firebird::ClumpletWriter dpb(Firebird::ClumpletReader::dpbList, MAX_DPB_SIZE); dpb.insertByte(isc_dpb_sec_attach, TRUE); dpb.insertString(isc_dpb_config, Firebird::ParsedList::getNonLoopbackProviders(secDbName)); + dpb.insertString(isc_dpb_search_path, SYSTEM_SCHEMA, fb_strlen(SYSTEM_SCHEMA)); // FIXME: plugin schema unsigned int authBlockSize; const unsigned char* authBlock = logonInfo->authBlock(&authBlockSize); @@ -343,6 +344,7 @@ int SecurityDatabaseManagement::execute(Firebird::CheckStatusWrapper* st, Firebi // this checks the "entered" flags for each parameter (except the name) // and makes all non-entered parameters null valued + // FIXME: epp queries outside engine has not exclusive schema search path set to SYSTEM STORE (TRANSACTION_HANDLE transaction REQUEST_HANDLE request) U IN PLG$VIEW_USERS USING STR_STORE(U.PLG$USER_NAME, user->userName()->get()); diff --git a/src/auth/SecurityDatabase/LegacyServer.cpp b/src/auth/SecurityDatabase/LegacyServer.cpp index 03715e9615..4b59c8709d 100644 --- a/src/auth/SecurityDatabase/LegacyServer.cpp +++ b/src/auth/SecurityDatabase/LegacyServer.cpp @@ -64,7 +64,11 @@ const UCHAR PWD_REQUEST[] = blr_begin, blr_for, blr_rse, 1, - blr_relation, 9, 'P', 'L', 'G', '$', 'U', 'S', 'E', 'R', 'S', 0, + blr_relation3, + 6, 'P', 'U', 'B', 'L', 'I', 'C', // PUBLIC_SCHEMA // FIXME: + 9, 'P', 'L', 'G', '$', 'U', 'S', 'E', 'R', 'S', + 0, + 0, blr_first, blr_literal, blr_short, 0, 1, 0, blr_boolean, diff --git a/src/burp/BurpTasks.cpp b/src/burp/BurpTasks.cpp index 396e1d7ea5..af4d4c6b4b 100644 --- a/src/burp/BurpTasks.cpp +++ b/src/burp/BurpTasks.cpp @@ -561,7 +561,7 @@ bool BackupRelationTask::fileWriter(Item& item) BurpGlobals* tdgbl = item.m_gbl; fb_assert(tdgbl == m_masterGbl); - BURP_verbose(142, m_relation->rel_name); + BURP_verbose(142, m_relation->rel_name.toQuotedString().c_str()); // msg 142 writing data for relation %s IOBuffer*& buf = item.m_buffer = NULL; diff --git a/src/burp/OdsDetection.epp b/src/burp/OdsDetection.epp index 024adfe776..2ca6036133 100644 --- a/src/burp/OdsDetection.epp +++ b/src/burp/OdsDetection.epp @@ -45,6 +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$SCHEMAS", 0, DB_VERSION_DDL14}, // FB6 {0, 0, 0} }; @@ -102,13 +103,16 @@ void detectRuntimeODS() Firebird::IRequest* req_handle = nullptr; FOR (REQUEST_HANDLE req_handle) RFR IN RDB$RELATION_FIELDS - WITH (RFR.RDB$RELATION_NAME = 'RDB$RELATIONS' OR RFR.RDB$RELATION_NAME = 'RDB$RELATION_FIELDS') - AND RFR.RDB$FIELD_NAME = 'RDB$SYSTEM_FLAG' + WITH (RFR.RDB$RELATION_NAME = 'RDB$RELATIONS' OR RFR.RDB$RELATION_NAME = 'RDB$RELATION_FIELDS') AND + RFR.RDB$FIELD_NAME = 'RDB$SYSTEM_FLAG' AND + (RFR.RDB$SCHEMA_NAME MISSING OR RFR.RDB$SCHEMA_NAME = SYSTEM_SCHEMA) + { ++count; - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR MISC_release_request_silent(req_handle); if (count != 2) @@ -119,14 +123,17 @@ void detectRuntimeODS() { FOR (REQUEST_HANDLE req_handle2) FIRST 1 X IN RDB$RELATIONS - WITH X.RDB$RELATION_NAME = rel->relation - AND X.RDB$SYSTEM_FLAG = 1 + WITH X.RDB$RELATION_NAME = rel->relation AND + X.RDB$SYSTEM_FLAG = 1 AND + (X.RDB$SCHEMA_NAME MISSING OR X.RDB$SCHEMA_NAME = SYSTEM_SCHEMA) + { if (tdgbl->runtimeODS < rel->ods_version) tdgbl->runtimeODS = rel->ods_version; - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } MISC_release_request_silent(req_handle2); @@ -138,15 +145,18 @@ void detectRuntimeODS() { FOR (REQUEST_HANDLE req_handle3) FIRST 1 X2 IN RDB$RELATION_FIELDS - WITH X2.RDB$RELATION_NAME = rf->relation - AND X2.RDB$FIELD_NAME = rf->field - AND X2.RDB$SYSTEM_FLAG = 1 + WITH X2.RDB$RELATION_NAME = rf->relation AND + X2.RDB$FIELD_NAME = rf->field AND + X2.RDB$SYSTEM_FLAG = 1 AND + (X2.RDB$SCHEMA_NAME MISSING OR X2.RDB$SCHEMA_NAME = SYSTEM_SCHEMA) + { if (tdgbl->runtimeODS < rf->ods_version) tdgbl->runtimeODS = rf->ods_version; - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } MISC_release_request_silent(req_handle3); } diff --git a/src/burp/OdsDetection.h b/src/burp/OdsDetection.h index 5abaf29852..a22087c160 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 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 ebfe71f168..0d59b58adf 100644 --- a/src/burp/backup.epp +++ b/src/burp/backup.epp @@ -111,7 +111,7 @@ inline const UCHAR* put_block(BurpGlobals* tdgbl, const UCHAR* p, ULONG n) void compress(const UCHAR*, ULONG); int copy(const TEXT*, TEXT*, ULONG); burp_fld* get_fields(burp_rel*); -SINT64 get_gen_id(const TEXT*, SSHORT); +SINT64 get_gen_id(const QualifiedMetaString& name); void get_ranges(burp_fld*); void put_array(burp_fld*, burp_rel*, ISC_QUAD*); void put_asciz(const att_type, const TEXT*); @@ -126,6 +126,7 @@ void put_boolean(att_type, FB_BOOLEAN value); void put_relation(burp_rel*); bool put_source_blob(att_type, att_type, ISC_QUAD&); int put_text(att_type, const TEXT*, SSHORT); +int put_text(att_type attribute, const MetaString& name); void write_character_sets(); void write_check_constraints(); void write_collations(); @@ -134,7 +135,7 @@ void write_exceptions(); void write_field_dimensions(); void write_filters(); void write_functions(); -void write_function_args(const GDS_NAME, GDS_NAME); +void write_function_args(const QualifiedMetaString& name); void write_global_fields(); void write_generators(); void write_sql_roles(); @@ -142,12 +143,13 @@ void write_mapping(); void write_db_creators(); void write_packages(); void write_procedures(); -void write_procedure_prms(const GDS_NAME, const GDS_NAME); +void write_procedure_prms(const QualifiedMetaString& name); void write_publications(); void write_pub_tables(); void write_ref_constraints(); void write_rel_constraints(); void write_relations(); +void write_schemas(); void write_secclasses(); void write_shadow_files(); void write_triggers(); @@ -338,6 +340,13 @@ int BACKUP_backup(const TEXT* dbb_file, const TEXT* file_name) write_database(dbb_file); + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + { + // Write schemas + BURP_verbose(412); // msg 412 writing schemas + write_schemas(); + } + // Write global fields BURP_verbose(150); @@ -411,7 +420,12 @@ int BACKUP_backup(const TEXT* dbb_file, const TEXT* file_name) for (burp_rel* relation = tdgbl->relations; relation; relation = relation->rel_next) { put(tdgbl, (UCHAR) rec_relation_data); - PUT_TEXT(att_relation_name, relation->rel_name); + + if (relation->rel_name.schema.hasData()) + put_text(att_relation_schema_name, relation->rel_name.schema); + + put_text(att_relation_name, relation->rel_name.object); + put(tdgbl, att_end); if (!(relation->rel_flags & REL_view) && !(relation->rel_flags & REL_external)) @@ -656,8 +670,10 @@ burp_fld* get_fields( burp_rel* relation) FOR (REQUEST_HANDLE tdgbl->handles_get_fields_req_handle1) X IN RDB$RELATION_FIELDS CROSS Y IN RDB$FIELDS WITH + X.RDB$FIELD_SOURCE_SCHEMA_NAME EQUIV Y.RDB$SCHEMA_NAME AND X.RDB$FIELD_SOURCE = Y.RDB$FIELD_NAME AND - X.RDB$RELATION_NAME EQ relation->rel_name + X.RDB$SCHEMA_NAME EQUIV NULLIF(relation->rel_name.schema.c_str(), '') AND + X.RDB$RELATION_NAME EQ relation->rel_name.object.c_str() { field = (burp_fld*) BURP_alloc_zero(sizeof(burp_fld)); field->fld_number = count++; @@ -692,7 +708,12 @@ burp_fld* get_fields( burp_rel* relation) field->fld_update_flag = X.RDB$UPDATE_FLAG; COPY (X.RDB$FIELD_NAME, field->fld_name); - COPY (X.RDB$FIELD_SOURCE, field->fld_source); + + if (!X.RDB$FIELD_SOURCE_SCHEMA_NAME.NULL) + field->fld_source.schema = X.RDB$FIELD_SOURCE_SCHEMA_NAME; + + field->fld_source.object = X.RDB$FIELD_SOURCE; + COPY (X.RDB$BASE_FIELD, field->fld_base); COPY (X.RDB$QUERY_NAME, field->fld_query_name); COPY (X.RDB$EDIT_STRING, field->fld_edit_string); @@ -776,7 +797,7 @@ burp_fld* get_fields( burp_rel* relation) X IN RDB$RELATION_FIELDS CROSS Y IN RDB$FIELDS WITH X.RDB$FIELD_SOURCE = Y.RDB$FIELD_NAME AND - X.RDB$RELATION_NAME EQ relation->rel_name + X.RDB$RELATION_NAME EQ relation->rel_name.object.c_str() { field = (burp_fld*) BURP_alloc_zero(sizeof(burp_fld)); field->fld_number = count++; @@ -811,7 +832,7 @@ burp_fld* get_fields( burp_rel* relation) field->fld_update_flag = X.RDB$UPDATE_FLAG; COPY (X.RDB$FIELD_NAME, field->fld_name); - COPY (X.RDB$FIELD_SOURCE, field->fld_source); + field->fld_source.object = X.RDB$FIELD_SOURCE; COPY (X.RDB$BASE_FIELD, field->fld_base); COPY (X.RDB$QUERY_NAME, field->fld_query_name); COPY (X.RDB$EDIT_STRING, field->fld_edit_string); @@ -896,7 +917,7 @@ burp_fld* get_fields( burp_rel* relation) } -SINT64 get_gen_id( const TEXT* name, SSHORT name_len) +SINT64 get_gen_id(const QualifiedMetaString& name) { /************************************** * @@ -912,10 +933,8 @@ SINT64 get_gen_id( const TEXT* name, SSHORT name_len) { BurpGlobals* tdgbl = BurpGlobals::getSpecific(); - Firebird::string nm, sql; - nm.assign(name, name_len); - BURP_makeSymbol(tdgbl, nm); - sql = "select first(1) gen_id(" + nm + ", 0) from rdb$database"; + Firebird::string sql; + sql = "select first(1) gen_id(" + name.toQuotedString() + ", 0) from rdb$database"; BurpSql getGenerator(tdgbl, sql.c_str()); FB_MESSAGE(GetGen, Firebird::ThrowWrapper, (FB_BIGINT, id)); @@ -961,20 +980,21 @@ void get_ranges( burp_fld* field) FOR (REQUEST_HANDLE tdgbl->handles_get_ranges_req_handle1) X IN RDB$FIELD_DIMENSIONS - WITH X.RDB$FIELD_NAME EQ field->fld_source + WITH X.RDB$SCHEMA_NAME EQUIV NULLIF(field->fld_source.schema.c_str(), '') AND + X.RDB$FIELD_NAME EQ field->fld_source.object.c_str() SORTED BY X.RDB$DIMENSION - + { if (count != X.RDB$DIMENSION) BURP_error_redirect (NULL, 52, SafeArg() << field->fld_name); // msg 52 array dimension for field %s is invalid *rp++ = X.RDB$LOWER_BOUND; *rp++ = X.RDB$UPPER_BOUND; count++; - - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR if (count != field->fld_dimensions) BURP_error_redirect(NULL, 52, SafeArg() << field->fld_name); @@ -1611,7 +1631,6 @@ void put_index( burp_rel* relation) * **************************************/ ULONG count; - TEXT temp[GDS_NAME_LEN]; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -1625,19 +1644,22 @@ void put_index( burp_rel* relation) { FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle1) X IN RDB$INDICES WITH - X.RDB$RELATION_NAME EQ relation->rel_name - + X.RDB$SCHEMA_NAME EQUIV NULLIF(relation->rel_name.schema.c_str(), '') AND + X.RDB$RELATION_NAME EQ relation->rel_name.object.c_str() + { count = 0; FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle2) I_S IN RDB$INDEX_SEGMENTS CROSS RFR IN RDB$RELATION_FIELDS WITH I_S.RDB$FIELD_NAME = RFR.RDB$FIELD_NAME AND + I_S.RDB$SCHEMA_NAME EQUIV X.RDB$SCHEMA_NAME AND I_S.RDB$INDEX_NAME = X.RDB$INDEX_NAME AND - RFR.RDB$RELATION_NAME = relation->rel_name - + RFR.RDB$SCHEMA_NAME EQUIV NULLIF(relation->rel_name.schema.c_str(), '') AND + RFR.RDB$RELATION_NAME = relation->rel_name.object.c_str() + { count++; - - END_FOR; + } + END_FOR ON_ERROR general_on_error(); END_ERROR; @@ -1649,22 +1671,23 @@ void put_index( burp_rel* relation) } put(tdgbl, rec_index); - const ULONG l = PUT_TEXT (att_index_name, X.RDB$INDEX_NAME); - MISC_terminate (X.RDB$INDEX_NAME, temp, l, sizeof(temp)); - BURP_verbose (151, temp); + PUT_TEXT(att_index_name, X.RDB$INDEX_NAME); + BURP_verbose(151, QualifiedMetaString(X.RDB$INDEX_NAME, relation->rel_name.schema).toQuotedString().c_str()); // msg 151 writing index %s + put_int32 (att_segment_count, X.RDB$SEGMENT_COUNT); put_int32 (att_index_inactive, X.RDB$INDEX_INACTIVE); put_int32 (att_index_unique_flag, X.RDB$UNIQUE_FLAG); FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle5) Y IN RDB$INDEX_SEGMENTS WITH + Y.RDB$SCHEMA_NAME EQUIV X.RDB$SCHEMA_NAME AND Y.RDB$INDEX_NAME EQ X.RDB$INDEX_NAME SORTED BY Y.RDB$FIELD_POSITION - + { PUT_TEXT (att_index_field_name, Y.RDB$FIELD_NAME); - - END_FOR; + } + END_FOR ON_ERROR general_on_error(); END_ERROR; @@ -1680,6 +1703,9 @@ void put_index( burp_rel* relation) if (!X.RDB$EXPRESSION_BLR.NULL) put_blr_blob(att_index_expression_blr, X.RDB$EXPRESSION_BLR); + if (!X.RDB$FOREIGN_KEY_SCHEMA_NAME.NULL) + PUT_TEXT(att_index_foreign_key_schema_name, X.RDB$FOREIGN_KEY_SCHEMA_NAME); + if (!X.RDB$FOREIGN_KEY.NULL) PUT_TEXT (att_index_foreign_key, X.RDB$FOREIGN_KEY); @@ -1692,8 +1718,8 @@ void put_index( burp_rel* relation) put_blr_blob(att_index_condition_blr, X.RDB$CONDITION_BLR); put(tdgbl, att_end); - - END_FOR; + } + END_FOR ON_ERROR general_on_error(); END_ERROR; @@ -1702,7 +1728,7 @@ void put_index( burp_rel* relation) { FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle1) X IN RDB$INDICES WITH - X.RDB$RELATION_NAME EQ relation->rel_name + X.RDB$RELATION_NAME EQ relation->rel_name.object.c_str() count = 0; FOR (REQUEST_HANDLE tdgbl->handles_put_index_req_handle2) @@ -1710,7 +1736,7 @@ void put_index( burp_rel* relation) RFR IN RDB$RELATION_FIELDS WITH I_S.RDB$FIELD_NAME = RFR.RDB$FIELD_NAME AND I_S.RDB$INDEX_NAME = X.RDB$INDEX_NAME AND - RFR.RDB$RELATION_NAME = relation->rel_name + RFR.RDB$RELATION_NAME = relation->rel_name.object.c_str() count++; @@ -1726,9 +1752,8 @@ void put_index( burp_rel* relation) } put(tdgbl, rec_index); - const ULONG l = PUT_TEXT (att_index_name, X.RDB$INDEX_NAME); - MISC_terminate (X.RDB$INDEX_NAME, temp, l, sizeof(temp)); - BURP_verbose (151, temp); + PUT_TEXT(att_index_name, X.RDB$INDEX_NAME); + BURP_verbose(151, MetaString(X.RDB$INDEX_NAME).toQuotedString().c_str()); // msg 151 writing index %s put_int32 (att_segment_count, X.RDB$SEGMENT_COUNT); put_int32 (att_index_inactive, X.RDB$INDEX_INACTIVE); @@ -1904,8 +1929,6 @@ void put_relation( burp_rel* relation) * Write relation meta-data and data. * **************************************/ - TEXT temp[GDS_NAME_LEN]; - BurpGlobals* tdgbl = BurpGlobals::getSpecific(); // Write local field information. This is made slightly more complicated @@ -1985,11 +2008,15 @@ void put_relation( burp_rel* relation) for (field = relation->rel_fields; field; field = field->fld_next) { put(tdgbl, (UCHAR) rec_field); - const USHORT l = PUT_TEXT(att_field_name, field->fld_name); - MISC_terminate(field->fld_name, temp, l, sizeof(temp)); - BURP_verbose(144, temp); + PUT_TEXT(att_field_name, field->fld_name); + BURP_verbose(144, MetaString(field->fld_name).toQuotedString().c_str()); // msg 144 writing field %s - PUT_TEXT(att_field_source, field->fld_source); + + if (field->fld_source.schema.hasData()) + put_text(att_field_schema_name, field->fld_source.schema); + + put_text(att_field_source, field->fld_source.object); + if (field->fld_query_name[0]) PUT_TEXT(att_field_query_name, field->fld_query_name); if (field->fld_complex_name[0]) @@ -2056,9 +2083,17 @@ void put_relation( burp_rel* relation) if (tdgbl->runtimeODS >= DB_VERSION_DDL12) { FOR (REQUEST_HANDLE tdgbl->handles_put_relation_req_handle1) - X IN RDB$VIEW_RELATIONS WITH X.RDB$VIEW_NAME EQ relation->rel_name + X IN RDB$VIEW_RELATIONS + WITH X.RDB$SCHEMA_NAME EQUIV NULLIF(relation->rel_name.schema.c_str(), '') AND + X.RDB$VIEW_NAME EQ relation->rel_name.object.c_str() + { put(tdgbl, rec_view); - PUT_TEXT (att_view_relation_name, X.RDB$RELATION_NAME); + + if (!X.RDB$RELATION_SCHEMA_NAME.NULL) + PUT_TEXT(att_view_relation_schema_name, X.RDB$RELATION_SCHEMA_NAME); + + PUT_TEXT(att_view_relation_name, X.RDB$RELATION_NAME); + put_int32 (att_view_context_id, X.RDB$VIEW_CONTEXT); // Will need PUT_MESSAGE if this field grows to more than 255 bytes. PUT_TEXT (att_view_context_name, X.RDB$CONTEXT_NAME); @@ -2067,6 +2102,7 @@ void put_relation( burp_rel* relation) if (!X.RDB$PACKAGE_NAME.NULL) PUT_TEXT(att_view_context_package, X.RDB$PACKAGE_NAME); put(tdgbl, att_end); + } END_FOR ON_ERROR general_on_error(); @@ -2075,7 +2111,7 @@ void put_relation( burp_rel* relation) else { FOR (REQUEST_HANDLE tdgbl->handles_put_relation_req_handle1) - X IN RDB$VIEW_RELATIONS WITH X.RDB$VIEW_NAME EQ relation->rel_name + X IN RDB$VIEW_RELATIONS WITH X.RDB$VIEW_NAME EQ relation->rel_name.object.c_str() put(tdgbl, rec_view); PUT_TEXT (att_view_relation_name, X.RDB$RELATION_NAME); put_int32 (att_view_context_id, X.RDB$VIEW_CONTEXT); @@ -2232,7 +2268,7 @@ bool put_source_blob(att_type attribute, att_type old_attribute, ISC_QUAD& blob_ } -int put_text( att_type attribute, const TEXT* text, SSHORT size_len) +int put_text(att_type attribute, const TEXT* text, SSHORT size_len) { /************************************** * @@ -2269,6 +2305,12 @@ int put_text( att_type attribute, const TEXT* text, SSHORT size_len) } +int put_text(att_type attribute, const MetaString& name) +{ + return put_text(attribute, name.c_str(), name.length() + 1); +} + + void write_character_sets() { /************************************** @@ -2291,9 +2333,14 @@ void write_character_sets() FOR (REQUEST_HANDLE req_handle1) X IN RDB$CHARACTER_SETS WITH X.RDB$SYSTEM_FLAG NE 1 OR - X.RDB$DEFAULT_COLLATE_NAME NE X.RDB$CHARACTER_SET_NAME - + NOT (X.RDB$DEFAULT_COLLATE_SCHEMA_NAME EQUIV X.RDB$SCHEMA_NAME AND + X.RDB$DEFAULT_COLLATE_NAME = X.RDB$CHARACTER_SET_NAME) + { put(tdgbl, rec_charset); + + if (!X.RDB$SCHEMA_NAME.NULL) + PUT_TEXT(att_charset_schema_name, X.RDB$SCHEMA_NAME); + PUT_TEXT (att_charset_name, X.RDB$CHARACTER_SET_NAME); if (X.RDB$SYSTEM_FLAG != 1) @@ -2320,12 +2367,16 @@ void write_character_sets() PUT_TEXT(att_charset_owner_name, X.RDB$OWNER_NAME); } - PUT_TEXT (att_charset_coll, X.RDB$DEFAULT_COLLATE_NAME); + if (!X.RDB$DEFAULT_COLLATE_SCHEMA_NAME.NULL) + PUT_TEXT(att_charset_coll_schema_name, X.RDB$DEFAULT_COLLATE_SCHEMA_NAME); + + PUT_TEXT(att_charset_coll, X.RDB$DEFAULT_COLLATE_NAME); put(tdgbl, att_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } else { @@ -2386,13 +2437,19 @@ void write_check_constraints() FOR (REQUEST_HANDLE req_handle1) X IN RDB$CHECK_CONSTRAINTS + { put(tdgbl, rec_chk_constraint); - PUT_TEXT (att_chk_constraint_name, X.RDB$CONSTRAINT_NAME); + if (!X.RDB$SCHEMA_NAME.NULL) + PUT_TEXT(att_chk_schema_name, X.RDB$SCHEMA_NAME); + + PUT_TEXT(att_chk_constraint_name, X.RDB$CONSTRAINT_NAME); + if (!X.RDB$TRIGGER_NAME.NULL) PUT_TEXT (att_chk_trigger_name, X.RDB$TRIGGER_NAME); put(tdgbl, att_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); END_ERROR; @@ -2422,7 +2479,12 @@ void write_collations() { FOR (REQUEST_HANDLE req_handle1) X IN RDB$COLLATIONS WITH X.RDB$SYSTEM_FLAG NE 1 + { put(tdgbl, rec_collation); + + if (!X.RDB$SCHEMA_NAME.NULL) + PUT_TEXT(att_coll_schema_name, X.RDB$SCHEMA_NAME); + PUT_TEXT (att_coll_name, X.RDB$COLLATION_NAME); put_int32 (att_coll_id, X.RDB$COLLATION_ID); put_int32 (att_coll_cs_id, X.RDB$CHARACTER_SET_ID); @@ -2433,8 +2495,10 @@ void write_collations() put_source_blob (att_coll_description, att_coll_description, X.RDB$DESCRIPTION); if (!X.RDB$FUNCTION_NAME.NULL) PUT_TEXT (att_coll_funct, X.RDB$FUNCTION_NAME); + if (!X.RDB$BASE_COLLATION_NAME.NULL) PUT_TEXT(att_coll_base_collation_name, X.RDB$BASE_COLLATION_NAME); + if (!X.RDB$SPECIFIC_ATTRIBUTES.NULL) put_source_blob (att_coll_specific_attr, att_coll_specific_attr, X.RDB$SPECIFIC_ATTRIBUTES); @@ -2444,10 +2508,11 @@ void write_collations() PUT_TEXT(att_coll_owner_name, X.RDB$OWNER_NAME); put(tdgbl, att_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } else if (tdgbl->runtimeODS >= DB_VERSION_DDL11) { @@ -2607,16 +2672,20 @@ void write_database( const TEXT* dbb_file) { FOR (REQUEST_HANDLE req_handle1) D IN RDB$DATABASE + { if (!D.RDB$SECURITY_CLASS.NULL) PUT_TEXT (att_database_security_class, D.RDB$SECURITY_CLASS); put_source_blob (att_database_description2, att_database_description, D.RDB$DESCRIPTION); + if (!D.RDB$CHARACTER_SET_SCHEMA_NAME.NULL) + PUT_TEXT (att_database_dfl_charset_schema_name, D.RDB$CHARACTER_SET_SCHEMA_NAME); if (!D.RDB$CHARACTER_SET_NAME.NULL) PUT_TEXT (att_database_dfl_charset, D.RDB$CHARACTER_SET_NAME); if (!D.RDB$LINGER.NULL) put_int32(att_database_linger, D.RDB$LINGER); if (!D.RDB$SQL_SECURITY.NULL) put_boolean(att_database_sql_security, D.RDB$SQL_SECURITY); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); END_ERROR; @@ -2676,7 +2745,7 @@ void write_exceptions() * each exception. * **************************************/ - TEXT temp[GDS_NAME_LEN]; + QualifiedMetaString name; Firebird::IRequest* req_handle1 = nullptr; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -2686,11 +2755,20 @@ void write_exceptions() FOR (REQUEST_HANDLE req_handle1) X IN RDB$EXCEPTIONS WITH X.RDB$SYSTEM_FLAG NE 1 + { put(tdgbl, rec_exception); - const SSHORT l = PUT_TEXT (att_exception_name, X.RDB$EXCEPTION_NAME); - MISC_terminate (X.RDB$EXCEPTION_NAME, temp, l, sizeof(temp)); - BURP_verbose (198, temp); + + if (!X.RDB$SCHEMA_NAME.NULL) + { + PUT_TEXT(att_exception_schema_name, X.RDB$SCHEMA_NAME); + name.schema = X.RDB$SCHEMA_NAME; + } + + PUT_TEXT(att_exception_name, X.RDB$EXCEPTION_NAME); + name.object = X.RDB$EXCEPTION_NAME; + BURP_verbose(198, name.toQuotedString().c_str()); // msg 198 writing exception %s + PUT_MESSAGE(att_exception_msg, att_exception_msg2, X.RDB$MESSAGE); put_source_blob (att_exception_description2, att_exception_description, X.RDB$DESCRIPTION); @@ -2700,7 +2778,8 @@ void write_exceptions() PUT_TEXT(att_exception_owner_name, X.RDB$OWNER_NAME); put(tdgbl, att_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); END_ERROR; @@ -2710,18 +2789,22 @@ void write_exceptions() FOR (REQUEST_HANDLE req_handle1) X IN RDB$EXCEPTIONS WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 + { put(tdgbl, rec_exception); - const SSHORT l = PUT_TEXT (att_exception_name, X.RDB$EXCEPTION_NAME); - MISC_terminate (X.RDB$EXCEPTION_NAME, temp, l, sizeof(temp)); - BURP_verbose (198, temp); + + PUT_TEXT(att_exception_name, X.RDB$EXCEPTION_NAME); + name.object = X.RDB$EXCEPTION_NAME; + BURP_verbose(198, name.toQuotedString().c_str()); // msg 198 writing exception %s + PUT_MESSAGE(att_exception_msg, att_exception_msg2, X.RDB$MESSAGE); put_source_blob (att_exception_description2, att_exception_description, X.RDB$DESCRIPTION); put(tdgbl, att_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } MISC_release_request_silent(req_handle1); @@ -2747,13 +2830,19 @@ void write_field_dimensions() FOR (REQUEST_HANDLE req_handle1) X IN RDB$FIELD_DIMENSIONS + { put(tdgbl, rec_field_dimensions); + + if (!X.RDB$SCHEMA_NAME.NULL) + PUT_TEXT(att_field_schema_name, X.RDB$SCHEMA_NAME); + PUT_TEXT (att_field_name, X.RDB$FIELD_NAME); put_int32 (att_field_dimensions, X.RDB$DIMENSION); put_int32 (att_field_range_low, X.RDB$LOWER_BOUND); put_int32 (att_field_range_high, X.RDB$UPPER_BOUND); put(tdgbl, att_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); END_ERROR; @@ -2775,7 +2864,6 @@ void write_filters() * each filter. * **************************************/ - TEXT temp[GDS_NAME_LEN]; Firebird::IRequest* req_handle1 = nullptr; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -2783,10 +2871,10 @@ void write_filters() FOR (REQUEST_HANDLE req_handle1) X IN RDB$FILTERS WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 + { put(tdgbl, rec_filter); - const SSHORT l = PUT_TEXT (att_filter_name, X.RDB$FUNCTION_NAME); - MISC_terminate (X.RDB$FUNCTION_NAME, temp, l, sizeof(temp)); - BURP_verbose (145, temp); + PUT_TEXT(att_filter_name, X.RDB$FUNCTION_NAME); + BURP_verbose(145, MetaString(X.RDB$FUNCTION_NAME).toQuotedString().c_str()); // msg 145 writing filter %s put_source_blob (att_filter_description2, att_filter_description, X.RDB$DESCRIPTION); PUT_TEXT (att_filter_module_name, X.RDB$MODULE_NAME); @@ -2794,10 +2882,11 @@ void write_filters() put_int32 (att_filter_input_sub_type, X.RDB$INPUT_SUB_TYPE); put_int32 (att_filter_output_sub_type, X.RDB$OUTPUT_SUB_TYPE); put(tdgbl, att_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR MISC_release_request_silent(req_handle1); } @@ -2816,8 +2905,7 @@ void write_functions() * each function. * **************************************/ - GDS_NAME func; - TEXT temp[GDS_NAME_LEN * 2]; + QualifiedMetaString name; Firebird::IRequest* req_handle1 = nullptr; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -2826,21 +2914,26 @@ void write_functions() { FOR (REQUEST_HANDLE req_handle1) X IN RDB$FUNCTIONS WITH X.RDB$SYSTEM_FLAG NE 1 + { put(tdgbl, rec_function); - SSHORT prefixLen = 0; + if (!X.RDB$SCHEMA_NAME.NULL) + { + PUT_TEXT(att_function_schema_name, X.RDB$SCHEMA_NAME); + name.schema = X.RDB$SCHEMA_NAME; + } if (!X.RDB$PACKAGE_NAME.NULL) { - prefixLen = PUT_TEXT(att_function_package_name, X.RDB$PACKAGE_NAME); - MISC_terminate(X.RDB$PACKAGE_NAME, temp, prefixLen, sizeof(temp)); - temp[prefixLen++] = '.'; + PUT_TEXT(att_function_package_name, X.RDB$PACKAGE_NAME); + name.package = X.RDB$PACKAGE_NAME; } - const SSHORT l = PUT_TEXT (att_function_name, X.RDB$FUNCTION_NAME); - MISC_terminate (X.RDB$FUNCTION_NAME, temp + prefixLen, l, sizeof(temp) - prefixLen); - BURP_verbose (147, temp); + PUT_TEXT(att_function_name, X.RDB$FUNCTION_NAME); + name.object = X.RDB$FUNCTION_NAME; + BURP_verbose(147, name.toQuotedString().c_str()); // msg 147 writing function %.*s + put_source_blob (att_function_description2, att_function_description, X.RDB$DESCRIPTION); if (!X.RDB$RETURN_ARGUMENT.NULL) @@ -2879,10 +2972,11 @@ void write_functions() put(tdgbl, att_end); - COPY (X.RDB$FUNCTION_NAME, func); - write_function_args ((X.RDB$PACKAGE_NAME.NULL ? "" : X.RDB$PACKAGE_NAME), func); + write_function_args(name); + put(tdgbl, rec_function_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); END_ERROR; @@ -2891,11 +2985,14 @@ void write_functions() { FOR (REQUEST_HANDLE req_handle1) X IN RDB$FUNCTIONS WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 + { put(tdgbl, rec_function); - const SSHORT l = PUT_TEXT (att_function_name, X.RDB$FUNCTION_NAME); - MISC_terminate (X.RDB$FUNCTION_NAME, temp, l, sizeof(temp)); - BURP_verbose (147, temp); + + PUT_TEXT(att_function_name, X.RDB$FUNCTION_NAME); + name.object = X.RDB$FUNCTION_NAME; + BURP_verbose(147, name.toQuotedString().c_str()); // msg 147 writing function %.*s + put_source_blob (att_function_description2, att_function_description, X.RDB$DESCRIPTION); PUT_TEXT (att_function_module_name, X.RDB$MODULE_NAME); PUT_TEXT (att_function_entrypoint, X.RDB$ENTRYPOINT); @@ -2906,20 +3003,21 @@ void write_functions() put_int32 (att_function_type, X.RDB$FUNCTION_TYPE); PUT_TEXT (att_function_query_name, X.RDB$QUERY_NAME); put(tdgbl, att_end); - COPY (X.RDB$FUNCTION_NAME, func); - write_function_args ("", func); + write_function_args(name); + put(tdgbl, rec_function_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } MISC_release_request_silent(req_handle1); } -void write_function_args(const GDS_NAME package, GDS_NAME funcptr) +void write_function_args(const QualifiedMetaString& name) { /************************************** * @@ -2931,8 +3029,6 @@ void write_function_args(const GDS_NAME package, GDS_NAME funcptr) * write all arguments for a function. * **************************************/ - TEXT temp[GDS_NAME_LEN * 2]; - BurpGlobals* tdgbl = BurpGlobals::getSpecific(); // if we have all capabilities, use the first request to get the @@ -2945,23 +3041,20 @@ void write_function_args(const GDS_NAME package, GDS_NAME funcptr) { FOR (REQUEST_HANDLE tdgbl->handles_write_function_args_req_handle1) X IN RDB$FUNCTION_ARGUMENTS - WITH X.RDB$FUNCTION_NAME EQ funcptr AND - X.RDB$PACKAGE_NAME EQUIV NULLIF(package, '') - + WITH X.RDB$SCHEMA_NAME EQUIV NULLIF(name.schema.c_str(), '') AND + X.RDB$FUNCTION_NAME EQ name.object.c_str() AND + X.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') + { put(tdgbl, rec_function_arg); - SSHORT prefixLen = 0; + if (name.schema.hasData()) + put_text(att_functionarg_schema_name, name.schema); - if (!X.RDB$PACKAGE_NAME.NULL) - { - prefixLen = PUT_TEXT(att_functionarg_package_name, X.RDB$PACKAGE_NAME); - MISC_terminate(X.RDB$PACKAGE_NAME, temp, prefixLen, sizeof(temp)); - temp[prefixLen++] = '.'; - } + if (name.package.hasData()) + put_text(att_functionarg_package_name, name.package); - const SSHORT l = PUT_TEXT (att_functionarg_name, X.RDB$FUNCTION_NAME); - MISC_terminate (X.RDB$FUNCTION_NAME, temp + prefixLen, l, sizeof(temp) - prefixLen); - BURP_verbose (141, temp); + put_text(att_functionarg_name, name.object); + BURP_verbose(141, name.toQuotedString().c_str()); // msg 141 writing argument for function %s if (!X.RDB$ARGUMENT_POSITION.NULL) @@ -2980,6 +3073,8 @@ void write_function_args(const GDS_NAME package, GDS_NAME funcptr) if (!X.RDB$ARGUMENT_NAME.NULL) PUT_TEXT(att_functionarg_arg_name, X.RDB$ARGUMENT_NAME); + if (!X.RDB$FIELD_SOURCE_SCHEMA_NAME.NULL) + PUT_TEXT(att_functionarg_field_source_schema_name, X.RDB$FIELD_SOURCE_SCHEMA_NAME); if (!X.RDB$FIELD_SOURCE.NULL) PUT_TEXT(att_functionarg_field_source, X.RDB$FIELD_SOURCE); if (!X.RDB$DEFAULT_VALUE.NULL) @@ -2995,13 +3090,16 @@ void write_function_args(const GDS_NAME package, GDS_NAME funcptr) put_int32(att_functionarg_type_mechanism, X.RDB$ARGUMENT_MECHANISM); if (!X.RDB$FIELD_NAME.NULL) PUT_TEXT(att_functionarg_field_name, X.RDB$FIELD_NAME); + if (!X.RDB$RELATION_SCHEMA_NAME.NULL) + PUT_TEXT(att_functionarg_relation_schema_name, X.RDB$RELATION_SCHEMA_NAME); if (!X.RDB$RELATION_NAME.NULL) PUT_TEXT(att_functionarg_relation_name, X.RDB$RELATION_NAME); if (!X.RDB$DESCRIPTION.NULL) put_source_blob(att_functionarg_description, att_functionarg_description, X.RDB$DESCRIPTION); put(tdgbl, att_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); END_ERROR; @@ -3010,12 +3108,12 @@ void write_function_args(const GDS_NAME package, GDS_NAME funcptr) { FOR (REQUEST_HANDLE tdgbl->handles_write_function_args_req_handle1) X IN RDB$FUNCTION_ARGUMENTS WITH - X.RDB$FUNCTION_NAME EQ funcptr - + X.RDB$FUNCTION_NAME EQ name.object.c_str() + { put(tdgbl, rec_function_arg); - const SSHORT l = PUT_TEXT (att_functionarg_name, X.RDB$FUNCTION_NAME); - MISC_terminate (X.RDB$FUNCTION_NAME, temp, l, sizeof(temp)); - BURP_verbose (141, temp); + + put_text(att_functionarg_name, name.object); + BURP_verbose(141, name.toQuotedString().c_str()); // msg 141 writing argument for function %s if (!X.RDB$ARGUMENT_POSITION.NULL) @@ -3032,21 +3130,22 @@ void write_function_args(const GDS_NAME package, GDS_NAME funcptr) if (!X.RDB$FIELD_PRECISION.NULL) put_int32 (att_functionarg_field_precision, X.RDB$FIELD_PRECISION); put(tdgbl, att_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } else { FOR (REQUEST_HANDLE tdgbl->handles_write_function_args_req_handle1) X IN RDB$FUNCTION_ARGUMENTS WITH - X.RDB$FUNCTION_NAME EQ funcptr - + X.RDB$FUNCTION_NAME EQ name.object.c_str() + { put(tdgbl, rec_function_arg); - const SSHORT l = PUT_TEXT (att_functionarg_name, X.RDB$FUNCTION_NAME); - MISC_terminate (X.RDB$FUNCTION_NAME, temp, l, sizeof(temp)); - BURP_verbose (141, temp); + + put_text(att_functionarg_name, name.object); + BURP_verbose(141, name.toQuotedString().c_str()); // msg 141 writing argument for function %s if (!X.RDB$ARGUMENT_POSITION.NULL) @@ -3065,11 +3164,11 @@ void write_function_args(const GDS_NAME package, GDS_NAME funcptr) // bit and store the RDB$FIELD_PRECISION. put(tdgbl, att_end); - - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } } @@ -3087,7 +3186,7 @@ void write_generators() * **************************************/ Firebird::IRequest* req_handle1 = nullptr; - TEXT temp[GDS_NAME_LEN]; + QualifiedMetaString name; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -3096,17 +3195,33 @@ void write_generators() FOR (REQUEST_HANDLE req_handle1) X IN RDB$GENERATORS WITH X.RDB$SYSTEM_FLAG NE 1 + { put(tdgbl, rec_generator); - const SSHORT l = PUT_TEXT (att_gen_generator, X.RDB$GENERATOR_NAME); + + if (!X.RDB$SCHEMA_NAME.NULL) + { + PUT_TEXT(att_gen_schema_name, X.RDB$SCHEMA_NAME); + name.schema = X.RDB$SCHEMA_NAME; + } + + PUT_TEXT(att_gen_generator, X.RDB$GENERATOR_NAME); + name.object = X.RDB$GENERATOR_NAME; + SINT64 value = 0; if (!tdgbl->gbl_sw_meta) { - value = get_gen_id (X.RDB$GENERATOR_NAME, l); + value = get_gen_id(name); + put_int64(att_gen_value_int64, value); + } + + BURP_verbose(165, SafeArg() << name.toQuotedString().c_str() << value); + // msg 165 writing generator %s value %ld + + if (!tdgbl->gbl_sw_meta) put_int64 (att_gen_value_int64, value); - } - if (!X.RDB$DESCRIPTION.NULL) { + + if (!X.RDB$DESCRIPTION.NULL) put_source_blob (att_gen_description, att_gen_description, X.RDB$DESCRIPTION); - } if (X.RDB$SYSTEM_FLAG) put_int32(att_gen_sysflag, X.RDB$SYSTEM_FLAG); @@ -3121,10 +3236,8 @@ void write_generators() put_int32(att_gen_id_increment, X.RDB$GENERATOR_INCREMENT); put(tdgbl, att_end); - MISC_terminate (X.RDB$GENERATOR_NAME, temp, l, sizeof(temp)); - BURP_verbose (165, SafeArg() << temp << value); - // msg 165 writing generator %s value %ld - END_FOR; + } + END_FOR ON_ERROR general_on_error(); END_ERROR; @@ -3134,47 +3247,55 @@ void write_generators() FOR (REQUEST_HANDLE req_handle1) X IN RDB$GENERATORS WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 + { put(tdgbl, rec_generator); - const SSHORT l = PUT_TEXT (att_gen_generator, X.RDB$GENERATOR_NAME); + PUT_TEXT(att_gen_generator, X.RDB$GENERATOR_NAME); + name.object = X.RDB$GENERATOR_NAME; + SINT64 value = 0; if (!tdgbl->gbl_sw_meta) { - value = get_gen_id (X.RDB$GENERATOR_NAME, l); - put_int64 (att_gen_value_int64, value); + value = get_gen_id(name); + put_int64(att_gen_value_int64, value); } if (!X.RDB$DESCRIPTION.NULL) { put_source_blob (att_gen_description, att_gen_description, X.RDB$DESCRIPTION); } put(tdgbl, att_end); - MISC_terminate (X.RDB$GENERATOR_NAME, temp, l, sizeof(temp)); - BURP_verbose (165, SafeArg() << temp << value); + + BURP_verbose(165, SafeArg() << name.toQuotedString().c_str() << value); // msg 165 writing generator %s value %ld - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } else { FOR (REQUEST_HANDLE req_handle1) X IN RDB$GENERATORS WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 + { put(tdgbl, rec_generator); - const SSHORT l = PUT_TEXT (att_gen_generator, X.RDB$GENERATOR_NAME); + PUT_TEXT(att_gen_generator, X.RDB$GENERATOR_NAME); + name.object = X.RDB$GENERATOR_NAME; + SINT64 value = 0; if (!tdgbl->gbl_sw_meta) { - value = get_gen_id (X.RDB$GENERATOR_NAME, l); - put_int64 (att_gen_value_int64, value); + value = get_gen_id(name); + put_int64(att_gen_value_int64, value); } put(tdgbl, att_end); - MISC_terminate (X.RDB$GENERATOR_NAME, temp, l, sizeof(temp)); - BURP_verbose (165, SafeArg() << temp << value); + + BURP_verbose(165, SafeArg() << name.toQuotedString().c_str() << value); // msg 165 writing generator %s value %ld - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } MISC_release_request_silent(req_handle1); @@ -3194,7 +3315,7 @@ void write_global_fields() * each global field. * **************************************/ - TEXT temp[GDS_NAME_LEN]; + QualifiedMetaString name; Firebird::IRequest* req_handle1 = nullptr; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -3210,11 +3331,20 @@ void write_global_fields() FOR (REQUEST_HANDLE req_handle1) X IN RDB$FIELDS WITH X.RDB$SYSTEM_FLAG NE 1 - + { put(tdgbl, rec_global_field); - const SSHORT l = PUT_TEXT (att_field_name, X.RDB$FIELD_NAME); - MISC_terminate (X.RDB$FIELD_NAME, temp, l, sizeof(temp)); - BURP_verbose (149, temp); + + if (!X.RDB$SCHEMA_NAME.NULL) + { + PUT_TEXT(att_field_schema_name, X.RDB$SCHEMA_NAME); + name.schema = X.RDB$SCHEMA_NAME; + } + + PUT_TEXT(att_field_name, X.RDB$FIELD_NAME); + name.object = X.RDB$FIELD_NAME; + + BURP_verbose(149, name.toQuotedString().c_str()); + // msg 149 writing global field %.*s if (!X.RDB$QUERY_NAME.NULL && X.RDB$QUERY_NAME [0] != ' ') PUT_TEXT (att_field_query_name, X.RDB$QUERY_NAME); @@ -3270,8 +3400,8 @@ void write_global_fields() PUT_TEXT(att_field_owner_name, X.RDB$OWNER_NAME); put(tdgbl, att_end); - - END_FOR; + } + END_FOR ON_ERROR general_on_error(); END_ERROR; @@ -3284,10 +3414,13 @@ void write_global_fields() X.RDB$SYSTEM_FLAG MISSING put(tdgbl, rec_global_field); - const SSHORT l = PUT_TEXT (att_field_name, X.RDB$FIELD_NAME); - MISC_terminate (X.RDB$FIELD_NAME, temp, l, sizeof(temp)); - BURP_verbose (149, temp); + + PUT_TEXT(att_field_name, X.RDB$FIELD_NAME); + name.object = X.RDB$FIELD_NAME; + + BURP_verbose(149, name.toQuotedString().c_str()); // msg 149 writing global field %.*s + if (!X.RDB$QUERY_NAME.NULL && X.RDB$QUERY_NAME [0] != ' ') PUT_TEXT (att_field_query_name, X.RDB$QUERY_NAME); if (!X.RDB$EDIT_STRING.NULL && X.RDB$EDIT_STRING [0] != ' ') @@ -3352,10 +3485,13 @@ void write_global_fields() X.RDB$SYSTEM_FLAG MISSING put(tdgbl, rec_global_field); - const SSHORT l = PUT_TEXT (att_field_name, X.RDB$FIELD_NAME); - MISC_terminate (X.RDB$FIELD_NAME, temp, l, sizeof(temp)); - BURP_verbose (149, temp); + + PUT_TEXT(att_field_name, X.RDB$FIELD_NAME); + name.object = X.RDB$FIELD_NAME; + + BURP_verbose(149, name.toQuotedString().c_str()); // msg 149 writing global field %.*s + if (!X.RDB$QUERY_NAME.NULL && X.RDB$QUERY_NAME [0] != ' ') PUT_TEXT (att_field_query_name, X.RDB$QUERY_NAME); if (!X.RDB$EDIT_STRING.NULL && X.RDB$EDIT_STRING [0] != ' ') @@ -3425,7 +3561,7 @@ void write_packages() * each package. * **************************************/ - TEXT temp[GDS_NAME_LEN]; + QualifiedMetaString name; Firebird::IRequest* req_handle1 = nullptr; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -3436,10 +3572,17 @@ void write_packages() WITH X.RDB$SYSTEM_FLAG NE 1 { put(tdgbl, rec_package); - const SSHORT l = PUT_TEXT(att_package_name, X.RDB$PACKAGE_NAME); - MISC_terminate(X.RDB$PACKAGE_NAME, temp, l, sizeof(temp)); - BURP_verbose(335, temp); // msg 335 writing package @1 + if (!X.RDB$SCHEMA_NAME.NULL) + { + PUT_TEXT(att_package_schema_name, X.RDB$SCHEMA_NAME); + name.schema = X.RDB$SCHEMA_NAME; + } + + PUT_TEXT(att_package_name, X.RDB$PACKAGE_NAME); + name.object = X.RDB$PACKAGE_NAME; + + BURP_verbose(335, name.toQuotedString().c_str()); // msg 335 writing package @1 if (!X.RDB$PACKAGE_HEADER_SOURCE.NULL) { @@ -3491,8 +3634,7 @@ void write_procedures() * each stored procedure. * **************************************/ - GDS_NAME proc; - TEXT temp[GDS_NAME_LEN * 2]; + QualifiedMetaString name; Firebird::IRequest* req_handle1 = nullptr; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -3502,22 +3644,27 @@ void write_procedures() FOR (REQUEST_HANDLE req_handle1) X IN RDB$PROCEDURES WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 + { put(tdgbl, rec_procedure); - SSHORT prefixLen = 0; + if (!X.RDB$SCHEMA_NAME.NULL) + { + PUT_TEXT(att_procedure_schema_name, X.RDB$SCHEMA_NAME); + name.schema = X.RDB$SCHEMA_NAME; + } if (!X.RDB$PACKAGE_NAME.NULL) { - prefixLen = PUT_TEXT(att_procedure_package_name, X.RDB$PACKAGE_NAME); - MISC_terminate (X.RDB$PACKAGE_NAME, temp, prefixLen, sizeof(temp)); - temp[prefixLen++] = '.'; + PUT_TEXT(att_procedure_package_name, X.RDB$PACKAGE_NAME); + name.package = X.RDB$PACKAGE_NAME; } - const SSHORT len = PUT_TEXT (att_procedure_name, X.RDB$PROCEDURE_NAME); - MISC_terminate (X.RDB$PROCEDURE_NAME, temp + prefixLen, len, sizeof(temp) - prefixLen); + PUT_TEXT(att_procedure_name, X.RDB$PROCEDURE_NAME); + name.object = X.RDB$PROCEDURE_NAME; - BURP_verbose (193, temp); + BURP_verbose(193, name.toQuotedString().c_str()); // msg 193 writing stored procedure %.*s + put_int32 (att_procedure_inputs, X.RDB$PROCEDURE_INPUTS); put_int32 (att_procedure_outputs, X.RDB$PROCEDURE_OUTPUTS); put_source_blob(att_procedure_description2, att_procedure_description, X.RDB$DESCRIPTION); @@ -3550,24 +3697,28 @@ void write_procedures() put_boolean(att_procedure_sql_security, X.RDB$SQL_SECURITY); put(tdgbl, att_end); - COPY(X.RDB$PROCEDURE_NAME, proc); - write_procedure_prms ((X.RDB$PACKAGE_NAME.NULL ? "" : X.RDB$PACKAGE_NAME), proc); + + write_procedure_prms(name); put(tdgbl, rec_procedure_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } else { FOR (REQUEST_HANDLE req_handle1) X IN RDB$PROCEDURES WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG NE 1 + { put(tdgbl, rec_procedure); - const SSHORT l = PUT_TEXT (att_procedure_name, X.RDB$PROCEDURE_NAME); - MISC_terminate (X.RDB$PROCEDURE_NAME, temp, l, sizeof(temp)); - BURP_verbose (193, temp); + + PUT_TEXT(att_procedure_name, X.RDB$PROCEDURE_NAME); + name.object = X.RDB$PROCEDURE_NAME; + BURP_verbose(193, name.toQuotedString().c_str()); // msg 193 writing stored procedure %.*s + put_int32 (att_procedure_inputs, X.RDB$PROCEDURE_INPUTS); put_int32 (att_procedure_outputs, X.RDB$PROCEDURE_OUTPUTS); put_source_blob (att_procedure_description2, att_procedure_description, X.RDB$DESCRIPTION); @@ -3578,20 +3729,21 @@ void write_procedures() if (!X.RDB$SECURITY_CLASS.NULL) PUT_TEXT (att_procedure_owner_name, X.RDB$OWNER_NAME); put(tdgbl, att_end); - COPY(X.RDB$PROCEDURE_NAME, proc); - write_procedure_prms ("", proc); + + write_procedure_prms(name); put(tdgbl, rec_procedure_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } MISC_release_request_silent(req_handle1); } -void write_procedure_prms(const GDS_NAME package, const GDS_NAME procptr) +void write_procedure_prms(const QualifiedMetaString& name) { /************************************** * @@ -3603,25 +3755,29 @@ void write_procedure_prms(const GDS_NAME package, const GDS_NAME procptr) * write all parameters of a stored procedure. * **************************************/ - TEXT temp[GDS_NAME_LEN]; - BurpGlobals* tdgbl = BurpGlobals::getSpecific(); if (tdgbl->runtimeODS >= DB_VERSION_DDL11_1) { FOR (REQUEST_HANDLE tdgbl->handles_write_procedure_prms_req_handle1) X IN RDB$PROCEDURE_PARAMETERS - WITH X.RDB$PROCEDURE_NAME EQ procptr AND - X.RDB$PACKAGE_NAME EQUIV NULLIF(package, '') + WITH X.RDB$SCHEMA_NAME EQUIV NULLIF(name.schema.c_str(), '') AND + X.RDB$PROCEDURE_NAME EQ name.object.c_str() AND + X.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') { put(tdgbl, rec_procedure_prm); - const SSHORT l = PUT_TEXT (att_procedureprm_name, X.RDB$PARAMETER_NAME); - MISC_terminate (X.RDB$PARAMETER_NAME, temp, l, sizeof(temp)); - BURP_verbose (194, temp); + + PUT_TEXT(att_procedureprm_name, X.RDB$PARAMETER_NAME); + BURP_verbose(194, MetaString(X.RDB$PARAMETER_NAME).toQuotedString().c_str()); // msg 194 writing parameter %s for stored procedure + put_int32 (att_procedureprm_number, X.RDB$PARAMETER_NUMBER); put_int32 (att_procedureprm_type, X.RDB$PARAMETER_type); - PUT_TEXT (att_procedureprm_field_source, X.RDB$FIELD_SOURCE); + + if (!X.RDB$FIELD_SOURCE_SCHEMA_NAME.NULL) + PUT_TEXT(att_procedureprm_field_source_schema_name, X.RDB$FIELD_SOURCE_SCHEMA_NAME); + + PUT_TEXT(att_procedureprm_field_source, X.RDB$FIELD_SOURCE); put_source_blob(att_procedureprm_description2, att_procedureprm_description, X.RDB$DESCRIPTION); put_blr_blob (att_procedureprm_default_value, X.RDB$DEFAULT_VALUE); @@ -3637,6 +3793,10 @@ void write_procedure_prms(const GDS_NAME package, const GDS_NAME procptr) // DB_VERSION_DDL11_2 if (!X.RDB$FIELD_NAME.NULL) PUT_TEXT(att_procedureprm_field_name, X.RDB$FIELD_NAME); + + if (!X.RDB$RELATION_SCHEMA_NAME.NULL) + PUT_TEXT(att_procedureprm_relation_schema_name, X.RDB$RELATION_SCHEMA_NAME); + if (!X.RDB$RELATION_NAME.NULL) PUT_TEXT(att_procedureprm_relation_name, X.RDB$RELATION_NAME); @@ -3645,27 +3805,30 @@ void write_procedure_prms(const GDS_NAME package, const GDS_NAME procptr) END_FOR; ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } else { FOR (REQUEST_HANDLE tdgbl->handles_write_procedure_prms_req_handle1) - X IN RDB$PROCEDURE_PARAMETERS WITH X.RDB$PROCEDURE_NAME EQ procptr + X IN RDB$PROCEDURE_PARAMETERS WITH X.RDB$PROCEDURE_NAME EQ name.object.c_str() + { put(tdgbl, rec_procedure_prm); - const SSHORT l = PUT_TEXT (att_procedureprm_name, X.RDB$PARAMETER_NAME); - MISC_terminate (X.RDB$PARAMETER_NAME, temp, l, sizeof(temp)); - BURP_verbose (194, temp); + + PUT_TEXT(att_procedureprm_name, X.RDB$PARAMETER_NAME); + BURP_verbose(194, MetaString(X.RDB$PARAMETER_NAME).toQuotedString().c_str()); // msg 194 writing parameter %s for stored procedure + put_int32 (att_procedureprm_number, X.RDB$PARAMETER_NUMBER); put_int32 (att_procedureprm_type, X.RDB$PARAMETER_type); PUT_TEXT (att_procedureprm_field_source, X.RDB$FIELD_SOURCE); put_source_blob(att_procedureprm_description2, att_procedureprm_description, X.RDB$DESCRIPTION); put(tdgbl, att_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } } @@ -3683,7 +3846,6 @@ void write_publications() * each publication. * **************************************/ - TEXT temp[GDS_NAME_LEN]; Firebird::IRequest* req_handle = nullptr; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -3694,10 +3856,9 @@ void write_publications() { put(tdgbl, rec_publication); - const SSHORT l = PUT_TEXT(att_pub_name, X.RDB$PUBLICATION_NAME); - MISC_terminate(X.RDB$PUBLICATION_NAME, temp, l, sizeof(temp)); + PUT_TEXT(att_pub_name, X.RDB$PUBLICATION_NAME); - BURP_verbose(397, temp); + BURP_verbose(397, MetaString(X.RDB$PUBLICATION_NAME).toQuotedString().c_str()); // msg 397 writing publication %s if (!X.RDB$OWNER_NAME.NULL) @@ -3733,7 +3894,7 @@ void write_pub_tables() * each publication table. * **************************************/ - TEXT temp[GDS_NAME_LEN]; + QualifiedMetaString tableName; Firebird::IRequest* req_handle = nullptr; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -3745,10 +3906,16 @@ void write_pub_tables() PUT_TEXT(att_ptab_pub_name, X.RDB$PUBLICATION_NAME); - const SSHORT l = PUT_TEXT(att_ptab_table_name, X.RDB$TABLE_NAME); - MISC_terminate(X.RDB$TABLE_NAME, temp, l, sizeof(temp)); + if (!X.RDB$TABLE_SCHEMA_NAME.NULL) + { + PUT_TEXT(att_ptab_table_schema_name, X.RDB$TABLE_NAME); + tableName.schema = X.RDB$TABLE_SCHEMA_NAME; + } - BURP_verbose(398, temp); + PUT_TEXT(att_ptab_table_name, X.RDB$TABLE_NAME); + tableName.object = X.RDB$TABLE_NAME; + + BURP_verbose(398, tableName.toQuotedString().c_str()); // msg 398 writing publication for table %s put(tdgbl, att_end); @@ -3781,14 +3948,25 @@ void write_ref_constraints() FOR (REQUEST_HANDLE req_handle1) X IN RDB$REF_CONSTRAINTS + { put(tdgbl, rec_ref_constraint); - PUT_TEXT (att_ref_constraint_name, X.RDB$CONSTRAINT_NAME); - PUT_TEXT (att_ref_unique_const_name, X.RDB$CONST_NAME_UQ); - PUT_TEXT (att_ref_match_option, X.RDB$MATCH_OPTION); - PUT_TEXT (att_ref_update_rule, X.RDB$UPDATE_RULE); - PUT_TEXT (att_ref_delete_rule, X.RDB$DELETE_RULE); + + if (!X.RDB$SCHEMA_NAME.NULL) + PUT_TEXT(att_ref_schema_name, X.RDB$SCHEMA_NAME); + + PUT_TEXT(att_ref_constraint_name, X.RDB$CONSTRAINT_NAME); + + if (!X.RDB$CONST_SCHEMA_NAME_UQ.NULL) + PUT_TEXT(att_ref_unique_const_schema_name, X.RDB$CONST_SCHEMA_NAME_UQ); + + PUT_TEXT(att_ref_unique_const_name, X.RDB$CONST_NAME_UQ); + + PUT_TEXT(att_ref_match_option, X.RDB$MATCH_OPTION); + PUT_TEXT(att_ref_update_rule, X.RDB$UPDATE_RULE); + PUT_TEXT(att_ref_delete_rule, X.RDB$DELETE_RULE); put(tdgbl, att_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); END_ERROR; @@ -3810,7 +3988,7 @@ void write_rel_constraints() * each relation constraint. * **************************************/ - TEXT temp[GDS_NAME_LEN]; + QualifiedMetaString name; Firebird::IRequest* req_handle1 = nullptr; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -3818,13 +3996,23 @@ void write_rel_constraints() FOR (REQUEST_HANDLE req_handle1) X IN RDB$RELATION_CONSTRAINTS CROSS REL IN RDB$RELATIONS - WITH REL.RDB$RELATION_NAME EQ X.RDB$RELATION_NAME AND + WITH REL.RDB$SCHEMA_NAME EQUIV X.RDB$SCHEMA_NAME AND + REL.RDB$RELATION_NAME EQ X.RDB$RELATION_NAME AND (REL.RDB$SYSTEM_FLAG MISSING OR REL.RDB$SYSTEM_FLAG NE 1) + { put(tdgbl, rec_rel_constraint); - const SSHORT l = PUT_TEXT (att_rel_constraint_name, X.RDB$CONSTRAINT_NAME); - MISC_terminate (X.RDB$CONSTRAINT_NAME, temp, l, sizeof(temp)); - BURP_verbose (207, temp); + + if (!X.RDB$SCHEMA_NAME.NULL) + { + PUT_TEXT(att_rel_constraint_schema_name, X.RDB$SCHEMA_NAME); + name.schema = X.RDB$SCHEMA_NAME; + } + + PUT_TEXT(att_rel_constraint_name, X.RDB$CONSTRAINT_NAME); + name.object = X.RDB$CONSTRAINT_NAME; + BURP_verbose(207, name.toQuotedString().c_str()); // msg 207 writing constraint %s + PUT_TEXT (att_rel_constraint_type, X.RDB$CONSTRAINT_TYPE); PUT_TEXT (att_rel_constraint_rel_name, X.RDB$RELATION_NAME); PUT_TEXT (att_rel_constraint_defer, X.RDB$DEFERRABLE); @@ -3832,7 +4020,8 @@ void write_rel_constraints() if (!X.RDB$INDEX_NAME.NULL) PUT_TEXT (att_rel_constraint_index, X.RDB$INDEX_NAME); put(tdgbl, att_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); END_ERROR; @@ -3854,7 +4043,7 @@ void write_relations() * each relation. * **************************************/ - TEXT temp[GDS_NAME_LEN]; + QualifiedMetaString name; Firebird::IRequest* req_handle1 = nullptr; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -3870,15 +4059,23 @@ void write_relations() FOR (REQUEST_HANDLE req_handle1) X IN RDB$RELATIONS WITH X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$SYSTEM_FLAG MISSING - + { SSHORT flags = 0; put(tdgbl, rec_relation); - const SSHORT l = PUT_TEXT (att_relation_name, X.RDB$RELATION_NAME); - MISC_terminate (X.RDB$RELATION_NAME, temp, l, sizeof(temp)); + + if (!X.RDB$SCHEMA_NAME.NULL) + { + PUT_TEXT(att_relation_schema_name, X.RDB$SCHEMA_NAME); + name.schema = X.RDB$SCHEMA_NAME; + } + + PUT_TEXT(att_relation_name, X.RDB$RELATION_NAME); + name.object = X.RDB$RELATION_NAME; + if (X.RDB$VIEW_BLR.NULL) - BURP_verbose(153, temp); // msg 153 writing table @1 + BURP_verbose(153, name.toQuotedString().c_str()); // msg 153 writing table @1 else - BURP_verbose(345, temp); // msg 345 writing view @1 + BURP_verbose(345, name.toQuotedString().c_str()); // msg 345 writing view @1 // RDB$VIEW_BLR must be the first blob field in the backup file. // RESTORE.EPP makes this assumption in get_relation(). @@ -3919,10 +4116,15 @@ void write_relations() relation->rel_next = tdgbl->relations; tdgbl->relations = relation; relation->rel_id = X.RDB$RELATION_ID; - relation->rel_name_length = COPY(X.RDB$RELATION_NAME, relation->rel_name); + + if (!X.RDB$SCHEMA_NAME.NULL) + relation->rel_name.schema = X.RDB$SCHEMA_NAME; + + relation->rel_name = name; relation->rel_flags |= flags; put_relation (relation); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); END_ERROR; @@ -3932,12 +4134,12 @@ void write_relations() FOR (REQUEST_HANDLE req_handle1) X IN RDB$RELATIONS WITH X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$SYSTEM_FLAG MISSING - + { SSHORT flags = 0; put(tdgbl, rec_relation); - const SSHORT l = PUT_TEXT(att_relation_name, X.RDB$RELATION_NAME); - MISC_terminate (X.RDB$RELATION_NAME, temp, l, sizeof(temp)); - BURP_verbose (153, temp); + PUT_TEXT(att_relation_name, X.RDB$RELATION_NAME); + name.object = X.RDB$RELATION_NAME; + BURP_verbose(153, name.toQuotedString().c_str()); // msg 153 writing table %.*s // RDB$VIEW_BLR must be the first blob field in the backup file. @@ -3969,40 +4171,83 @@ void write_relations() relation->rel_next = tdgbl->relations; tdgbl->relations = relation; relation->rel_id = X.RDB$RELATION_ID; - relation->rel_name_length = COPY(X.RDB$RELATION_NAME, relation->rel_name); + relation->rel_name = name; relation->rel_flags |= flags; put_relation (relation); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } MISC_release_request_silent(req_handle1); } +// Write a record in the burp file for each schema. +void write_schemas() +{ + IRequest* reqHandle1 = nullptr; + BurpGlobals* tdgbl = BurpGlobals::getSpecific(); + + FOR (REQUEST_HANDLE reqHandle1) + X IN RDB$SCHEMAS + WITH X.RDB$SYSTEM_FLAG NE 1 + { + put(tdgbl, rec_schema); + + PUT_TEXT(att_schema_name, X.RDB$SCHEMA_NAME); + + BURP_verbose(411, MetaString(X.RDB$SCHEMA_NAME).toQuotedString().c_str()); // msg 411 writing schema @1 + + if (!X.RDB$CHARACTER_SET_SCHEMA_NAME.NULL) + PUT_TEXT(att_schema_charset_schema_name, X.RDB$CHARACTER_SET_SCHEMA_NAME); + + if (!X.RDB$CHARACTER_SET_NAME.NULL) + PUT_TEXT(att_schema_charset_name, X.RDB$CHARACTER_SET_NAME); + + if (!X.RDB$SECURITY_CLASS.NULL) + PUT_TEXT(att_schema_security_class, X.RDB$SECURITY_CLASS); + + if (!X.RDB$OWNER_NAME.NULL) + PUT_TEXT(att_schema_owner_name, X.RDB$OWNER_NAME); + + if (!X.RDB$DESCRIPTION.NULL) + put_source_blob(att_schema_description, att_schema_description, X.RDB$DESCRIPTION); + + put(tdgbl, att_end); + } + END_FOR + ON_ERROR + general_on_error(); + END_ERROR + + MISC_release_request_silent(reqHandle1); +} + + void write_secclasses() { - TEXT temp[GDS_NAME_LEN]; Firebird::IRequest* req_handle1 = nullptr; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); FOR (REQUEST_HANDLE req_handle1) X IN RDB$SECURITY_CLASSES WITH X.RDB$SECURITY_CLASS NOT STARTING "SQL$" + { put(tdgbl, rec_security_class); - const ULONG l = PUT_TEXT (att_class_security_class, X.RDB$SECURITY_CLASS); - MISC_terminate (X.RDB$SECURITY_CLASS, temp, l, sizeof(temp)); - BURP_verbose (155, temp); + PUT_TEXT(att_class_security_class, X.RDB$SECURITY_CLASS); + BURP_verbose(155, MetaString(X.RDB$SECURITY_CLASS).toQuotedString().c_str()); // msg 155 writing security class @1 put_blr_blob (att_class_acl, X.RDB$ACL); put_source_blob (att_class_description2, att_class_description, X.RDB$DESCRIPTION); put(tdgbl, att_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR MISC_release_request_silent(req_handle1); } @@ -4020,7 +4265,6 @@ void write_shadow_files() * Write out files to use as shadows. * **************************************/ - BASED ON RDB$FILES.RDB$FILE_NAME temp; Firebird::IRequest* req_handle1 = nullptr; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -4029,10 +4273,10 @@ void write_shadow_files() X IN RDB$FILES WITH X.RDB$SHADOW_NUMBER NOT MISSING AND X.RDB$SHADOW_NUMBER NE 0 + { put(tdgbl, rec_files); - const SSHORT l = PUT_TEXT (att_file_filename, X.RDB$FILE_NAME); - MISC_terminate (X.RDB$FILE_NAME, temp, l, sizeof(temp)); - BURP_verbose (163, temp); + PUT_TEXT(att_file_filename, X.RDB$FILE_NAME); + BURP_verbose(163, MetaString(X.RDB$FILE_NAME).toQuotedString().c_str()); // msg 163 writing shadow file %s put_int32 (att_file_sequence, X.RDB$FILE_SEQUENCE); put_int32 (att_file_start, X.RDB$FILE_START); @@ -4040,10 +4284,11 @@ void write_shadow_files() put_int32 (att_file_flags, X.RDB$FILE_FLAGS); put_int32 (att_shadow_number, X.RDB$SHADOW_NUMBER); put(tdgbl, att_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR MISC_release_request_silent(req_handle1); } @@ -4063,7 +4308,6 @@ void write_sql_roles() * **************************************/ Firebird::IRequest* req_handle1 = nullptr; - TEXT temp[GDS_NAME_LEN]; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -4072,10 +4316,10 @@ void write_sql_roles() FOR (REQUEST_HANDLE req_handle1) X IN RDB$ROLES WITH X.RDB$SYSTEM_FLAG EQ 0 OR X.RDB$SYSTEM_FLAG MISSING - + { put(tdgbl, rec_sql_roles); - const SSHORT l = PUT_TEXT(att_role_name, X.RDB$ROLE_NAME); - PUT_TEXT (att_role_owner_name, X.RDB$OWNER_NAME); + PUT_TEXT(att_role_name, X.RDB$ROLE_NAME); + PUT_TEXT(att_role_owner_name, X.RDB$OWNER_NAME); if (!X.RDB$DESCRIPTION.NULL) { put_source_blob (att_role_description, att_role_description, X.RDB$DESCRIPTION); } @@ -4086,32 +4330,30 @@ void write_sql_roles() put_block(tdgbl, (const UCHAR*) (X.RDB$SYSTEM_PRIVILEGES), ll); put(tdgbl, att_end); - MISC_terminate (X.RDB$ROLE_NAME, temp, l, sizeof(temp)); - BURP_verbose (249, temp); + BURP_verbose(249, MetaString(X.RDB$ROLE_NAME).toQuotedString().c_str()); // msg 249 writing SQL role: %s - - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } else { FOR (REQUEST_HANDLE req_handle1) X IN RDB$ROLES - + { put(tdgbl, rec_sql_roles); - const SSHORT l = PUT_TEXT(att_role_name, X.RDB$ROLE_NAME); - PUT_TEXT (att_role_owner_name, X.RDB$OWNER_NAME); + PUT_TEXT(att_role_name, X.RDB$ROLE_NAME); + PUT_TEXT(att_role_owner_name, X.RDB$OWNER_NAME); put(tdgbl, att_end); - MISC_terminate (X.RDB$ROLE_NAME, temp, l, sizeof(temp)); - BURP_verbose (249, temp); + BURP_verbose(249, MetaString(X.RDB$ROLE_NAME).toQuotedString().c_str()); // msg 249 writing SQL role: %s - - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } MISC_release_request_silent(req_handle1); @@ -4132,8 +4374,6 @@ void write_mapping() * **************************************/ Firebird::IRequest* req_handle = nullptr; - TEXT temp[GDS_NAME_LEN]; - BurpGlobals* tdgbl = BurpGlobals::getSpecific(); if (tdgbl->runtimeODS >= DB_VERSION_DDL12) @@ -4141,9 +4381,9 @@ void write_mapping() FOR (REQUEST_HANDLE req_handle) M IN RDB$AUTH_MAPPING WITH M.RDB$SYSTEM_FLAG EQ 0 - + { put(tdgbl, rec_mapping); - const SSHORT l = PUT_TEXT(att_map_name, M.RDB$MAP_NAME); + PUT_TEXT(att_map_name, M.RDB$MAP_NAME); PUT_TEXT(att_map_using, M.RDB$MAP_USING); if (!M.RDB$MAP_PLUGIN.NULL) @@ -4167,34 +4407,33 @@ void write_mapping() put(tdgbl, att_end); - MISC_terminate (M.RDB$MAP_NAME, temp, l, sizeof(temp)); - BURP_verbose (297, temp); + BURP_verbose(297, MetaString(M.RDB$MAP_NAME).toQuotedString().c_str()); // msg 297 writing mapping for %s - - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } else if (tdgbl->runtimeODS >= DB_VERSION_DDL11_2) { FOR (REQUEST_HANDLE req_handle) X IN RDB$ROLES WITH X.RDB$ROLE_NAME EQ ADMIN_ROLE - + { if (X.RDB$SYSTEM_FLAG == 6) // constant 6 turns on auto admin mapping in FB 2.5 { put(tdgbl, rec_mapping); put_text(att_auto_map_role, ADMIN_ROLE, static_cast(strlen(ADMIN_ROLE) + 1)); put(tdgbl, att_end); - BURP_verbose (297, ADMIN_ROLE); + BURP_verbose(297, MetaString(ADMIN_ROLE).toQuotedString().c_str()); // msg 297 writing mapping for @1 } - - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } MISC_release_request_silent(req_handle); @@ -4215,7 +4454,6 @@ void write_db_creators() * **************************************/ Firebird::IRequest* req_handle = nullptr; - TEXT temp[GDS_NAME_LEN]; bool first = true; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -4244,10 +4482,9 @@ void write_db_creators() if (fl) put(tdgbl, rec_db_creator); fl = false; - const SSHORT l = PUT_TEXT(att_dbc_user, C.RDB$USER); + PUT_TEXT(att_dbc_user, C.RDB$USER); - MISC_terminate (C.RDB$USER, temp, l, sizeof(temp)); - BURP_verbose (392, temp); + BURP_verbose(392, MetaString(C.RDB$USER).toQuotedString().c_str()); // msg 392 writing db creator %s } @@ -4275,7 +4512,7 @@ void write_triggers() * write the triggers in rdb$triggers * **************************************/ - TEXT temp[GDS_NAME_LEN]; + QualifiedMetaString name; Firebird::IRequest* req_handle1 = nullptr; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -4292,11 +4529,18 @@ void write_triggers() X IN RDB$TRIGGERS WITH X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$SYSTEM_FLAG MISSING - + { put(tdgbl, rec_trigger); - const SSHORT l = PUT_TEXT (att_trig_name, X.RDB$TRIGGER_NAME); - MISC_terminate (X.RDB$TRIGGER_NAME, temp, l, sizeof(temp)); - BURP_verbose (156, temp); + + if (!X.RDB$SCHEMA_NAME.NULL) + { + PUT_TEXT(att_trig_schema_name, X.RDB$SCHEMA_NAME); + name.schema = X.RDB$SCHEMA_NAME; + } + + PUT_TEXT(att_trig_name, X.RDB$TRIGGER_NAME); + name.object = X.RDB$TRIGGER_NAME; + BURP_verbose(156, name.toQuotedString().c_str()); // msg 156 writing trigger %s if (!X.RDB$RELATION_NAME.NULL) @@ -4334,8 +4578,8 @@ void write_triggers() put_boolean(att_trig_sql_security, X.RDB$SQL_SECURITY); put(tdgbl, att_end); - - END_FOR; + } + END_FOR ON_ERROR general_on_error(); END_ERROR; @@ -4346,11 +4590,12 @@ void write_triggers() X IN RDB$TRIGGERS WITH X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$SYSTEM_FLAG MISSING - + { put(tdgbl, rec_trigger); - const SSHORT l = PUT_TEXT (att_trig_name, X.RDB$TRIGGER_NAME); - MISC_terminate (X.RDB$TRIGGER_NAME, temp, l, sizeof(temp)); - BURP_verbose (156, temp); + + PUT_TEXT(att_trig_name, X.RDB$TRIGGER_NAME); + name.object = X.RDB$TRIGGER_NAME; + BURP_verbose(156, name.toQuotedString().c_str()); // msg 156 writing trigger %s if (!X.RDB$RELATION_NAME.NULL) @@ -4368,11 +4613,11 @@ void write_triggers() put_int32 (att_trig_flags, X.RDB$FLAGS); put(tdgbl, att_end); - - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } MISC_release_request_silent(req_handle1); @@ -4392,25 +4637,37 @@ void write_trigger_messages() * each trigger message. * **************************************/ - TEXT temp[GDS_NAME_LEN]; + QualifiedMetaString name; Firebird::IRequest* req_handle1 = nullptr; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); FOR (REQUEST_HANDLE req_handle1) - T IN RDB$TRIGGERS CROSS X IN RDB$TRIGGER_MESSAGES - OVER RDB$TRIGGER_NAME - WITH T.RDB$SYSTEM_FLAG NE 1 OR T.RDB$SYSTEM_FLAG MISSING - + T IN RDB$TRIGGERS + CROSS X IN RDB$TRIGGER_MESSAGES + WITH X.RDB$SCHEMA_NAME EQUIV T.RDB$SCHEMA_NAME AND + X.RDB$TRIGGER_NAME EQ T.RDB$TRIGGER_NAME AND + T.RDB$SYSTEM_FLAG NE 1 OR T.RDB$SYSTEM_FLAG MISSING + { put(tdgbl, rec_trigger_message); - const SSHORT l = PUT_TEXT (att_trigmsg_name, X.RDB$TRIGGER_NAME); - MISC_terminate (X.RDB$TRIGGER_NAME, temp, l, sizeof(temp)); - BURP_verbose (157, temp); + + if (!X.RDB$SCHEMA_NAME.NULL) + { + PUT_TEXT(att_trigmsg_schema_name, X.RDB$SCHEMA_NAME); + name.schema = X.RDB$SCHEMA_NAME; + } + + PUT_TEXT(att_trigmsg_name, X.RDB$TRIGGER_NAME); + name.object = X.RDB$TRIGGER_NAME; + + BURP_verbose(157, name.toQuotedString().c_str()); // msg 157 writing trigger message for %s + put_int32 (att_trigmsg_number, X.RDB$MESSAGE_NUMBER); PUT_MESSAGE (att_trigmsg_text, att_end, X.RDB$MESSAGE); put(tdgbl, att_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); END_ERROR; @@ -4439,6 +4696,7 @@ void write_types() FOR (REQUEST_HANDLE req_handle1) X IN RDB$TYPES WITH X.RDB$SYSTEM_FLAG NE 1 OR X.RDB$SYSTEM_FLAG MISSING + { put(tdgbl, rec_system_type); PUT_TEXT (att_type_name, X.RDB$TYPE_NAME); PUT_TEXT (att_type_field_name, X.RDB$FIELD_NAME); @@ -4449,10 +4707,11 @@ void write_types() if (X.RDB$SYSTEM_FLAG) put_int32 (att_type_system_flag, X.RDB$SYSTEM_FLAG); put(tdgbl, att_end); - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR MISC_release_request_silent(req_handle1); } @@ -4471,7 +4730,7 @@ void write_user_privileges() * each user privilege. * **************************************/ - TEXT temp[GDS_NAME_LEN]; + QualifiedMetaString user; Firebird::IRequest* req_handle1 = nullptr; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -4479,21 +4738,36 @@ void write_user_privileges() FOR (REQUEST_HANDLE req_handle1) X IN RDB$USER_PRIVILEGES WITH X.RDB$GRANTOR NOT MISSING + { put(tdgbl, rec_user_privilege); - const SSHORT l = PUT_TEXT (att_priv_user, X.RDB$USER); - MISC_terminate (X.RDB$USER, temp, l, sizeof(temp)); - BURP_verbose (152, temp); + + if (!X.RDB$USER_SCHEMA_NAME.NULL) + { + PUT_TEXT(att_priv_user_schema_name, X.RDB$USER_SCHEMA_NAME); + user.schema = X.RDB$USER_SCHEMA_NAME; + } + + PUT_TEXT(att_priv_user, X.RDB$USER); + user.object = X.RDB$USER; + BURP_verbose(152, user.toQuotedString().c_str()); // msg 152 writing privilege for user %s + PUT_TEXT (att_priv_grantor, X.RDB$GRANTOR); PUT_TEXT (att_priv_privilege, X.RDB$PRIVILEGE); if (!X.RDB$GRANT_OPTION.NULL) put_int32 (att_priv_grant_option, X.RDB$GRANT_OPTION); - PUT_TEXT (att_priv_object_name, X.RDB$RELATION_NAME); + + if (!X.RDB$RELATION_SCHEMA_NAME.NULL) + PUT_TEXT(att_priv_object_schema_name, X.RDB$RELATION_SCHEMA_NAME); + + PUT_TEXT(att_priv_object_name, X.RDB$RELATION_NAME); + if (!X.RDB$FIELD_NAME.NULL) PUT_TEXT (att_priv_field_name, X.RDB$FIELD_NAME); put_int32 (att_priv_user_type, X.RDB$USER_TYPE); put_int32 (att_priv_obj_type, X.RDB$OBJECT_TYPE); put(tdgbl, att_end); + } END_FOR ON_ERROR general_on_error(); diff --git a/src/burp/burp.cpp b/src/burp/burp.cpp index 9db13af103..1ccc04f40c 100644 --- a/src/burp/burp.cpp +++ b/src/burp/burp.cpp @@ -765,13 +765,35 @@ int gbak(Firebird::UtilSvc* uSvc) } tdgbl->gbl_sw_user = argv[itr]; break; + case IN_SW_BURP_SKIP_SCHEMA_DATA: + if (++itr >= argc) + { + BURP_error(417, true); + // missing regular expression to skip tables + } + + tdgbl->setupSkipIncludePattern(argv[itr], 419, tdgbl->skipSchemaDataMatcher); + // msg 419 regular expression to skip schemas was already set + break; case IN_SW_BURP_SKIP_DATA: if (++itr >= argc) { BURP_error(354, true); // missing regular expression to skip tables } - tdgbl->setupSkipData(argv[itr]); + + tdgbl->setupSkipIncludePattern(argv[itr], 356, tdgbl->skipDataMatcher); + // msg 356 regular expression to skip tables was already set + break; + case IN_SW_BURP_INCLUDE_SCHEMA_DATA: + if (++itr >= argc) + { + BURP_error(418, true); + // missing regular expression to include tables + } + + tdgbl->setupSkipIncludePattern(argv[itr], 420, tdgbl->includeSchemaDataMatcher); + // msg 420 regular expression to include schemas was already set break; case IN_SW_BURP_INCLUDE_DATA: if (++itr >= argc) @@ -779,7 +801,9 @@ int gbak(Firebird::UtilSvc* uSvc) BURP_error(389, true); // missing regular expression to include tables } - tdgbl->setupIncludeData(argv[itr]); + + tdgbl->setupSkipIncludePattern(argv[itr], 390, tdgbl->includeDataMatcher); + // msg 390 regular expression to include tables was already set break; case IN_SW_BURP_ROLE: if (++itr >= argc) @@ -1153,6 +1177,8 @@ int gbak(Firebird::UtilSvc* uSvc) dpb.insertBytes(isc_dpb_auth_block, authBlock, authSize); } + dpb.insertString(isc_dpb_search_path, SYSTEM_SCHEMA, fb_strlen(SYSTEM_SCHEMA)); + // We call getTableMod() because we are interested in the items that were activated previously, // not in the original, unchanged table that "switches" took as parameter in the constructor. for (const Switches::in_sw_tab_t* in_sw_tab = switches.getTableMod(); @@ -2664,59 +2690,25 @@ void close_platf(DESC file) #endif // WIN_NT -void BurpGlobals::setupSkipData(const Firebird::string& regexp) +void BurpGlobals::setupSkipIncludePattern(const string& regexp, USHORT alreadySetErrorCode, + AutoPtr& matcher) { - if (skipDataMatcher) - { - BURP_error(356, true); - // msg 356 regular expression to skip tables was already set - } + if (matcher) + BURP_error(alreadySetErrorCode, true); - // Compile skip relation expressions + // Compile expressions try { if (regexp.hasData()) { - Firebird::string filter(regexp); + string filter(regexp); if (!uSvc->utf8FileNames()) ISC_systemToUtf8(filter); BurpGlobals* tdgbl = BurpGlobals::getSpecific(); - skipDataMatcher.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()); - } -} - -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, + matcher.reset(FB_NEW_POOL(tdgbl->getPool()) SimilarToRegex( + tdgbl->getPool(), SimilarToFlag::CASE_INSENSITIVE, filter.c_str(), filter.length(), "\\", 1)); } @@ -2750,7 +2742,7 @@ namespace // for local symbols } } -bool BurpGlobals::skipRelation(const char* name) +bool BurpGlobals::skipRelation(const QualifiedMetaString& name) { if (gbl_sw_meta) return true; @@ -2764,10 +2756,12 @@ bool BurpGlobals::skipRelation(const char* name) { false, false, true} // NM p }; - const enum Pattern res1 = checkPattern(skipDataMatcher, name); - const enum Pattern res2 = checkPattern(includeDataMatcher, name); + const enum Pattern res1sch = checkPattern(skipSchemaDataMatcher, name.schema.c_str()); + const enum Pattern res1obj = checkPattern(skipDataMatcher, name.object.c_str()); + const enum Pattern res2sch = checkPattern(includeSchemaDataMatcher, name.schema.c_str()); + const enum Pattern res2obj = checkPattern(includeDataMatcher, name.object.c_str()); - return result[res1][res2]; + return result[res1sch][res2sch] && result[res1obj][res2obj]; } void BurpGlobals::read_stats(SINT64* stats) @@ -2888,24 +2882,6 @@ void BurpGlobals::print_stats_header() burp_output(false, "\n"); } -void BURP_makeSymbol(BurpGlobals* tdgbl, Firebird::string& name) // add double quotes to string -{ - if (tdgbl->gbl_dialect < SQL_DIALECT_V6) - return; - - const char dq = '"'; - for (unsigned p = 0; p < name.length(); ++p) - { - if (name[p] == dq) - { - name.insert(p, 1, dq); - ++p; - } - } - name.insert(0u, 1, dq); - name += dq; -} - static void processFetchPass(const SCHAR*& password, int& itr, const int argc, Firebird::UtilSvc::ArgvType& argv) { if (++itr >= argc) diff --git a/src/burp/burp.h b/src/burp/burp.h index cb791efa7e..30541eb080 100644 --- a/src/burp/burp.h +++ b/src/burp/burp.h @@ -42,7 +42,9 @@ #include "../common/UtilSvc.h" #include "../common/classes/array.h" #include "../common/classes/fb_pair.h" +#include "../common/classes/GenericMap.h" #include "../common/classes/MetaString.h" +#include "../common/classes/QualifiedMetaString.h" #include "../common/SimilarToRegex.h" #include "../common/status.h" #include "../common/sha.h" @@ -120,7 +122,8 @@ enum rec_type { rec_package, // Package rec_db_creator, // Database creator rec_publication, // Publication - rec_pub_table // Publication table + rec_pub_table, // Publication table + rec_schema // Schema }; @@ -205,9 +208,12 @@ Version 10: FB3.0. Version 11: FB4.0. SQL SECURITY feature, tables RDB$PUBLICATIONS/RDB$PUBLICATION_TABLES. + +Version 12: FB6.0. + Schemas. */ -const int ATT_BACKUP_FORMAT = 11; +const int ATT_BACKUP_FORMAT = 12; // max array dimension @@ -259,6 +265,7 @@ enum att_type { att_database_sql_security, // default sql security value att_default_pub_active, // default publication status att_default_pub_auto_enable, + att_database_dfl_charset_schema_name, // default character set schema name // Relation attributes @@ -282,6 +289,7 @@ enum att_type { att_relation_type, att_relation_sql_security_deprecated, // can be removed later att_relation_sql_security, + att_relation_schema_name, // Field attributes (used for both global and local fields) @@ -341,6 +349,7 @@ enum att_type { att_field_owner_name, // FB3.0, ODS12_0, att_field_generator_name, att_field_identity_type, + att_field_schema_name, // Index attributes @@ -357,6 +366,7 @@ enum att_type { att_index_expression_blr, att_index_condition_source, att_index_condition_blr, + att_index_foreign_key_schema_name, // Data record @@ -381,6 +391,7 @@ enum att_type { // Security class attributes + // FIXME: SERIES + ... ? att_class_security_class = SERIES + 10, att_class_acl, att_class_description, @@ -396,7 +407,9 @@ enum att_type { att_xdr_length = SERIES + 16, att_xdr_array, + att_class_description2, + att_view_relation_schema_name, // Trigger attributes @@ -419,6 +432,7 @@ enum att_type { att_trig_type2, att_trig_sql_security_deprecated, // can be removed later att_trig_sql_security, + att_trig_schema_name, // Function attributes @@ -444,6 +458,7 @@ enum att_type { att_function_deterministic_flag, att_function_sql_security_deprecated, // can be removed later att_function_sql_security, + att_function_schema_name, // Function argument attributes @@ -467,6 +482,9 @@ enum att_type { att_functionarg_field_name, att_functionarg_relation_name, att_functionarg_description, + att_functionarg_schema_name, + att_functionarg_field_source_schema_name, + att_functionarg_relation_schema_name, // TYPE relation attributes att_type_name = SERIES, @@ -490,6 +508,7 @@ enum att_type { att_trigmsg_name = SERIES, att_trigmsg_number, att_trigmsg_text, + att_trigmsg_schema_name, // User privilege attributes att_priv_user = SERIES, @@ -500,6 +519,8 @@ enum att_type { att_priv_field_name, att_priv_user_type, att_priv_obj_type, + att_priv_user_schema_name, + att_priv_object_schema_name, // files for shadowing purposes att_file_filename = SERIES, @@ -519,6 +540,7 @@ enum att_type { att_gen_sysflag, att_gen_init_val, att_gen_id_increment, + att_gen_schema_name, // Stored procedure attributes @@ -541,6 +563,7 @@ enum att_type { att_procedure_private_flag, att_procedure_sql_security_deprecated, // can be removed later att_procedure_sql_security, + att_procedure_schema_name, // Stored procedure parameter attributes @@ -557,6 +580,8 @@ enum att_type { att_procedureprm_mechanism, att_procedureprm_field_name, att_procedureprm_relation_name, + att_procedureprm_field_source_schema_name, + att_procedureprm_relation_schema_name, // Exception attributes @@ -567,6 +592,7 @@ enum att_type { att_exception_msg2, att_exception_security_class, // FB3.0, ODS12_0 att_exception_owner_name, + att_exception_schema_name, // FB6.0, ODS14_0 // Relation constraints attributes @@ -576,6 +602,7 @@ enum att_type { att_rel_constraint_defer, att_rel_constraint_init, att_rel_constraint_index, + att_rel_constraint_schema_name, // Referential constraints attributes @@ -584,6 +611,8 @@ enum att_type { att_ref_match_option, att_ref_update_rule, att_ref_delete_rule, + att_ref_schema_name, + att_ref_unique_const_schema_name, // SQL roles attributes att_role_name = SERIES, @@ -594,6 +623,7 @@ enum att_type { // Check constraints attributes att_chk_constraint_name = SERIES, att_chk_trigger_name, + att_chk_schema_name, // Character Set attributes att_charset_name = SERIES, @@ -607,6 +637,8 @@ enum att_type { att_charset_bytes_char, att_charset_security_class, // FB3.0, ODS12_0 att_charset_owner_name, + att_charset_schema_name, + att_charset_coll_schema_name, att_coll_name = SERIES, att_coll_id, @@ -620,6 +652,7 @@ enum att_type { att_coll_specific_attr, att_coll_security_class, // FB3.0, ODS12_0 att_coll_owner_name, + att_coll_schema_name, // Names mapping att_map_name = SERIES, @@ -643,6 +676,7 @@ enum att_type { att_package_description, att_package_sql_security_deprecated, // can be removed later att_package_sql_security, + att_package_schema_name, // Database creators att_dbc_user = SERIES, @@ -656,7 +690,16 @@ enum att_type { // Publication tables att_ptab_pub_name = SERIES, - att_ptab_table_name + att_ptab_table_name, + att_ptab_table_schema_name, + + // Schema attributes + att_schema_name = SERIES, + att_schema_charset_schema_name, + att_schema_charset_name, + att_schema_security_class, + att_schema_owner_name, + att_schema_description, }; @@ -703,7 +746,7 @@ struct burp_fld SSHORT fld_system_flag; SSHORT fld_name_length; TEXT fld_name [GDS_NAME_LEN]; - TEXT fld_source [GDS_NAME_LEN]; + Firebird::QualifiedMetaString fld_source; TEXT fld_base [GDS_NAME_LEN]; TEXT fld_query_name [GDS_NAME_LEN]; TEXT fld_security_class [GDS_NAME_LEN]; @@ -748,8 +791,7 @@ struct burp_rel burp_fld* rel_fields; SSHORT rel_flags; SSHORT rel_id; - SSHORT rel_name_length; - GDS_NAME rel_name; + Firebird::QualifiedMetaString rel_name; GDS_NAME rel_owner; // relation owner, if not us ULONG rel_max_pp; // max pointer page sequence number }; @@ -763,7 +805,7 @@ enum burp_rel_flags_vals { struct burp_pkg { burp_pkg* pkg_next; - GDS_NAME pkg_name; + Firebird::QualifiedMetaString pkg_name; GDS_NAME pkg_owner; }; @@ -772,16 +814,14 @@ struct burp_pkg struct burp_prc { burp_prc* prc_next; - //SSHORT prc_name_length; // Currently useless, but didn't want to delete it. - GDS_NAME prc_package; - GDS_NAME prc_name; + Firebird::QualifiedMetaString prc_name; GDS_NAME prc_owner; // relation owner, if not us }; struct gfld { - TEXT gfld_name [GDS_NAME_LEN]; + Firebird::QualifiedMetaString gfld_name; ISC_QUAD gfld_vb; ISC_QUAD gfld_vs; ISC_QUAD gfld_vs2; @@ -806,7 +846,7 @@ struct burp_meta_obj { burp_meta_obj* obj_next; USHORT obj_type; - GDS_NAME obj_name; + Firebird::QualifiedMetaString obj_name; bool obj_class; }; @@ -1144,6 +1184,7 @@ public: Firebird::IRequest* handles_get_ref_constraint_req_handle1; Firebird::IRequest* handles_get_rel_constraint_req_handle1; Firebird::IRequest* handles_get_relation_req_handle1; + Firebird::IRequest* handles_get_schema_req_handle1; Firebird::IRequest* handles_get_security_class_req_handle1; Firebird::IRequest* handles_get_sql_roles_req_handle1; Firebird::IRequest* handles_get_trigger_message_req_handle1; @@ -1189,9 +1230,9 @@ public: { ThreadData::restoreSpecific(); } - void setupSkipData(const Firebird::string& regexp); - void setupIncludeData(const Firebird::string& regexp); - bool skipRelation(const char* name); + void setupSkipIncludePattern(const Firebird::string& regexp, USHORT alreadySetErrorCode, + Firebird::AutoPtr& matcher); + bool skipRelation(const Firebird::QualifiedMetaString& name); char veryEnd; //starting after this members must be initialized in constructor explicitly @@ -1199,9 +1240,8 @@ public: Firebird::FbLocalStatus status_vector; Firebird::ThrowLocalStatus throwStatus; - Firebird::Array > > - defaultCollations; - Firebird::SortedArray systemFields; + Firebird::NonPooledMap defaultCollations; + Firebird::SortedArray systemFields; Firebird::Array gbl_dpb_data; Firebird::UtilSvc* uSvc; bool master; // set for master thread only @@ -1211,7 +1251,9 @@ public: bool firstMap; // this is the first time we entered get_mapping() bool firstDbc; // this is the first time we entered get_db_creators() bool stdIoMode; // stdin or stdout is used as backup file + Firebird::AutoPtr skipSchemaDataMatcher; Firebird::AutoPtr skipDataMatcher; + Firebird::AutoPtr includeSchemaDataMatcher; Firebird::AutoPtr includeDataMatcher; public: diff --git a/src/burp/burp_proto.h b/src/burp/burp_proto.h index 393da083cc..2b692d5234 100644 --- a/src/burp/burp_proto.h +++ b/src/burp/burp_proto.h @@ -38,7 +38,6 @@ void BURP_abort(Firebird::IStatus* status = nullptr); void BURP_error(USHORT, bool, const MsgFormat::SafeArg& arg = MsgFormat::SafeArg()); void BURP_error(USHORT, bool, const char* str); void BURP_error_redirect(Firebird::IStatus*, USHORT, const MsgFormat::SafeArg& arg = MsgFormat::SafeArg()); -void BURP_makeSymbol(BurpGlobals*, Firebird::string&); void BURP_msg_partial(bool, USHORT, const MsgFormat::SafeArg& arg = MsgFormat::SafeArg()); void BURP_msg_put(bool, USHORT, const MsgFormat::SafeArg& arg); const int BURP_MSG_GET_SIZE = 128; // Use it for buffers passed to this function. diff --git a/src/burp/burpswi.h b/src/burp/burpswi.h index 609f928614..57da4f4a1b 100644 --- a/src/burp/burpswi.h +++ b/src/burp/burpswi.h @@ -102,6 +102,9 @@ const int IN_SW_BURP_REPLICA = 53; // replica mode 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_SKIP_SCHEMA_DATA = 56; // skip data from schema +const int IN_SW_BURP_INCLUDE_SCHEMA_DATA = 57; // backup data from schemas + /**************************************************************************/ static const char* const BURP_SW_MODE_NONE = "NONE"; @@ -186,8 +189,12 @@ static const Switches::in_sw_tab_t reference_burp_in_sw_table[] = {IN_SW_BURP_S, 0, "SKIP_BAD_DATA", 0, 0, 0, false, false, 0, 4, NULL, boRestore}, {IN_SW_BURP_SE, 0, "SERVICE", 0, 0, 0, false, false, 277, 2, NULL, boGeneral}, // msg 277: @1SE(RVICE) use services manager + {IN_SW_BURP_SKIP_SCHEMA_DATA, isc_spb_res_skip_schema_data, "SKIP_SCHEMA_DATA", 0, 0, 0, false, false, 415, 13, NULL, boGeneral}, + // msg 415: @1SKIP_SCHEMA_DATA skip data for schema {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_SCHEMA_DATA, isc_spb_res_include_schema_data, "INCLUDE_SCHEMA_DATA", 0, 0, 0, false, false, 416, 16, NULL, boGeneral}, + // msg 416: @1INCLUDE_SCHEMA_D(ATA) backup data of schemas(s) {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}, diff --git a/src/burp/restore.epp b/src/burp/restore.epp index bdd59a7a19..4b7682cf4f 100644 --- a/src/burp/restore.epp +++ b/src/burp/restore.epp @@ -116,7 +116,7 @@ void decompress(BurpGlobals* tdgbl, UCHAR*, ULONG); void eat_blob(BurpGlobals* tdgbl); void eat_text(BurpGlobals* tdgbl); void eat_text2(BurpGlobals* tdgbl); -burp_rel* find_relation(BurpGlobals* tdgbl, const TEXT*); +burp_rel* find_relation(BurpGlobals* tdgbl, const QualifiedMetaString&); void fix_security_class_name(BurpGlobals* tdgbl, TEXT* sec_class, bool is_field); // CVC: when do these functions return false indeed??? // get_acl and get_index are the only exceptions but ironically their @@ -145,13 +145,14 @@ SLONG get_int32(BurpGlobals* tdgbl); SINT64 get_int64(BurpGlobals* tdgbl); bool get_package(BurpGlobals* tdgbl); bool get_procedure(BurpGlobals* tdgbl); -bool get_procedure_prm(BurpGlobals* tdgbl, GDS_NAME, GDS_NAME); +bool get_procedure_prm(BurpGlobals* tdgbl, const QualifiedMetaString&); bool get_publication(BurpGlobals* tdgbl); bool get_pub_table(BurpGlobals* tdgbl); bool get_ref_constraint(BurpGlobals* tdgbl); bool get_rel_constraint(BurpGlobals* tdgbl); bool get_relation(BurpGlobals* tdgbl, Coordinator* coord, RestoreRelationTask* task); bool get_relation_data(BurpGlobals* tdgbl, Coordinator* coord, RestoreRelationTask* task); +bool get_schema(BurpGlobals* tdgbl); bool get_sql_roles(BurpGlobals* tdgbl); bool get_mapping(BurpGlobals* tdgbl); bool get_db_creator(BurpGlobals* tdgbl); @@ -174,8 +175,8 @@ USHORT recompute_length(BurpGlobals* tdgbl, burp_rel*); #endif bool restore(BurpGlobals* tdgbl, Firebird::IProvider*, const TEXT*, const TEXT*); void restore_security_class(BurpGlobals* tdgbl, const TEXT*, const TEXT*); -USHORT get_view_base_relation_count(BurpGlobals* tdgbl, const TEXT*, USHORT, bool* error); -void store_blr_gen_id(BurpGlobals* tdgbl, const TEXT* gen_name, SINT64 value, SINT64 initial_value, +USHORT get_view_base_relation_count(BurpGlobals* tdgbl, const QualifiedMetaString&, USHORT, bool* error); +void store_blr_gen_id(BurpGlobals* tdgbl, const QualifiedMetaString& gen_name, SINT64 value, SINT64 initial_value, const ISC_QUAD* gen_desc, const char* secclass, const char* ownername, fb_sysflag sysFlag, SLONG increment); void update_global_field(BurpGlobals* tdgbl); @@ -264,21 +265,22 @@ const int USER_PRIV_FIELD_NAME = 32; const int USER_PRIV_USER_TYPE = 64; const int USER_PRIV_OBJECT_TYPE = 128; -static inline void collect_missing_privs(BurpGlobals* tdgbl, USHORT type, const GDS_NAME name, bool hasSecClass) +static inline void collect_missing_privs(BurpGlobals* tdgbl, USHORT type, const QualifiedMetaString& name, + bool hasSecClass) { burp_meta_obj* object = (burp_meta_obj*) BURP_alloc_zero(sizeof(burp_meta_obj)); object->obj_next = tdgbl->miss_privs; object->obj_type = type; - strcpy(object->obj_name, name); + object->obj_name = name; object->obj_class = hasSecClass; tdgbl->miss_privs = object; } } // namespace -void activateIndex(BurpGlobals* tdgbl, const char* index_name) +void activateIndex(BurpGlobals* tdgbl, const QualifiedMetaString& indexName) { - BURP_verbose(285, index_name); + BURP_verbose(285, indexName.toQuotedString().c_str()); // activating and creating deferred index %s bool fError = false; @@ -288,16 +290,19 @@ void activateIndex(BurpGlobals* tdgbl, const char* index_name) START_TRANSACTION activateIndexTran; FOR (TRANSACTION_HANDLE activateIndexTran REQUEST_HANDLE tdgbl->handles_activateIndex_req_handle1) - IND1 IN RDB$INDICES WITH IND1.RDB$INDEX_NAME EQ index_name + IND1 IN RDB$INDICES + WITH IND1.RDB$SCHEMA_NAME EQUIV NULLIF(indexName.schema.c_str(), '') AND + IND1.RDB$INDEX_NAME EQ indexName.object.c_str() + { MODIFY IND1 USING IND1.RDB$INDEX_INACTIVE = FALSE; - END_MODIFY; - END_FOR; - + END_MODIFY + } + END_FOR ON_ERROR fError = true; fb_utils::copyStatus(&local_status_vector, isc_status); - END_ERROR; + END_ERROR if (!fError) { @@ -305,19 +310,19 @@ void activateIndex(BurpGlobals* tdgbl, const char* index_name) ON_ERROR fError = true; fb_utils::copyStatus(&local_status_vector, isc_status); - END_ERROR; + END_ERROR } if (fError) { - BURP_print(false, 173, index_name); + BURP_print(false, 173, indexName.toQuotedString().c_str()); BURP_print_status(false, &local_status_vector); tdgbl->flag_on_line = false; ROLLBACK activateIndexTran; ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } } @@ -335,7 +340,7 @@ int RESTORE_restore (const TEXT* file_name, const TEXT* database_name) **************************************/ Firebird::IRequest* req_handle1 = nullptr; Firebird::IRequest* req_handle3 = nullptr; - BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name; + QualifiedMetaString indexName; Firebird::DispatcherPtr provider; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -349,6 +354,7 @@ int RESTORE_restore (const TEXT* file_name, const TEXT* database_name) COMMIT; ON_ERROR + { // Fix for bug_no 8055: // don't throw away the database just because an index // could not be made @@ -359,18 +365,21 @@ int RESTORE_restore (const TEXT* file_name, const TEXT* database_name) { case isc_sort_mem_err: case isc_no_dup: - strcpy(index_name, (TEXT *)tdgbl->status_vector[3]); + indexName = QualifiedMetaString::parseSchemaObject((TEXT*) tdgbl->status_vector[3]); BURP_print_status(false, &tdgbl->status_vector); FOR (REQUEST_HANDLE req_handle3) - IDX IN RDB$INDICES WITH IDX.RDB$INDEX_NAME EQ index_name - - BURP_verbose(243, index_name); + IDX IN RDB$INDICES + WITH IDX.RDB$SCHEMA_NAME EQUIV NULLIF(indexName.schema.c_str(), '') AND + IDX.RDB$INDEX_NAME EQ indexName.object.c_str() + { + BURP_verbose(243, indexName.toQuotedString().c_str()); MODIFY IDX USING IDX.RDB$INDEX_INACTIVE = TRUE; END_MODIFY; - BURP_print(false, 240, index_name); + BURP_print(false, 240, indexName.toQuotedString().c_str()); // msg 240 Index \"%s\" failed to activate because: - if ( error_code == isc_no_dup ) + + if (error_code == isc_no_dup) { BURP_print(false, 241); // msg 241 The unique index has duplicate values or NULLs @@ -384,12 +393,16 @@ int RESTORE_restore (const TEXT* file_name, const TEXT* database_name) BURP_print(false, 245); // msg 245 Set the TMP environment variable to a directory on a filesystem that does have enough space, and activate index with } - BURP_print(false, 243, index_name); + + BURP_print(false, 243, indexName.toQuotedString().c_str()); // msg 243 ALTER INDEX \"%s\" ACTIVE; - END_FOR; + } + END_FOR + // don't bring the database on-line tdgbl->flag_on_line = false; break; + default: general_on_error (); break; @@ -399,7 +412,8 @@ int RESTORE_restore (const TEXT* file_name, const TEXT* database_name) continue; END_ERROR } - END_ERROR; + } + END_ERROR if (tdgbl->global_trans) { @@ -430,21 +444,25 @@ int RESTORE_restore (const TEXT* file_name, const TEXT* database_name) FOR (REQUEST_HANDLE req_handle1) IDS IN RDB$INDICES WITH IDS.RDB$INDEX_INACTIVE EQ DEFERRED_ACTIVE AND IDS.RDB$FOREIGN_KEY MISSING + { + if (!IDS.RDB$SCHEMA_NAME.NULL) + indexName.schema = IDS.RDB$SCHEMA_NAME; - MISC_terminate(IDS.RDB$INDEX_NAME, index_name, - (ULONG)MISC_symbol_length(IDS.RDB$INDEX_NAME, sizeof(IDS.RDB$INDEX_NAME)), - sizeof(index_name)); + indexName.object = IDS.RDB$INDEX_NAME; - activateIndex(tdgbl, index_name); - END_FOR; + activateIndex(tdgbl, indexName); + } + END_FOR ON_ERROR general_on_error (); - END_ERROR; + END_ERROR + MISC_release_request_silent(req_handle1); + COMMIT; ON_ERROR general_on_error (); - END_ERROR; + END_ERROR EXEC SQL SET TRANSACTION ISOLATION LEVEL READ COMMITTED NO_AUTO_UNDO; if (gds_status->hasData()) @@ -463,23 +481,27 @@ int RESTORE_restore (const TEXT* file_name, const TEXT* database_name) CNST IN RDB$RELATION_CONSTRAINTS CROSS IDS IN RDB$INDICES WITH CNST.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY AND + CNST.RDB$SCHEMA_NAME EQUIV IDS.RDB$SCHEMA_NAME AND CNST.RDB$INDEX_NAME EQ IDS.RDB$INDEX_NAME AND IDS.RDB$INDEX_INACTIVE EQ DEFERRED_ACTIVE + { + if (!IDS.RDB$SCHEMA_NAME.NULL) + indexName.schema = IDS.RDB$SCHEMA_NAME; - MISC_terminate(IDS.RDB$INDEX_NAME, index_name, - (ULONG) MISC_symbol_length(IDS.RDB$INDEX_NAME, sizeof(IDS.RDB$INDEX_NAME)), - sizeof(index_name)); + indexName.object = IDS.RDB$INDEX_NAME; - activateIndex(tdgbl, index_name); - END_FOR; + activateIndex(tdgbl, indexName); + } + END_FOR ON_ERROR general_on_error (); - END_ERROR; + END_ERROR MISC_release_request_silent(req_handle1); + COMMIT; ON_ERROR general_on_error (); - END_ERROR; + END_ERROR } EXEC SQL SET TRANSACTION ISOLATION LEVEL READ COMMITTED NO_AUTO_UNDO; @@ -989,6 +1011,9 @@ void create_database(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TE dpb.insertInt(isc_dpb_page_size, page_size & 0xff00); dpb.insertString(isc_dpb_gbak_attach, FB_VERSION, fb_strlen(FB_VERSION)); + if (tdgbl->RESTORE_format >= 12) + dpb.insertTag(isc_dpb_gbak_restore_has_schema); + if (sweep_interval != MAX_ULONG) { dpb.insertInt(isc_dpb_sweep_interval, sweep_interval); @@ -1044,10 +1069,11 @@ void create_database(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TE dpb.insertInt(isc_dpb_parallel_workers, tdgbl->gbl_sw_par_workers); dpb.insertByte(isc_dpb_shutdown, isc_dpb_shut_multi); } + dpb.insertInt(isc_dpb_shutdown_delay, 0); dpb.insertInt(isc_dpb_overwrite, tdgbl->gbl_sw_overwrite); - dpb.insertByte(isc_dpb_no_db_triggers, 1); + dpb.insertString(isc_dpb_search_path, SYSTEM_SCHEMA, fb_strlen(SYSTEM_SCHEMA)); FbLocalStatus status_vector; @@ -1356,7 +1382,7 @@ void eat_text2(BurpGlobals* tdgbl) MVOL_skip_block(tdgbl, len); } -burp_rel* find_relation(BurpGlobals* tdgbl, const TEXT* name) +burp_rel* find_relation(BurpGlobals* tdgbl, const QualifiedMetaString& name) { /************************************** * @@ -1373,14 +1399,11 @@ burp_rel* find_relation(BurpGlobals* tdgbl, const TEXT* name) // Why isn't strcmp used here? for (burp_rel* relation = tdgbl->relations; relation; relation = relation->rel_next) { - for (const TEXT* p = relation->rel_name, *q = name; *p == *q; p++, q++) - { - if (!*p) - return relation; - } + if (relation->rel_name == name) + return relation; } - BURP_error_redirect(NULL, 35, SafeArg() << name); + BURP_error_redirect(NULL, 35, SafeArg() << name.toQuotedString().c_str()); // msg 35 can't find relation %s return NULL; @@ -1434,8 +1457,18 @@ void fix_security_class_name(BurpGlobals* tdgbl, TEXT* sec_class, bool is_field) add_byte(blr, blr_begin); add_byte(blr, blr_assignment); - add_byte(blr, blr_gen_id); - add_string(blr, SQL_SECCLASS_GENERATOR); + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + { + add_byte(blr, blr_gen_id3); + add_string(blr, SYSTEM_SCHEMA); + add_string(blr, SQL_SECCLASS_GENERATOR); + add_byte(blr, 1); + } + else + { + add_byte(blr, blr_gen_id); + add_string(blr, SQL_SECCLASS_GENERATOR); + } add_byte(blr, blr_literal); add_byte(blr, blr_int64); @@ -1884,8 +1917,15 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer) add_byte(blr, field->fld_type); } + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + { + add_byte(blr, isc_sdl_schema); + add_string(blr, + (relation->rel_name.schema.hasData() ? relation->rel_name.schema.c_str() : PUBLIC_SCHEMA)); + } + add_byte(blr, isc_sdl_relation); - add_string(blr, relation->rel_name); + add_string(blr, relation->rel_name.object.c_str()); add_byte(blr, isc_sdl_field); add_string(blr, field->fld_name); @@ -2119,8 +2159,14 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer) add_byte(blr, field->fld_type); } + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + { + add_byte(blr, isc_sdl_schema); + add_string(blr, (relation->rel_name.schema.hasData() ? relation->rel_name.schema.c_str() : PUBLIC_SCHEMA)); + } + add_byte(blr, isc_sdl_relation); - add_string(blr, relation->rel_name); + add_string(blr, relation->rel_name.object.c_str()); add_byte(blr, isc_sdl_field); add_string(blr, field->fld_name); @@ -2432,6 +2478,7 @@ bool get_character_set(BurpGlobals* tdgbl) { }; + QualifiedMetaString name; att_type attribute; scan_attr_t scan_next_attr; @@ -2439,14 +2486,19 @@ bool get_character_set(BurpGlobals* tdgbl) { if (tdgbl->runtimeODS >= DB_VERSION_DDL12) { - GDS_NAME charset_name; + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + name.schema = PUBLIC_SCHEMA; + bool securityClass = false; STORE (REQUEST_HANDLE tdgbl->handles_get_character_sets_req_handle1) X IN RDB$CHARACTER_SETS + { + X.RDB$SCHEMA_NAME.NULL = TRUE; X.RDB$CHARACTER_SET_NAME.NULL = TRUE; X.RDB$FORM_OF_USE.NULL = TRUE; X.RDB$NUMBER_OF_CHARACTERS.NULL = TRUE; + X.RDB$DEFAULT_COLLATE_SCHEMA_NAME.NULL = TRUE; X.RDB$DEFAULT_COLLATE_NAME.NULL = TRUE; X.RDB$CHARACTER_SET_ID.NULL = TRUE; X.RDB$SYSTEM_FLAG = 0; @@ -2462,10 +2514,17 @@ bool get_character_set(BurpGlobals* tdgbl) { switch (attribute) { + case att_charset_schema_name: + X.RDB$SCHEMA_NAME.NULL = FALSE; + GET_TEXT(X.RDB$SCHEMA_NAME); + name.schema = X.RDB$SCHEMA_NAME; + break; + case att_charset_name: X.RDB$CHARACTER_SET_NAME.NULL = FALSE; GET_TEXT(X.RDB$CHARACTER_SET_NAME); - BURP_verbose (msgVerbose_restore_charset, X.RDB$CHARACTER_SET_NAME); + name.object = X.RDB$CHARACTER_SET_NAME; + BURP_verbose(msgVerbose_restore_charset, name.toQuotedString().c_str()); break; case att_charset_form: @@ -2478,6 +2537,11 @@ bool get_character_set(BurpGlobals* tdgbl) X.RDB$NUMBER_OF_CHARACTERS = (USHORT) get_int32(tdgbl); break; + case att_charset_coll_schema_name: + X.RDB$DEFAULT_COLLATE_SCHEMA_NAME.NULL = FALSE; + GET_TEXT(X.RDB$DEFAULT_COLLATE_SCHEMA_NAME); + break; + case att_charset_coll: X.RDB$DEFAULT_COLLATE_NAME.NULL = FALSE; GET_TEXT(X.RDB$DEFAULT_COLLATE_NAME); @@ -2540,20 +2604,19 @@ bool get_character_set(BurpGlobals* tdgbl) if (X.RDB$CHARACTER_SET_ID.NULL && !X.RDB$DEFAULT_COLLATE_NAME.NULL && !X.RDB$CHARACTER_SET_NAME.NULL) { - tdgbl->defaultCollations.add( - Firebird::Pair >( - X.RDB$CHARACTER_SET_NAME, X.RDB$DEFAULT_COLLATE_NAME)); + tdgbl->defaultCollations.put( + QualifiedMetaString(X.RDB$CHARACTER_SET_NAME, X.RDB$SCHEMA_NAME), + QualifiedMetaString(X.RDB$DEFAULT_COLLATE_NAME, X.RDB$DEFAULT_COLLATE_SCHEMA_NAME)); + throw AbortException(); // prevent the STORE } - - strcpy(charset_name, X.RDB$CHARACTER_SET_NAME); - - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR - collect_missing_privs(tdgbl, obj_charset, charset_name, securityClass); + collect_missing_privs(tdgbl, obj_charset, name, securityClass); } else { @@ -2578,7 +2641,8 @@ bool get_character_set(BurpGlobals* tdgbl) case att_charset_name: X.RDB$CHARACTER_SET_NAME.NULL = FALSE; GET_TEXT(X.RDB$CHARACTER_SET_NAME); - BURP_verbose (msgVerbose_restore_charset, X.RDB$CHARACTER_SET_NAME); + name.object = X.RDB$CHARACTER_SET_NAME; + BURP_verbose(msgVerbose_restore_charset, name.toQuotedString().c_str()); break; case att_charset_form: @@ -2639,9 +2703,10 @@ bool get_character_set(BurpGlobals* tdgbl) if (X.RDB$CHARACTER_SET_ID.NULL && !X.RDB$DEFAULT_COLLATE_NAME.NULL && !X.RDB$CHARACTER_SET_NAME.NULL) { - tdgbl->defaultCollations.add( - Firebird::Pair >( - X.RDB$CHARACTER_SET_NAME, X.RDB$DEFAULT_COLLATE_NAME)); + tdgbl->defaultCollations.put( + QualifiedMetaString(X.RDB$CHARACTER_SET_NAME), + QualifiedMetaString(X.RDB$DEFAULT_COLLATE_NAME)); + throw AbortException(); // prevent the STORE } @@ -2675,6 +2740,8 @@ bool get_chk_constraint(BurpGlobals* tdgbl) STORE (REQUEST_HANDLE tdgbl->handles_get_chk_constraint_req_handle1) X IN RDB$CHECK_CONSTRAINTS + { + X.RDB$SCHEMA_NAME.NULL = TRUE; X.RDB$CONSTRAINT_NAME.NULL = TRUE; X.RDB$TRIGGER_NAME.NULL = TRUE; @@ -2683,6 +2750,11 @@ bool get_chk_constraint(BurpGlobals* tdgbl) { switch (attribute) { + case att_chk_schema_name: + X.RDB$SCHEMA_NAME.NULL = FALSE; + GET_TEXT(X.RDB$SCHEMA_NAME); + break; + case att_chk_constraint_name: X.RDB$CONSTRAINT_NAME.NULL = FALSE; GET_TEXT(X.RDB$CONSTRAINT_NAME); @@ -2699,10 +2771,11 @@ bool get_chk_constraint(BurpGlobals* tdgbl) break; } } - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR return true; } @@ -2719,16 +2792,18 @@ bool get_collation(BurpGlobals* tdgbl) * Restore data for user defined collations * **************************************/ + QualifiedMetaString name; att_type attribute; scan_attr_t scan_next_attr; if (tdgbl->runtimeODS >= DB_VERSION_DDL12) { - GDS_NAME coll_name; bool securityClass = false; STORE (REQUEST_HANDLE tdgbl->handles_get_collation_req_handle1) X IN RDB$COLLATIONS + { + X.RDB$SCHEMA_NAME.NULL = TRUE; X.RDB$COLLATION_NAME.NULL = TRUE; X.RDB$COLLATION_ID.NULL = TRUE; X.RDB$CHARACTER_SET_ID.NULL = TRUE; @@ -2747,11 +2822,17 @@ bool get_collation(BurpGlobals* tdgbl) { switch (attribute) { + case att_coll_schema_name: + X.RDB$SCHEMA_NAME.NULL = FALSE; + GET_TEXT(X.RDB$SCHEMA_NAME); + name.schema = X.RDB$SCHEMA_NAME; + break; case att_coll_name: X.RDB$COLLATION_NAME.NULL = FALSE; GET_TEXT(X.RDB$COLLATION_NAME); - BURP_verbose(msgVerbose_restore_collation, X.RDB$COLLATION_NAME); + name.object = X.RDB$COLLATION_NAME; + BURP_verbose(msgVerbose_restore_collation, name.toQuotedString().c_str()); break; case att_coll_id: @@ -2837,21 +2918,20 @@ bool get_collation(BurpGlobals* tdgbl) break; } } - - strcpy(coll_name, X.RDB$COLLATION_NAME); - - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR - collect_missing_privs(tdgbl, obj_collation, coll_name, securityClass); + collect_missing_privs(tdgbl, obj_collation, name, securityClass); } else if (tdgbl->runtimeODS >= DB_VERSION_DDL11) { // This includes DDL11_0 that doesn't know to ignore unknown system fields. STORE (REQUEST_HANDLE tdgbl->handles_get_collation_req_handle1) X IN RDB$COLLATIONS + { X.RDB$COLLATION_NAME.NULL = TRUE; X.RDB$COLLATION_ID.NULL = TRUE; X.RDB$CHARACTER_SET_ID.NULL = TRUE; @@ -2872,7 +2952,8 @@ bool get_collation(BurpGlobals* tdgbl) case att_coll_name: X.RDB$COLLATION_NAME.NULL = FALSE; GET_TEXT(X.RDB$COLLATION_NAME); - BURP_verbose(msgVerbose_restore_collation, X.RDB$COLLATION_NAME); + name.object = X.RDB$COLLATION_NAME; + BURP_verbose(msgVerbose_restore_collation, name.toQuotedString().c_str()); break; case att_coll_id: @@ -2944,15 +3025,17 @@ bool get_collation(BurpGlobals* tdgbl) break; } } - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR } else { STORE (REQUEST_HANDLE tdgbl->handles_get_collation_req_handle1) X IN RDB$COLLATIONS + { X.RDB$COLLATION_NAME.NULL = TRUE; X.RDB$COLLATION_ID.NULL = TRUE; X.RDB$CHARACTER_SET_ID.NULL = TRUE; @@ -2973,7 +3056,8 @@ bool get_collation(BurpGlobals* tdgbl) case att_coll_name: X.RDB$COLLATION_NAME.NULL = FALSE; GET_TEXT(X.RDB$COLLATION_NAME); - BURP_verbose(msgVerbose_restore_collation, X.RDB$COLLATION_NAME); + name.object = X.RDB$COLLATION_NAME; + BURP_verbose(msgVerbose_restore_collation, name.toQuotedString().c_str()); break; case att_coll_id: @@ -3039,10 +3123,11 @@ bool get_collation(BurpGlobals* tdgbl) break; } } - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR } return true; @@ -3052,11 +3137,12 @@ bool get_collation(BurpGlobals* tdgbl) static void check_data_error(BurpGlobals* tdgbl, IStatus* status_vector, const burp_rel* relation) { ISC_STATUS code = status_vector->getErrors()[1]; + if (code == isc_not_valid) { if (tdgbl->gbl_sw_incremental) { - BURP_print(false, 138, relation->rel_name); + BURP_print(false, 138, relation->rel_name.toQuotedString().c_str()); // msg 138 validation error on field in relation %s BURP_print_status (false, status_vector); } @@ -3069,7 +3155,7 @@ static void check_data_error(BurpGlobals* tdgbl, IStatus* status_vector, const b if (tdgbl->gbl_sw_incremental) { // msg 114 restore failed for record in relation %s - BURP_print(false, 114, relation->rel_name); + BURP_print(false, 114, relation->rel_name.toQuotedString().c_str()); BURP_print_status(false, status_vector, 342); // isc_gbak_invalid_data } @@ -3080,7 +3166,7 @@ static void check_data_error(BurpGlobals* tdgbl, IStatus* status_vector, const b { if (tdgbl->gbl_sw_incremental && isc_sqlcode(status_vector->getErrors()) != -902) { - BURP_print (false, 114, relation->rel_name); + BURP_print (false, 114, relation->rel_name.toQuotedString().c_str()); // msg 114 restore failed for record in relation %s BURP_print_status(false, status_vector); } @@ -3092,12 +3178,12 @@ static void check_data_error(BurpGlobals* tdgbl, IStatus* status_vector, const b static void commit_relation_data(BurpGlobals* tdgbl, burp_rel* relation) { - BURP_verbose(72, relation->rel_name); + BURP_verbose(72, relation->rel_name.toQuotedString().c_str()); // msg 72 committing data for relation %s COMMIT // existing ON_ERROR continues past error, beck ON_ERROR - + { // Fix for bug_no 8055: // don't throw away the database just because an index // could not be made @@ -3109,51 +3195,58 @@ static void commit_relation_data(BurpGlobals* tdgbl, burp_rel* relation) while (error_code = tdgbl->status_vector[1]) { Firebird::IRequest* req_handle = 0; - BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name; + QualifiedMetaString indexName; switch (error_code) { case isc_sort_mem_err: case isc_no_dup: - strcpy(index_name, (TEXT *)tdgbl->status_vector[3]); + indexName = QualifiedMetaString::parseSchemaObject((TEXT*) tdgbl->status_vector[3]); + indexName.object = (TEXT*) tdgbl->status_vector[3]; BURP_print_status(false, &tdgbl->status_vector); FOR(REQUEST_HANDLE req_handle) IDX IN RDB$INDICES - WITH IDX.RDB$INDEX_NAME EQ index_name + WITH IDX.RDB$SCHEMA_NAME EQUIV NULLIF(indexName.schema.c_str(), '') AND + IDX.RDB$INDEX_NAME EQ indexName.object.c_str() { MODIFY IDX USING + { IDX.RDB$INDEX_INACTIVE = TRUE; - BURP_print(false, 240, index_name); - // msg 240 Index \"%s\" failed to activate because: - if (error_code == isc_no_dup) - { - BURP_print(false, 241); - // msg 241 The unique index has duplicate values or NULLs - BURP_print(false, 242); - // msg 242 Delete or Update duplicate values or NULLs, and activate index with + BURP_print(false, 240, indexName.toQuotedString().c_str()); + // msg 240 Index \"%s\" failed to activate because: + + if (error_code == isc_no_dup) + { + BURP_print(false, 241); + // msg 241 The unique index has duplicate values or NULLs + BURP_print(false, 242); + // msg 242 Delete or Update duplicate values or NULLs, and activate index with + } + else + { + BURP_print(false, 244); + // msg 244 Not enough disk space to create the sort file for an index + BURP_print(false, 245); + // msg 245 Set the TMP environment variable to a directory on a filesystem that does have enough space, and activate index with + } + + BURP_print(false, 243, indexName.toQuotedString().c_str()); + // msg 243 ALTER INDEX \"%s\" ACTIVE } - else - { - BURP_print(false, 244); - // msg 244 Not enough disk space to create the sort file for an index - BURP_print(false, 245); - // msg 245 Set the TMP environment variable to a directory on a filesystem that does have enough space, and activate index with - } - BURP_print(false, 243, index_name); - // msg 243 ALTER INDEX \"%s\" ACTIVE - END_MODIFY; + END_MODIFY } - END_FOR; + END_FOR // commit one more time COMMIT - ON_ERROR + ON_ERROR continue; END_ERROR - break; + break; + default: - BURP_print(false, 69, relation->rel_name); + BURP_print(false, 69, relation->rel_name.toQuotedString().c_str()); // msg 69 commit failed on relation %s BURP_print_status(false, &tdgbl->status_vector); ROLLBACK; @@ -3163,13 +3256,14 @@ static void commit_relation_data(BurpGlobals* tdgbl, burp_rel* relation) break; } // end of switch } // end of while - END_ERROR; + } + END_ERROR set_transaction(tdgbl); } // We have a corrupt backup, save the restore process from becoming useless. -void fix_exception(BurpGlobals* tdgbl, const char* exc_name, scan_attr_t& scan_next_attr, +void fix_exception(BurpGlobals* tdgbl, const QualifiedMetaString& name, scan_attr_t& scan_next_attr, const att_type attribute, att_type& failed_attrib, UCHAR*& msg_ptr, ULONG& l2, bool& msg_seen) { if (msg_seen && (tdgbl->RESTORE_format == 7 || tdgbl->RESTORE_format == 8)) @@ -3177,7 +3271,7 @@ void fix_exception(BurpGlobals* tdgbl, const char* exc_name, scan_attr_t& scan_n if (!failed_attrib) { failed_attrib = attribute; - BURP_print(false, 313, SafeArg() << failed_attrib << exc_name); + BURP_print(false, 313, SafeArg() << failed_attrib << name.toQuotedString().c_str()); } // Notice we use 1021 instead of 1023 because this is the maximum length @@ -3230,7 +3324,7 @@ void get_data(BurpGlobals* tdgbl, burp_rel* relation, WriteRelationReq* req) RCRD_LENGTH length = req->getDataLength(); UCHAR* buffer = req->getData(); - // BURP_verbose (124, relation->rel_name); // msg 124 restoring data for relation %s + // BURP_verbose (124, relation->rel_name.toQuotedString().c_str()); // msg 124 restoring data for relation %s lstring data; data.lstr_allocated = 0; @@ -3395,18 +3489,22 @@ bool get_exception(BurpGlobals* tdgbl) * Reconstruct a exception. * **************************************/ + QualifiedMetaString name; + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + name.schema = PUBLIC_SCHEMA; + att_type attribute; - TEXT temp[GDS_NAME_LEN]; ULONG l2 = 0; scan_attr_t scan_next_attr; if (tdgbl->runtimeODS >= DB_VERSION_DDL12) { - GDS_NAME exception_name; bool securityClass = false; STORE (REQUEST_HANDLE tdgbl->handles_get_exception_req_handle1) X IN RDB$EXCEPTIONS + { + X.RDB$SCHEMA_NAME.NULL = TRUE; X.RDB$EXCEPTION_NAME.NULL = TRUE; X.RDB$DESCRIPTION.NULL = TRUE; X.RDB$MESSAGE.NULL = TRUE; @@ -3424,22 +3522,28 @@ bool get_exception(BurpGlobals* tdgbl) { switch (attribute) { + case att_exception_schema_name: + GET_TEXT(X.RDB$SCHEMA_NAME); + X.RDB$SCHEMA_NAME.NULL = FALSE; + name.schema = X.RDB$SCHEMA_NAME; + break; + case att_exception_name: if (!X.RDB$EXCEPTION_NAME.NULL) - BURP_error(311, true, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_error(311, true, SafeArg() << attribute << name.toQuotedString().c_str()); else { - const ULONG l = GET_TEXT(X.RDB$EXCEPTION_NAME); + GET_TEXT(X.RDB$EXCEPTION_NAME); X.RDB$EXCEPTION_NAME.NULL = FALSE; - MISC_terminate (X.RDB$EXCEPTION_NAME, temp, l, sizeof(temp)); - BURP_verbose (199, temp); + name.object = X.RDB$EXCEPTION_NAME; + BURP_verbose(199, name.toQuotedString().c_str()); // msg 199 restoring exception %s } break; case att_exception_description: if (!X.RDB$DESCRIPTION.NULL) - BURP_error(311, true, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_error(311, true, SafeArg() << attribute << name.toQuotedString().c_str()); else { msg_seen = false; @@ -3450,7 +3554,7 @@ bool get_exception(BurpGlobals* tdgbl) case att_exception_description2: if (!X.RDB$DESCRIPTION.NULL) - BURP_error(311, true, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_error(311, true, SafeArg() << attribute << name.toQuotedString().c_str()); else { msg_seen = false; @@ -3461,11 +3565,11 @@ bool get_exception(BurpGlobals* tdgbl) case att_exception_msg: if (msg_seen) - BURP_error(311, true, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_error(311, true, SafeArg() << attribute << name.toQuotedString().c_str()); else if (!X.RDB$MESSAGE.NULL) { msg_seen = true; - BURP_print(false, 312, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_print(false, 312, SafeArg() << attribute << name.toQuotedString().c_str()); eat_text(tdgbl); } else @@ -3479,10 +3583,10 @@ bool get_exception(BurpGlobals* tdgbl) case att_exception_msg2: if (msg_seen) - BURP_error(311, true, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_error(311, true, SafeArg() << attribute << name.toQuotedString().c_str()); else if (!X.RDB$MESSAGE.NULL) { - BURP_print(false, 312, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_print(false, 312, SafeArg() << attribute << name.toQuotedString().c_str()); eat_text2(tdgbl); } else @@ -3495,7 +3599,7 @@ bool get_exception(BurpGlobals* tdgbl) case att_exception_security_class: if (!X.RDB$SECURITY_CLASS.NULL) { - BURP_error(311, true, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_error(311, true, SafeArg() << attribute << name.toQuotedString().c_str()); } else { @@ -3509,7 +3613,7 @@ bool get_exception(BurpGlobals* tdgbl) } else { - fix_exception(tdgbl, X.RDB$EXCEPTION_NAME, scan_next_attr, attribute, + fix_exception(tdgbl, name, scan_next_attr, attribute, failed_attrib, msg_ptr, l2, msg_seen); } } @@ -3518,7 +3622,7 @@ bool get_exception(BurpGlobals* tdgbl) case att_exception_owner_name: if (!X.RDB$OWNER_NAME.NULL) { - BURP_error(311, true, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_error(311, true, SafeArg() << attribute << name.toQuotedString().c_str()); } else { @@ -3530,7 +3634,7 @@ bool get_exception(BurpGlobals* tdgbl) } else { - fix_exception(tdgbl, X.RDB$EXCEPTION_NAME, scan_next_attr, attribute, + fix_exception(tdgbl, name, scan_next_attr, attribute, failed_attrib, msg_ptr, l2, msg_seen); } } @@ -3538,20 +3642,18 @@ bool get_exception(BurpGlobals* tdgbl) default: // do we have a corrupt backup? - fix_exception(tdgbl, X.RDB$EXCEPTION_NAME, scan_next_attr, attribute, + fix_exception(tdgbl, name, scan_next_attr, attribute, failed_attrib, msg_ptr, l2, msg_seen); break; } } - - strcpy(exception_name, X.RDB$EXCEPTION_NAME); - - END_STORE; + } + END_STORE ON_ERROR general_on_error (); END_ERROR; - collect_missing_privs(tdgbl, obj_exception, exception_name, securityClass); + collect_missing_privs(tdgbl, obj_exception, name, securityClass); } else { @@ -3577,20 +3679,20 @@ bool get_exception(BurpGlobals* tdgbl) { case att_exception_name: if (!X.RDB$EXCEPTION_NAME.NULL) - BURP_error(311, true, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_error(311, true, SafeArg() << attribute << name.toQuotedString().c_str()); else { - const ULONG l = GET_TEXT(X.RDB$EXCEPTION_NAME); + GET_TEXT(X.RDB$EXCEPTION_NAME); X.RDB$EXCEPTION_NAME.NULL = FALSE; - MISC_terminate (X.RDB$EXCEPTION_NAME, temp, l, sizeof(temp)); - BURP_verbose (199, temp); + name.object = X.RDB$EXCEPTION_NAME; + BURP_verbose(199, name.toQuotedString().c_str()); // msg 199 restoring exception %s } break; case att_exception_description: if (!X.RDB$DESCRIPTION.NULL) - BURP_error(311, true, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_error(311, true, SafeArg() << attribute << name.toQuotedString().c_str()); else { msg_seen = false; @@ -3601,7 +3703,7 @@ bool get_exception(BurpGlobals* tdgbl) case att_exception_description2: if (!X.RDB$DESCRIPTION.NULL) - BURP_error(311, true, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_error(311, true, SafeArg() << attribute << name.toQuotedString().c_str()); else { msg_seen = false; @@ -3612,11 +3714,11 @@ bool get_exception(BurpGlobals* tdgbl) case att_exception_msg: if (msg_seen) - BURP_error(311, true, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_error(311, true, SafeArg() << attribute << name.toQuotedString().c_str()); else if (!X.RDB$MESSAGE.NULL) { msg_seen = true; - BURP_print(false, 312, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_print(false, 312, SafeArg() << attribute << name.toQuotedString().c_str()); eat_text(tdgbl); } else @@ -3630,10 +3732,10 @@ bool get_exception(BurpGlobals* tdgbl) case att_exception_msg2: if (msg_seen) - BURP_error(311, true, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_error(311, true, SafeArg() << attribute << name.toQuotedString().c_str()); else if (!X.RDB$MESSAGE.NULL) { - BURP_print(false, 312, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_print(false, 312, SafeArg() << attribute << name.toQuotedString().c_str()); eat_text2(tdgbl); } else @@ -3645,7 +3747,7 @@ bool get_exception(BurpGlobals* tdgbl) case att_exception_security_class: if (secclass_seen) - BURP_error(311, true, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_error(311, true, SafeArg() << attribute << name.toQuotedString().c_str()); else { msg_seen = false; @@ -3656,7 +3758,7 @@ bool get_exception(BurpGlobals* tdgbl) } else { - fix_exception(tdgbl, X.RDB$EXCEPTION_NAME, scan_next_attr, attribute, + fix_exception(tdgbl, name, scan_next_attr, attribute, failed_attrib, msg_ptr, l2, msg_seen); } } @@ -3664,7 +3766,7 @@ bool get_exception(BurpGlobals* tdgbl) case att_exception_owner_name: if (ownername_seen) - BURP_error(311, true, SafeArg() << attribute << X.RDB$EXCEPTION_NAME); + BURP_error(311, true, SafeArg() << attribute << name.toQuotedString().c_str()); else { msg_seen = false; @@ -3675,7 +3777,7 @@ bool get_exception(BurpGlobals* tdgbl) } else { - fix_exception(tdgbl, X.RDB$EXCEPTION_NAME, scan_next_attr, attribute, + fix_exception(tdgbl, name, scan_next_attr, attribute, failed_attrib, msg_ptr, l2, msg_seen); } } @@ -3683,7 +3785,7 @@ bool get_exception(BurpGlobals* tdgbl) default: // do we have a corrupt backup? - fix_exception(tdgbl, X.RDB$EXCEPTION_NAME, scan_next_attr, attribute, + fix_exception(tdgbl, name, scan_next_attr, attribute, failed_attrib, msg_ptr, l2, msg_seen); break; } @@ -3738,7 +3840,8 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation) STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_field_req_handle1) X IN RDB$RELATION_FIELDS { - strcpy (X.RDB$RELATION_NAME, relation->rel_name); + strcpy(X.RDB$RELATION_NAME, relation->rel_name.object.c_str()); + X.RDB$SCHEMA_NAME.NULL = TRUE; X.RDB$FIELD_POSITION = 0; X.RDB$VIEW_CONTEXT.NULL = TRUE; X.RDB$BASE_FIELD.NULL = TRUE; @@ -3759,6 +3862,14 @@ 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$FIELD_SOURCE_SCHEMA_NAME.NULL = TRUE; + + if (relation->rel_name.schema.hasData()) + { + strcpy(X.RDB$SCHEMA_NAME, relation->rel_name.schema.c_str()); + X.RDB$SCHEMA_NAME.NULL = FALSE; + } skip_init(&scan_next_attr); while (get_attribute(&attribute, tdgbl) != att_end) @@ -3767,14 +3878,23 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation) { case att_field_name: field->fld_name_length = GET_TEXT(field->fld_name); - BURP_verbose (115, field->fld_name); + BURP_verbose(115, MetaString(field->fld_name).toQuotedString().c_str()); // msg 115 restoring field %s strcpy (X.RDB$FIELD_NAME, field->fld_name); break; + case att_field_schema_name: + GET_TEXT(X.RDB$FIELD_SOURCE_SCHEMA_NAME); + X.RDB$FIELD_SOURCE_SCHEMA_NAME.NULL = FALSE; + field->fld_source.schema = X.RDB$FIELD_SOURCE_SCHEMA_NAME; + + if (field->fld_source.schema.isEmpty() && tdgbl->runtimeODS >= DB_VERSION_DDL14) + field->fld_source.schema = PUBLIC_SCHEMA; + break; + case att_field_source: GET_TEXT(X.RDB$FIELD_SOURCE); - strcpy(field->fld_source, X.RDB$FIELD_SOURCE); + field->fld_source.object = X.RDB$FIELD_SOURCE; break; case att_field_security_class: @@ -3945,7 +4065,7 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation) STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_field_req_handle1) X IN RDB$RELATION_FIELDS { - strcpy (X.RDB$RELATION_NAME, relation->rel_name); + strcpy (X.RDB$RELATION_NAME, relation->rel_name.object.c_str()); X.RDB$FIELD_POSITION = 0; X.RDB$VIEW_CONTEXT.NULL = TRUE; X.RDB$BASE_FIELD.NULL = TRUE; @@ -3971,14 +4091,14 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation) { case att_field_name: field->fld_name_length = GET_TEXT(field->fld_name); - BURP_verbose (115, field->fld_name); + BURP_verbose(115, MetaString(field->fld_name).toQuotedString().c_str()); // msg 115 restoring field %s strcpy (X.RDB$FIELD_NAME, field->fld_name); break; case att_field_source: GET_TEXT(X.RDB$FIELD_SOURCE); - strcpy(field->fld_source, X.RDB$FIELD_SOURCE); + field->fld_source.object = X.RDB$FIELD_SOURCE; break; case att_field_security_class: @@ -4152,12 +4272,19 @@ bool get_field_dimensions(BurpGlobals* tdgbl) STORE (REQUEST_HANDLE tdgbl->handles_get_field_dimensions_req_handle1) X IN RDB$FIELD_DIMENSIONS + { + X.RDB$SCHEMA_NAME.NULL = TRUE; skip_init(&scan_next_attr); while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end) { switch (attribute) { + case att_field_schema_name: + GET_TEXT(X.RDB$SCHEMA_NAME); + X.RDB$SCHEMA_NAME.NULL = FALSE; + break; + case att_field_name: GET_TEXT(X.RDB$FIELD_NAME); break; @@ -4180,10 +4307,11 @@ bool get_field_dimensions(BurpGlobals* tdgbl) break; } } - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR return true; } @@ -4315,7 +4443,7 @@ bool get_filter(BurpGlobals* tdgbl) { case att_filter_name: GET_TEXT(X.RDB$FUNCTION_NAME); - BURP_verbose (117, X.RDB$FUNCTION_NAME); + BURP_verbose(117, MetaString(X.RDB$FUNCTION_NAME).toQuotedString().c_str()); // msg 117 restoring filter %s break; @@ -4371,9 +4499,11 @@ bool get_function(BurpGlobals* tdgbl) * Reconstruct a function. * **************************************/ + QualifiedMetaString name; + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + name.schema = PUBLIC_SCHEMA; + att_type attribute; - TEXT temp[GDS_NAME_LEN * 2]; - SSHORT l; scan_attr_t scan_next_attr; bool existFlag = false; @@ -4382,14 +4512,15 @@ bool get_function(BurpGlobals* tdgbl) if (tdgbl->runtimeODS >= DB_VERSION_DDL12) { - GDS_NAME function_name; bool securityClass = false; STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_function_req_handle1) X IN RDB$FUNCTIONS + { X.RDB$DESCRIPTION.NULL = TRUE; X.RDB$ENGINE_NAME.NULL = TRUE; + X.RDB$SCHEMA_NAME.NULL = TRUE; X.RDB$PACKAGE_NAME.NULL = TRUE; X.RDB$PRIVATE_FLAG.NULL = TRUE; X.RDB$FUNCTION_BLR.NULL = TRUE; @@ -4419,22 +4550,11 @@ bool get_function(BurpGlobals* tdgbl) switch (attribute) { case att_function_name: - { - SSHORT prefixLen = 0; - if (!X.RDB$PACKAGE_NAME.NULL) - { - prefixLen = static_cast(strlen(X.RDB$PACKAGE_NAME)); - memcpy(temp, X.RDB$PACKAGE_NAME, prefixLen); - temp[prefixLen++] = '.'; - } - - l = GET_TEXT(X.RDB$FUNCTION_NAME); - MISC_terminate (X.RDB$FUNCTION_NAME, temp + prefixLen, l, - sizeof(temp) - prefixLen); - BURP_verbose (118, temp); + GET_TEXT(X.RDB$FUNCTION_NAME); + name.object = X.RDB$FUNCTION_NAME; + BURP_verbose(118, name.toQuotedString().c_str()); // msg 118 restoring function %s break; - } case att_function_description: X.RDB$DESCRIPTION.NULL = FALSE; @@ -4479,12 +4599,18 @@ bool get_function(BurpGlobals* tdgbl) bad_attribute(scan_next_attr, attribute, 89); break; + case att_function_schema_name: + GET_TEXT(X.RDB$SCHEMA_NAME); + X.RDB$SCHEMA_NAME.NULL = FALSE; + name.schema = X.RDB$SCHEMA_NAME; + break; + case att_function_package_name: if (tdgbl->RESTORE_format >= 10) { GET_TEXT(X.RDB$PACKAGE_NAME); - fb_utils::exact_name(X.RDB$PACKAGE_NAME); X.RDB$PACKAGE_NAME.NULL = FALSE; + name.package = X.RDB$PACKAGE_NAME; securityClass = true; // prevent creation of security class for packaged function } else @@ -4600,23 +4726,23 @@ bool get_function(BurpGlobals* tdgbl) break; } } - - strcpy(function_name, X.RDB$FUNCTION_NAME); - END_STORE; + } + END_STORE ON_ERROR if (gds_status->getErrors()[1] != isc_no_dup) general_on_error (); else existFlag = true; - END_ERROR; + END_ERROR - collect_missing_privs(tdgbl, obj_udf, function_name, securityClass); + collect_missing_privs(tdgbl, obj_udf, name, securityClass); } else { STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_function_req_handle1) X IN RDB$FUNCTIONS + { X.RDB$RETURN_ARGUMENT.NULL = TRUE; X.RDB$SYSTEM_FLAG = 0; X.RDB$SYSTEM_FLAG.NULL = FALSE; @@ -4628,9 +4754,9 @@ bool get_function(BurpGlobals* tdgbl) switch (attribute) { case att_function_name: - l = GET_TEXT(X.RDB$FUNCTION_NAME); - MISC_terminate (X.RDB$FUNCTION_NAME, temp, l, sizeof(temp)); - BURP_verbose (118, temp); + GET_TEXT(X.RDB$FUNCTION_NAME); + name.object = X.RDB$FUNCTION_NAME; + BURP_verbose(118, name.toQuotedString().c_str()); // msg 118 restoring function %s break; @@ -4732,14 +4858,14 @@ bool get_function(BurpGlobals* tdgbl) break; } } - - END_STORE; + } + END_STORE ON_ERROR if (gds_status->getErrors()[1] != isc_no_dup) general_on_error (); else existFlag = true; - END_ERROR; + END_ERROR } // at the end of args for a function is the rec_function_end marker @@ -4761,6 +4887,7 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) * Reconstruct function argument. * **************************************/ + QualifiedMetaString name; att_type attribute; scan_attr_t scan_next_attr; @@ -4773,6 +4900,7 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) { switch (attribute) { + case att_functionarg_schema_name: case att_functionarg_name: eat_text(tdgbl); break; @@ -4814,6 +4942,7 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) case att_functionarg_package_name: case att_functionarg_arg_name: + case att_functionarg_field_source_schema_name: case att_functionarg_field_source: if (tdgbl->RESTORE_format >= 10) eat_text(tdgbl); @@ -4839,6 +4968,7 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) break; case att_functionarg_field_name: + case att_functionarg_relation_schema_name: case att_functionarg_relation_name: if (tdgbl->RESTORE_format >= 10) eat_text(tdgbl); @@ -4862,21 +4992,21 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) return; } - SSHORT l; - TEXT temp[GDS_NAME_LEN * 2]; - if (tdgbl->runtimeODS >= DB_VERSION_DDL12) { // with RDB$FIELD_PRECISION STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_function_arg_req_handle1) X IN RDB$FUNCTION_ARGUMENTS + { X.RDB$ARGUMENT_POSITION.NULL = TRUE; X.RDB$FIELD_SUB_TYPE.NULL = TRUE; X.RDB$CHARACTER_SET_ID.NULL = TRUE; X.RDB$FIELD_PRECISION.NULL = TRUE; + X.RDB$SCHEMA_NAME.NULL = TRUE; X.RDB$PACKAGE_NAME.NULL = TRUE; X.RDB$ARGUMENT_NAME.NULL = TRUE; + X.RDB$FIELD_SOURCE_SCHEMA_NAME.NULL = TRUE; X.RDB$FIELD_SOURCE.NULL = TRUE; X.RDB$DEFAULT_VALUE.NULL = TRUE; X.RDB$DEFAULT_SOURCE.NULL = TRUE; @@ -4884,6 +5014,7 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) X.RDB$NULL_FLAG.NULL = TRUE; X.RDB$ARGUMENT_MECHANISM.NULL = TRUE; X.RDB$FIELD_NAME.NULL = TRUE; + X.RDB$RELATION_SCHEMA_NAME.NULL = TRUE; X.RDB$RELATION_NAME.NULL = TRUE; X.RDB$DESCRIPTION.NULL = TRUE; @@ -4896,22 +5027,10 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) switch (attribute) { case att_functionarg_name: - { - SSHORT prefixLen = 0; - if (!X.RDB$PACKAGE_NAME.NULL) - { - prefixLen = static_cast(strlen(X.RDB$PACKAGE_NAME)); - memcpy(temp, X.RDB$PACKAGE_NAME, prefixLen); - temp[prefixLen++] = '.'; - } - - l = GET_TEXT(X.RDB$FUNCTION_NAME); - MISC_terminate(X.RDB$FUNCTION_NAME, temp + prefixLen, l, - sizeof(temp) - prefixLen); - - // msg 119 restoring argument for function %s - BURP_verbose(119, temp); - } + GET_TEXT(X.RDB$FUNCTION_NAME); + name.object = X.RDB$FUNCTION_NAME; + BURP_verbose(119, name.toQuotedString().c_str()); + // msg 119 restoring argument for function %s break; case att_functionarg_position: @@ -4955,12 +5074,18 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) bad_attribute(scan_next_attr, attribute, 90); break; + case att_functionarg_schema_name: + GET_TEXT(X.RDB$SCHEMA_NAME); + X.RDB$SCHEMA_NAME.NULL = FALSE; + name.schema = X.RDB$SCHEMA_NAME; + break; + case att_functionarg_package_name: if (tdgbl->RESTORE_format >= 10) { GET_TEXT(X.RDB$PACKAGE_NAME); X.RDB$PACKAGE_NAME.NULL = FALSE; - fb_utils::exact_name(X.RDB$PACKAGE_NAME); + name.package = X.RDB$PACKAGE_NAME; } else bad_attribute(scan_next_attr, attribute, 90); @@ -4976,6 +5101,16 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) bad_attribute(scan_next_attr, attribute, 90); break; + case att_functionarg_field_source_schema_name: + if (tdgbl->RESTORE_format >= 10) + { + GET_TEXT(X.RDB$FIELD_SOURCE_SCHEMA_NAME); + X.RDB$FIELD_SOURCE_SCHEMA_NAME.NULL = FALSE; + } + else + bad_attribute(scan_next_attr, attribute, 90); + break; + case att_functionarg_field_source: if (tdgbl->RESTORE_format >= 10) { @@ -5046,6 +5181,16 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) bad_attribute(scan_next_attr, attribute, 90); break; + case att_functionarg_relation_schema_name: + if (tdgbl->RESTORE_format >= 10) + { + GET_TEXT(X.RDB$RELATION_SCHEMA_NAME); + X.RDB$RELATION_SCHEMA_NAME.NULL = FALSE; + } + else + bad_attribute(scan_next_attr, attribute, 90); + break; + case att_functionarg_relation_name: if (tdgbl->RESTORE_format >= 10) { @@ -5072,7 +5217,8 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) break; } } - END_STORE; + } + END_STORE ON_ERROR general_on_error (); END_ERROR; @@ -5094,9 +5240,9 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) switch (attribute) { case att_functionarg_name: - l = GET_TEXT(X.RDB$FUNCTION_NAME); - MISC_terminate (X.RDB$FUNCTION_NAME, temp, l, sizeof(temp)); - BURP_verbose (119, temp); + GET_TEXT(X.RDB$FUNCTION_NAME); + name.object = X.RDB$FUNCTION_NAME; + BURP_verbose(119, name.toQuotedString().c_str()); // msg 119 restoring argument for function %s break; @@ -5143,6 +5289,7 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) case att_functionarg_package_name: case att_functionarg_arg_name: + case att_functionarg_field_source_schema_name: case att_functionarg_field_source: if (tdgbl->RESTORE_format >= 10) eat_text(tdgbl); @@ -5168,6 +5315,7 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) break; case att_functionarg_field_name: + case att_functionarg_relation_schema_name: case att_functionarg_relation_name: if (tdgbl->RESTORE_format >= 10) eat_text(tdgbl); @@ -5209,9 +5357,9 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) switch (attribute) { case att_functionarg_name: - l = GET_TEXT(X.RDB$FUNCTION_NAME); - MISC_terminate (X.RDB$FUNCTION_NAME, temp, l, sizeof(temp)); - BURP_verbose (119, temp); + GET_TEXT(X.RDB$FUNCTION_NAME); + name.object = X.RDB$FUNCTION_NAME; + BURP_verbose(119, name.toQuotedString().c_str()); // msg 119 restoring argument for function %s break; @@ -5255,6 +5403,7 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) case att_functionarg_package_name: case att_functionarg_arg_name: + case att_functionarg_field_source_schema_name: case att_functionarg_field_source: if (tdgbl->RESTORE_format >= 10) eat_text(tdgbl); @@ -5280,6 +5429,7 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) break; case att_functionarg_field_name: + case att_functionarg_relation_schema_name: case att_functionarg_relation_name: if (tdgbl->RESTORE_format >= 10) eat_text(tdgbl); @@ -5324,7 +5474,11 @@ bool get_generator(BurpGlobals* tdgbl) **************************************/ SINT64 value = 0, initial_value = 0; - BASED_ON RDB$GENERATORS.RDB$GENERATOR_NAME name = ""; + QualifiedMetaString name; + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + name.schema = PUBLIC_SCHEMA; + + BASED_ON RDB$GENERATORS.RDB$GENERATOR_NAME temp = ""; BASED_ON RDB$GENERATORS.RDB$SECURITY_CLASS secclass = ""; BASED_ON RDB$GENERATORS.RDB$OWNER_NAME ownername = ""; BASED_ON RDB$GENERATORS.RDB$GENERATOR_INCREMENT increment = 1; @@ -5343,8 +5497,14 @@ bool get_generator(BurpGlobals* tdgbl) { switch (attribute) { + case att_gen_schema_name: + GET_TEXT(temp); + name.schema = temp; + break; + case att_gen_generator: - GET_TEXT(name); + GET_TEXT(temp); + name.object = temp; break; case att_gen_value: @@ -5435,22 +5595,24 @@ bool get_global_field(BurpGlobals* tdgbl) * Reconstruct a global field. * **************************************/ + QualifiedMetaString name; + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + name.schema = PUBLIC_SCHEMA; + att_type attribute; - TEXT temp[GDS_NAME_LEN]; - SSHORT l; scan_attr_t scan_next_attr; gfld* gfield = NULL; if (tdgbl->runtimeODS >= DB_VERSION_DDL12) { - GDS_NAME field_name; bool securityClass = false; // with rdb$field_precision, rdb$security_class and rdb$owner_name. STORE (REQUEST_HANDLE tdgbl->handles_get_global_field_req_handle1) X IN RDB$FIELDS - + { + X.RDB$SCHEMA_NAME.NULL = TRUE; X.RDB$FIELD_SCALE = X.RDB$SEGMENT_LENGTH = 0; X.RDB$CHARACTER_SET_ID = X.RDB$COLLATION_ID = 0; X.RDB$FIELD_SUB_TYPE = 0; @@ -5488,10 +5650,16 @@ bool get_global_field(BurpGlobals* tdgbl) { switch (attribute) { + case att_field_schema_name: + GET_TEXT(X.RDB$SCHEMA_NAME); + X.RDB$SCHEMA_NAME.NULL = FALSE; + name.schema = X.RDB$SCHEMA_NAME; + break; + case att_field_name: - l = GET_TEXT(X.RDB$FIELD_NAME); - MISC_terminate (X.RDB$FIELD_NAME, temp, l, sizeof(temp)); - BURP_verbose (121, temp); + GET_TEXT(X.RDB$FIELD_NAME); + name.object = X.RDB$FIELD_NAME; + BURP_verbose(121, name.toQuotedString().c_str()); // msg 121 restoring global field %s break; @@ -5785,15 +5953,13 @@ bool get_global_field(BurpGlobals* tdgbl) if (X.RDB$FIELD_TYPE <= DTYPE_BLR_MAX) { - l = gds_cvt_blr_dtype[X.RDB$FIELD_TYPE]; + SSHORT l = gds_cvt_blr_dtype[X.RDB$FIELD_TYPE]; if (l = type_lengths[l]) X.RDB$FIELD_LENGTH = l; } - strcpy(field_name, X.RDB$FIELD_NAME); - if (gfield) - strcpy(gfield->gfld_name, field_name); + gfield->gfld_name = name; if (tdgbl->gbl_sw_fix_fss_data && tdgbl->gbl_sw_fix_fss_data_id == 0 && !X.RDB$CHARACTER_SET_ID.NULL && X.RDB$CHARACTER_SET_ID == CS_UNICODE_FSS && @@ -5807,20 +5973,20 @@ bool get_global_field(BurpGlobals* tdgbl) X.RDB$CHARACTER_SET_ID = CS_NONE; X.RDB$COLLATION_ID = 0; } - - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR - collect_missing_privs(tdgbl, obj_field, field_name, securityClass); + collect_missing_privs(tdgbl, obj_field, name, securityClass); } else if (tdgbl->runtimeODS >= DB_VERSION_DDL10) { // with rdb$field_precision STORE (REQUEST_HANDLE tdgbl->handles_get_global_field_req_handle1) X IN RDB$FIELDS - + { X.RDB$FIELD_SCALE = X.RDB$SEGMENT_LENGTH = 0; X.RDB$CHARACTER_SET_ID = X.RDB$COLLATION_ID = 0; X.RDB$FIELD_SUB_TYPE = 0; @@ -5856,9 +6022,9 @@ bool get_global_field(BurpGlobals* tdgbl) switch (attribute) { case att_field_name: - l = GET_TEXT(X.RDB$FIELD_NAME); - MISC_terminate (X.RDB$FIELD_NAME, temp, l, sizeof(temp)); - BURP_verbose (121, temp); + GET_TEXT(X.RDB$FIELD_NAME); + name.object = X.RDB$FIELD_NAME; + BURP_verbose(121, name.toQuotedString().c_str()); // msg 121 restoring global field %s break; @@ -6138,13 +6304,13 @@ bool get_global_field(BurpGlobals* tdgbl) if (X.RDB$FIELD_TYPE <= DTYPE_BLR_MAX) { - l = gds_cvt_blr_dtype[X.RDB$FIELD_TYPE]; + SSHORT l = gds_cvt_blr_dtype[X.RDB$FIELD_TYPE]; if (l = type_lengths[l]) X.RDB$FIELD_LENGTH = l; } if (gfield) - strcpy (gfield->gfld_name, X.RDB$FIELD_NAME); + gfield->gfld_name = name; if (tdgbl->gbl_sw_fix_fss_data && tdgbl->gbl_sw_fix_fss_data_id == 0 && !X.RDB$CHARACTER_SET_ID.NULL && X.RDB$CHARACTER_SET_ID == CS_UNICODE_FSS && @@ -6158,12 +6324,11 @@ bool get_global_field(BurpGlobals* tdgbl) X.RDB$CHARACTER_SET_ID = CS_NONE; X.RDB$COLLATION_ID = 0; } - - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; - + END_ERROR } else // runtimeODS < DB_VERSION_DDL10 { @@ -6171,7 +6336,7 @@ bool get_global_field(BurpGlobals* tdgbl) STORE (REQUEST_HANDLE tdgbl->handles_get_global_field_req_handle1) X IN RDB$FIELDS - + { X.RDB$FIELD_SCALE = X.RDB$SEGMENT_LENGTH = 0; X.RDB$CHARACTER_SET_ID = X.RDB$COLLATION_ID = 0; X.RDB$FIELD_SUB_TYPE = 0; @@ -6206,9 +6371,9 @@ bool get_global_field(BurpGlobals* tdgbl) switch (attribute) { case att_field_name: - l = GET_TEXT(X.RDB$FIELD_NAME); - MISC_terminate (X.RDB$FIELD_NAME, temp, l, sizeof(temp)); - BURP_verbose (121, temp); + GET_TEXT(X.RDB$FIELD_NAME); + name.object = X.RDB$FIELD_NAME; + BURP_verbose(121, name.toQuotedString().c_str()); // msg 121 restoring global field %s break; @@ -6485,13 +6650,13 @@ bool get_global_field(BurpGlobals* tdgbl) if (X.RDB$FIELD_TYPE <= DTYPE_BLR_MAX) { - l = gds_cvt_blr_dtype[X.RDB$FIELD_TYPE]; + SSHORT l = gds_cvt_blr_dtype[X.RDB$FIELD_TYPE]; if (l = type_lengths[l]) X.RDB$FIELD_LENGTH = l; } if (gfield) - strcpy (gfield->gfld_name, X.RDB$FIELD_NAME); + gfield->gfld_name = name; if (tdgbl->gbl_sw_fix_fss_data && tdgbl->gbl_sw_fix_fss_data_id == 0 && !X.RDB$CHARACTER_SET_ID.NULL && X.RDB$CHARACTER_SET_ID == CS_UNICODE_FSS && @@ -6505,12 +6670,11 @@ bool get_global_field(BurpGlobals* tdgbl) X.RDB$CHARACTER_SET_ID = CS_NONE; X.RDB$COLLATION_ID = 0; } - - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; - + END_ERROR } if (gfield) @@ -6547,14 +6711,18 @@ bool get_index(BurpGlobals* tdgbl, const burp_rel* relation) STORE (REQUEST_HANDLE tdgbl->handles_get_index_req_handle1) X IN RDB$INDICES - strcpy (X.RDB$RELATION_NAME, relation->rel_name); + { + strcpy (X.RDB$RELATION_NAME, relation->rel_name.object.c_str()); X.RDB$UNIQUE_FLAG = 0; if (!tdgbl->gbl_sw_deactivate_indexes) X.RDB$INDEX_INACTIVE = FALSE; else X.RDB$INDEX_INACTIVE = TRUE; + + X.RDB$SCHEMA_NAME.NULL = TRUE; X.RDB$INDEX_TYPE.NULL = TRUE; X.RDB$DESCRIPTION.NULL = TRUE; + X.RDB$FOREIGN_KEY_SCHEMA_NAME.NULL = TRUE; X.RDB$FOREIGN_KEY.NULL = TRUE; X.RDB$EXPRESSION_SOURCE.NULL = TRUE; X.RDB$EXPRESSION_BLR.NULL = TRUE; @@ -6563,6 +6731,12 @@ bool get_index(BurpGlobals* tdgbl, const burp_rel* relation) X.RDB$SYSTEM_FLAG = 0; X.RDB$SYSTEM_FLAG.NULL = FALSE; + if (relation->rel_name.schema.hasData()) + { + strcpy(X.RDB$SCHEMA_NAME, relation->rel_name.schema.c_str()); + X.RDB$SCHEMA_NAME.NULL = FALSE; + } + skip_init(&scan_next_attr); while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end) { @@ -6570,8 +6744,8 @@ bool get_index(BurpGlobals* tdgbl, const burp_rel* relation) { case att_index_name: GET_TEXT(X.RDB$INDEX_NAME); - strcpy (index_name, X.RDB$INDEX_NAME); - BURP_verbose (122, X.RDB$INDEX_NAME); + strcpy(index_name, X.RDB$INDEX_NAME); + BURP_verbose(122, QualifiedMetaString(X.RDB$INDEX_NAME, relation->rel_name.schema).toQuotedString().c_str()); break; case att_segment_count: @@ -6608,13 +6782,19 @@ bool get_index(BurpGlobals* tdgbl, const burp_rel* relation) case att_index_field_name: STORE (REQUEST_HANDLE tdgbl->handles_get_index_req_handle2) Y IN RDB$INDEX_SEGMENTS + { GET_TEXT(Y.RDB$FIELD_NAME); - strcpy (Y.RDB$INDEX_NAME, X.RDB$INDEX_NAME); + strcpy(Y.RDB$INDEX_NAME, X.RDB$INDEX_NAME); Y.RDB$FIELD_POSITION = count++; - END_STORE; + + Y.RDB$SCHEMA_NAME.NULL = X.RDB$SCHEMA_NAME.NULL; + if (!X.RDB$SCHEMA_NAME.NULL) + strcpy(Y.RDB$SCHEMA_NAME, X.RDB$SCHEMA_NAME); + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR break; case att_index_description: @@ -6663,6 +6843,11 @@ bool get_index(BurpGlobals* tdgbl, const burp_rel* relation) bad_attribute(scan_next_attr, attribute, 93); break; + case att_index_foreign_key_schema_name: + X.RDB$FOREIGN_KEY_SCHEMA_NAME.NULL = FALSE; + GET_TEXT(X.RDB$FOREIGN_KEY_SCHEMA_NAME); + break; + case att_index_foreign_key: foreign_index = true; // Defer foreign key index activation @@ -6683,33 +6868,45 @@ bool get_index(BurpGlobals* tdgbl, const burp_rel* relation) count = 0; FOR (REQUEST_HANDLE tdgbl->handles_get_index_req_handle3) - RFR IN RDB$RELATION_FIELDS CROSS I_S IN RDB$INDEX_SEGMENTS - OVER RDB$FIELD_NAME WITH I_S.RDB$INDEX_NAME = index_name AND - RFR.RDB$RELATION_NAME = relation->rel_name + RFR IN RDB$RELATION_FIELDS + CROSS IDS IN RDB$INDEX_SEGMENTS + WITH RFR.RDB$SCHEMA_NAME EQUIV NULLIF(relation->rel_name.schema.c_str(), '') AND + RFR.RDB$RELATION_NAME = relation->rel_name.object.c_str() AND + IDS.RDB$SCHEMA_NAME EQUIV RFR.RDB$SCHEMA_NAME AND + IDS.RDB$FIELD_NAME = RFR.RDB$FIELD_NAME AND + IDS.RDB$INDEX_NAME = index_name + { count++; - END_FOR; + } + END_FOR ON_ERROR general_on_error (); - END_ERROR; + END_ERROR if (count != segments) { FOR (REQUEST_HANDLE tdgbl->handles_get_index_req_handle4) - I_S IN RDB$INDEX_SEGMENTS WITH I_S.RDB$INDEX_NAME = index_name - ERASE I_S; + IDS IN RDB$INDEX_SEGMENTS + WITH IDS.RDB$SCHEMA_NAME EQUIV NULLIF(relation->rel_name.schema.c_str(), '') AND + IDS.RDB$INDEX_NAME = index_name + { + ERASE IDS; ON_ERROR general_on_error (); - END_ERROR; - END_FOR; + END_ERROR + } + END_FOR ON_ERROR general_on_error (); - END_ERROR; + + END_ERROR return false; } - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR return true; } @@ -6825,8 +7022,6 @@ bool get_package(BurpGlobals* tdgbl) * **************************************/ att_type attribute; - TEXT temp[GDS_NAME_LEN]; - SSHORT len; scan_attr_t scan_next_attr; if (tdgbl->RESTORE_format < 10) @@ -6835,12 +7030,16 @@ bool get_package(BurpGlobals* tdgbl) Firebird::ITransaction* local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans; burp_pkg* package = (burp_pkg*) BURP_alloc_zero(sizeof(burp_pkg)); + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + package->pkg_name.schema = PUBLIC_SCHEMA; + package->pkg_next = tdgbl->packages; tdgbl->packages = package; STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_package_req_handle1) X IN RDB$PACKAGES { + X.RDB$SCHEMA_NAME.NULL = TRUE; X.RDB$PACKAGE_HEADER_SOURCE.NULL = TRUE; X.RDB$PACKAGE_BODY_SOURCE.NULL = TRUE; X.RDB$VALID_BODY_FLAG.NULL = TRUE; @@ -6856,11 +7055,16 @@ bool get_package(BurpGlobals* tdgbl) { switch (attribute) { + case att_package_schema_name: + GET_TEXT(X.RDB$SCHEMA_NAME); + X.RDB$SCHEMA_NAME.NULL = FALSE; + package->pkg_name.schema = X.RDB$SCHEMA_NAME; + break; + case att_package_name: - len = GET_TEXT(X.RDB$PACKAGE_NAME); - strcpy(package->pkg_name, X.RDB$PACKAGE_NAME); - MISC_terminate(X.RDB$PACKAGE_NAME, temp, len, sizeof(temp)); - BURP_verbose(337, temp); // msg 337 restoring package %s + GET_TEXT(X.RDB$PACKAGE_NAME); + package->pkg_name.object = X.RDB$PACKAGE_NAME; + BURP_verbose(337, package->pkg_name.toQuotedString().c_str()); // msg 337 restoring package %s break; case att_package_header_source: @@ -6934,15 +7138,14 @@ bool get_procedure(BurpGlobals* tdgbl) * **************************************/ att_type attribute; - GDS_NAME package_name = ""; - GDS_NAME procedure_name = ""; - TEXT temp[GDS_NAME_LEN * 2]; - SSHORT l; scan_attr_t scan_next_attr; Firebird::ITransaction* local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans; burp_prc* procedure = (burp_prc*) BURP_alloc_zero (sizeof(burp_prc)); + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + procedure->prc_name.schema = PUBLIC_SCHEMA; + procedure->prc_next = tdgbl->procedures; tdgbl->procedures = procedure; @@ -6951,6 +7154,7 @@ bool get_procedure(BurpGlobals* tdgbl) STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_procedure_req_handle1) X IN RDB$PROCEDURES + { X.RDB$PROCEDURE_SOURCE.NULL = TRUE; X.RDB$DESCRIPTION.NULL = TRUE; X.RDB$SECURITY_CLASS.NULL = TRUE; @@ -6964,6 +7168,7 @@ bool get_procedure(BurpGlobals* tdgbl) X.RDB$PROCEDURE_BLR.NULL = TRUE; X.RDB$ENGINE_NAME.NULL = TRUE; X.RDB$ENTRYPOINT.NULL = TRUE; + X.RDB$SCHEMA_NAME.NULL = TRUE; X.RDB$PACKAGE_NAME.NULL = TRUE; X.RDB$PRIVATE_FLAG.NULL = TRUE; X.RDB$SQL_SECURITY.NULL = TRUE; @@ -6973,25 +7178,28 @@ bool get_procedure(BurpGlobals* tdgbl) { switch (attribute) { - case att_procedure_name: + case att_procedure_schema_name: + GET_TEXT(X.RDB$SCHEMA_NAME); + X.RDB$SCHEMA_NAME.NULL = FALSE; + procedure->prc_name.schema = X.RDB$SCHEMA_NAME; + break; + + case att_procedure_package_name: + if (tdgbl->RESTORE_format >= 10) { - SSHORT prefixLen = 0; - if (package_name[0]) - { - prefixLen = static_cast(strlen(package_name)); - memcpy(temp, package_name, prefixLen); - temp[prefixLen++] = '.'; - } - - l = GET_TEXT(X.RDB$PROCEDURE_NAME); - //procedure->prc_name_length = l; - strcpy (procedure->prc_name, X.RDB$PROCEDURE_NAME); - - MISC_terminate (X.RDB$PROCEDURE_NAME, temp + prefixLen, l, - sizeof(temp) - prefixLen); - BURP_verbose (195, temp); - // msg 195 restoring stored procedure %s + GET_TEXT(X.RDB$PACKAGE_NAME); + X.RDB$PACKAGE_NAME.NULL = FALSE; + procedure->prc_name.package = X.RDB$PACKAGE_NAME; } + else + bad_attribute(scan_next_attr, attribute, 290); + break; + + case att_procedure_name: + GET_TEXT(X.RDB$PROCEDURE_NAME); + procedure->prc_name.object = X.RDB$PROCEDURE_NAME; + BURP_verbose(195, procedure->prc_name.toQuotedString().c_str()); + // msg 195 restoring stored procedure %s break; case att_procedure_description: @@ -7088,19 +7296,6 @@ bool get_procedure(BurpGlobals* tdgbl) bad_attribute(scan_next_attr, attribute, 290); break; - case att_procedure_package_name: - if (tdgbl->RESTORE_format >= 10) - { - GET_TEXT(X.RDB$PACKAGE_NAME); - X.RDB$PACKAGE_NAME.NULL = FALSE; - strcpy(procedure->prc_package, X.RDB$PACKAGE_NAME); - strcpy(package_name, X.RDB$PACKAGE_NAME); - fb_utils::exact_name(package_name); - } - else - bad_attribute(scan_next_attr, attribute, 290); - break; - case att_procedure_private_flag: if (tdgbl->RESTORE_format >= 10) { @@ -7128,8 +7323,8 @@ bool get_procedure(BurpGlobals* tdgbl) break; } } - strcpy (procedure_name, X.RDB$PROCEDURE_NAME); - END_STORE; + } + END_STORE ON_ERROR general_on_error (); END_ERROR; @@ -7139,6 +7334,7 @@ bool get_procedure(BurpGlobals* tdgbl) STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_procedure_req_handle1) X IN RDB$PROCEDURES + { X.RDB$PROCEDURE_SOURCE.NULL = TRUE; X.RDB$DESCRIPTION.NULL = TRUE; X.RDB$SECURITY_CLASS.NULL = TRUE; @@ -7152,11 +7348,9 @@ bool get_procedure(BurpGlobals* tdgbl) switch (attribute) { case att_procedure_name: - l = GET_TEXT(X.RDB$PROCEDURE_NAME); - //procedure->prc_name_length = l; - strcpy (procedure->prc_name, X.RDB$PROCEDURE_NAME); - MISC_terminate (X.RDB$PROCEDURE_NAME, temp, l, sizeof(temp)); - BURP_verbose (195, temp); + GET_TEXT(X.RDB$PROCEDURE_NAME); + procedure->prc_name.object = X.RDB$PROCEDURE_NAME; + BURP_verbose(195, procedure->prc_name.toQuotedString().c_str()); // msg 195 restoring stored procedure %s break; @@ -7251,22 +7445,22 @@ bool get_procedure(BurpGlobals* tdgbl) break; } } - strcpy (procedure_name, X.RDB$PROCEDURE_NAME); - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR } // at the end of prms for a procedure is the rec_procedure_end marker while (get(tdgbl) == rec_procedure_prm) - get_procedure_prm (tdgbl, package_name, procedure_name); + get_procedure_prm(tdgbl, procedure->prc_name); return true; } -bool get_procedure_prm (BurpGlobals* tdgbl, GDS_NAME package_name, GDS_NAME procptr) +bool get_procedure_prm(BurpGlobals* tdgbl, const QualifiedMetaString& name) { /************************************** * @@ -7282,8 +7476,6 @@ bool get_procedure_prm (BurpGlobals* tdgbl, GDS_NAME package_name, GDS_NAME proc * **************************************/ att_type attribute; - SSHORT l; - TEXT temp[GDS_NAME_LEN]; scan_attr_t scan_next_attr; Firebird::ITransaction* local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans; @@ -7293,17 +7485,26 @@ bool get_procedure_prm (BurpGlobals* tdgbl, GDS_NAME package_name, GDS_NAME proc STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_procedure_prm_req_handle1) X IN RDB$PROCEDURE_PARAMETERS + { + strcpy(X.RDB$PROCEDURE_NAME, name.object.c_str()); - strcpy(X.RDB$PROCEDURE_NAME, procptr); - - if (package_name[0]) + if (name.schema.hasData()) { - strcpy(X.RDB$PACKAGE_NAME, package_name); + strcpy(X.RDB$SCHEMA_NAME, name.schema.c_str()); + X.RDB$SCHEMA_NAME.NULL = FALSE; + } + else + X.RDB$SCHEMA_NAME.NULL = TRUE; + + if (name.package.hasData()) + { + strcpy(X.RDB$PACKAGE_NAME, name.package.c_str()); X.RDB$PACKAGE_NAME.NULL = FALSE; } else X.RDB$PACKAGE_NAME.NULL = TRUE; + X.RDB$FIELD_SOURCE_SCHEMA_NAME.NULL = TRUE; X.RDB$DESCRIPTION.NULL = TRUE; X.RDB$DEFAULT_VALUE.NULL = TRUE; X.RDB$DEFAULT_SOURCE.NULL = TRUE; @@ -7318,8 +7519,8 @@ bool get_procedure_prm (BurpGlobals* tdgbl, GDS_NAME package_name, GDS_NAME proc X.RDB$PARAMETER_MECHANISM = prm_mech_normal; X.RDB$PARAMETER_MECHANISM.NULL = FALSE; - // DB_VERSION_DDL11_2 X.RDB$FIELD_NAME.NULL = TRUE; + X.RDB$RELATION_SCHEMA_NAME.NULL = TRUE; X.RDB$RELATION_NAME.NULL = TRUE; skip_init(&scan_next_attr); @@ -7328,9 +7529,8 @@ bool get_procedure_prm (BurpGlobals* tdgbl, GDS_NAME package_name, GDS_NAME proc switch (attribute) { case att_procedureprm_name: - l = GET_TEXT(X.RDB$PARAMETER_NAME); - MISC_terminate (X.RDB$PARAMETER_NAME, temp, l, sizeof(temp)); - BURP_verbose (196, temp); + GET_TEXT(X.RDB$PARAMETER_NAME); + BURP_verbose(196, MetaString(X.RDB$PARAMETER_NAME).toQuotedString().c_str()); // msg 196 restoring parameter %s for stored procedure break; @@ -7342,6 +7542,11 @@ bool get_procedure_prm (BurpGlobals* tdgbl, GDS_NAME package_name, GDS_NAME proc X.RDB$PARAMETER_NUMBER= (USHORT) get_int32(tdgbl); break; + case att_procedureprm_field_source_schema_name: + GET_TEXT(X.RDB$FIELD_SOURCE_SCHEMA_NAME); + X.RDB$FIELD_SOURCE_SCHEMA_NAME.NULL = FALSE; + break; + case att_procedureprm_field_source: GET_TEXT(X.RDB$FIELD_SOURCE); break; @@ -7411,6 +7616,11 @@ bool get_procedure_prm (BurpGlobals* tdgbl, GDS_NAME package_name, GDS_NAME proc bad_attribute(scan_next_attr, attribute, 291); break; + case att_procedureprm_relation_schema_name: + X.RDB$RELATION_SCHEMA_NAME.NULL = FALSE; + GET_TEXT(X.RDB$RELATION_SCHEMA_NAME); + break; + // DB_VERSION_DDL11_2 case att_procedureprm_relation_name: if (tdgbl->RESTORE_format >= 9) @@ -7428,18 +7638,20 @@ bool get_procedure_prm (BurpGlobals* tdgbl, GDS_NAME package_name, GDS_NAME proc break; } } - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR } else { STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_procedure_prm_req_handle1) X IN RDB$PROCEDURE_PARAMETERS + { X.RDB$DESCRIPTION.NULL = TRUE; - strcpy (X.RDB$PROCEDURE_NAME, procptr); + strcpy(X.RDB$PROCEDURE_NAME, name.object.c_str()); X.RDB$SYSTEM_FLAG = 0; X.RDB$SYSTEM_FLAG.NULL = FALSE; @@ -7449,9 +7661,8 @@ bool get_procedure_prm (BurpGlobals* tdgbl, GDS_NAME package_name, GDS_NAME proc switch (attribute) { case att_procedureprm_name: - l = GET_TEXT(X.RDB$PARAMETER_NAME); - MISC_terminate (X.RDB$PARAMETER_NAME, temp, l, sizeof(temp)); - BURP_verbose (196, temp); + GET_TEXT(X.RDB$PARAMETER_NAME); + BURP_verbose(196, MetaString(X.RDB$PARAMETER_NAME).toQuotedString().c_str()); // msg 196 restoring parameter %s for stored procedure break; @@ -7509,10 +7720,11 @@ bool get_procedure_prm (BurpGlobals* tdgbl, GDS_NAME package_name, GDS_NAME proc break; } } - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR } return true; @@ -7558,7 +7770,7 @@ bool get_publication(BurpGlobals* tdgbl) case att_pub_name: GET_TEXT(X.RDB$PUBLICATION_NAME); X.RDB$PUBLICATION_NAME.NULL = FALSE; - BURP_verbose(399, X.RDB$PUBLICATION_NAME); + BURP_verbose(399, MetaString(X.RDB$PUBLICATION_NAME).toQuotedString().c_str()); // msg 399 restoring publication %s break; @@ -7627,6 +7839,10 @@ bool get_pub_table(BurpGlobals* tdgbl) * Reconstruct a publication table. * **************************************/ + QualifiedMetaString name; + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + name.schema = PUBLIC_SCHEMA; + att_type attribute; scan_attr_t scan_next_attr; @@ -7634,8 +7850,9 @@ bool get_pub_table(BurpGlobals* tdgbl) { STORE (REQUEST_HANDLE tdgbl->handles_get_pub_tab_req_handle1) X IN RDB$PUBLICATION_TABLES - + { X.RDB$PUBLICATION_NAME.NULL = TRUE; + X.RDB$TABLE_SCHEMA_NAME.NULL = TRUE; X.RDB$TABLE_NAME.NULL = TRUE; skip_init(&scan_next_attr); @@ -7648,10 +7865,17 @@ bool get_pub_table(BurpGlobals* tdgbl) X.RDB$PUBLICATION_NAME.NULL = FALSE; break; + case att_ptab_table_schema_name: + GET_TEXT(X.RDB$TABLE_SCHEMA_NAME); + name.schema = X.RDB$TABLE_SCHEMA_NAME; + X.RDB$TABLE_SCHEMA_NAME.NULL = FALSE; + break; + case att_ptab_table_name: GET_TEXT(X.RDB$TABLE_NAME); + name.object = X.RDB$TABLE_NAME; X.RDB$TABLE_NAME.NULL = FALSE; - BURP_verbose(401, X.RDB$TABLE_NAME); + BURP_verbose(401, name.toQuotedString().c_str()); // msg 401 restoring publication for table %s break; @@ -7661,10 +7885,11 @@ bool get_pub_table(BurpGlobals* tdgbl) break; } } - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR } else { @@ -7675,6 +7900,7 @@ bool get_pub_table(BurpGlobals* tdgbl) switch (attribute) { case att_ptab_pub_name: + case att_ptab_table_schema_name: case att_ptab_table_name: eat_text(tdgbl); break; @@ -7707,7 +7933,10 @@ bool get_ref_constraint(BurpGlobals* tdgbl) STORE (REQUEST_HANDLE tdgbl->handles_get_ref_constraint_req_handle1) X IN RDB$REF_CONSTRAINTS + { + X.RDB$SCHEMA_NAME.NULL = TRUE; X.RDB$CONSTRAINT_NAME.NULL = TRUE; + X.RDB$CONST_SCHEMA_NAME_UQ.NULL = TRUE; X.RDB$CONST_NAME_UQ.NULL = TRUE; X.RDB$MATCH_OPTION.NULL = TRUE; X.RDB$UPDATE_RULE.NULL = TRUE; @@ -7718,11 +7947,21 @@ bool get_ref_constraint(BurpGlobals* tdgbl) { switch (attribute) { + case att_ref_schema_name: + X.RDB$SCHEMA_NAME.NULL = FALSE; + GET_TEXT(X.RDB$SCHEMA_NAME); + break; + case att_ref_constraint_name: X.RDB$CONSTRAINT_NAME.NULL = FALSE; GET_TEXT(X.RDB$CONSTRAINT_NAME); break; + case att_ref_unique_const_schema_name: + X.RDB$CONST_SCHEMA_NAME_UQ.NULL = FALSE; + GET_TEXT(X.RDB$CONST_SCHEMA_NAME_UQ); + break; + case att_ref_unique_const_name: X.RDB$CONST_NAME_UQ.NULL = FALSE; GET_TEXT(X.RDB$CONST_NAME_UQ); @@ -7749,10 +7988,11 @@ bool get_ref_constraint(BurpGlobals* tdgbl) break; } } - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR return true; } @@ -7812,24 +8052,13 @@ bool get_relation(BurpGlobals* tdgbl, Coordinator* coord, RestoreRelationTask* t // Pick up relation attributes burp_rel* relation = (burp_rel*) BURP_alloc_zero (sizeof(burp_rel)); + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + relation->rel_name.schema = PUBLIC_SCHEMA; + relation->rel_next = tdgbl->relations; tdgbl->relations = relation; - /* - STORE (REQUEST_HANDLE tdgbl->handles_get_relation_req_handle1) - X IN RDB$RELATIONS - X.RDB$SYSTEM_FLAG = 0; - X.RDB$SYSTEM_FLAG.NULL = FALSE; - X.RDB$FLAGS.NULL = TRUE; - X.RDB$SECURITY_CLASS.NULL = TRUE; - X.RDB$VIEW_BLR.NULL = TRUE; - X.RDB$VIEW_SOURCE.NULL = TRUE; - X.RDB$DESCRIPTION.NULL = TRUE; - X.RDB$RUNTIME.NULL = TRUE; - X.RDB$EXTERNAL_DESCRIPTION.NULL = TRUE; - */ - - TEXT rel_name[GDS_NAME_LEN] = ""; + TEXT temp[GDS_NAME_LEN]; att_type attribute; scan_attr_t scan_next_attr; skip_init(&scan_next_attr); @@ -7838,12 +8067,16 @@ bool get_relation(BurpGlobals* tdgbl, Coordinator* coord, RestoreRelationTask* t { switch (attribute) { + case att_relation_schema_name: + GET_TEXT(temp); + relation->rel_name.schema = temp; + break; + case att_relation_name: { - const SSHORT l = GET_TEXT(relation->rel_name); - relation->rel_name_length = l; - MISC_terminate (relation->rel_name, rel_name, l, sizeof(rel_name)); - BURP_verbose(167, rel_name); // msg 167 restoring table @1 + GET_TEXT(temp); + relation->rel_name.object = temp; + BURP_verbose(167, relation->rel_name.toQuotedString().c_str()); // msg 167 restoring table @1 } break; @@ -7857,8 +8090,8 @@ bool get_relation(BurpGlobals* tdgbl, Coordinator* coord, RestoreRelationTask* t view_blr_null = false; get_blr_blob(tdgbl, view_blr, true); relation->rel_flags |= REL_view; - fb_assert(rel_name[0] != 0); - BURP_verbose(346, rel_name); // msg 346 ' table @1 is a view' + fb_assert(relation->rel_name.object.hasData()); + BURP_verbose(346, relation->rel_name.toQuotedString().c_str()); // msg 346 ' table @1 is a view' break; case att_relation_view_source: @@ -7941,7 +8174,8 @@ bool get_relation(BurpGlobals* tdgbl, Coordinator* coord, RestoreRelationTask* t STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_relation_req_handle1) X IN RDB$RELATIONS - + { + X.RDB$SCHEMA_NAME.NULL = TRUE; X.RDB$SYSTEM_FLAG.NULL = FALSE; X.RDB$FLAGS.NULL = rel_flags_null; X.RDB$SECURITY_CLASS.NULL = sec_class_null; @@ -7961,24 +8195,30 @@ bool get_relation(BurpGlobals* tdgbl, Coordinator* coord, RestoreRelationTask* t X.RDB$DESCRIPTION = rel_desc; X.RDB$EXTERNAL_DESCRIPTION = ext_desc; + if (relation->rel_name.schema.hasData()) + { + strcpy(X.RDB$SCHEMA_NAME, relation->rel_name.schema.c_str()); + X.RDB$SCHEMA_NAME.NULL = FALSE; + } + strcpy(X.RDB$SECURITY_CLASS, sec_class); - strcpy(X.RDB$RELATION_NAME, relation->rel_name); + strcpy(X.RDB$RELATION_NAME, relation->rel_name.object.c_str()); strcpy(X.RDB$EXTERNAL_FILE, ext_file_name); X.RDB$RELATION_TYPE = (USHORT) type; X.RDB$SQL_SECURITY = (FB_BOOLEAN) sql_security; - - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR } else { STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_relation_req_handle1) X IN RDB$RELATIONS - + { X.RDB$SYSTEM_FLAG.NULL = FALSE; X.RDB$FLAGS.NULL = rel_flags_null; X.RDB$SECURITY_CLASS.NULL = sec_class_null; @@ -7997,13 +8237,13 @@ bool get_relation(BurpGlobals* tdgbl, Coordinator* coord, RestoreRelationTask* t X.RDB$EXTERNAL_DESCRIPTION = ext_desc; strcpy(X.RDB$SECURITY_CLASS, sec_class); - strcpy(X.RDB$RELATION_NAME, relation->rel_name); + strcpy(X.RDB$RELATION_NAME, relation->rel_name.object.c_str()); strcpy(X.RDB$EXTERNAL_FILE, ext_file_name); - - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR } // Eat up misc. records @@ -8018,12 +8258,12 @@ bool get_relation(BurpGlobals* tdgbl, Coordinator* coord, RestoreRelationTask* t case rec_relation_end: if (tdgbl->gbl_sw_incremental) { - BURP_verbose (170, relation->rel_name); + BURP_verbose(170, relation->rel_name.toQuotedString().c_str()); // msg 170: committing metadata for relation %s COMMIT // existing ON_ERROR continues past error, beck ON_ERROR - BURP_print (false, 171, relation->rel_name); + BURP_print(false, 171, relation->rel_name.toQuotedString().c_str()); // msg 171: error committing metadata for relation %s BURP_print_status (false, &tdgbl->status_vector); ROLLBACK; @@ -8071,7 +8311,7 @@ bool get_relation(BurpGlobals* tdgbl, Coordinator* coord, RestoreRelationTask* t // If we're only doing meta-data, ignore data records - if (tdgbl->gbl_sw_meta || tdgbl->skipRelation(rel_name)) + if (tdgbl->gbl_sw_meta || tdgbl->skipRelation(relation->rel_name)) ignore_data(tdgbl, relation); else { @@ -8102,6 +8342,8 @@ bool get_rel_constraint(BurpGlobals* tdgbl) STORE (REQUEST_HANDLE tdgbl->handles_get_rel_constraint_req_handle1) X IN RDB$RELATION_CONSTRAINTS + { + X.RDB$SCHEMA_NAME.NULL = TRUE; X.RDB$CONSTRAINT_NAME.NULL = TRUE; X.RDB$CONSTRAINT_TYPE.NULL = TRUE; X.RDB$RELATION_NAME.NULL = TRUE; @@ -8114,6 +8356,11 @@ bool get_rel_constraint(BurpGlobals* tdgbl) { switch (attribute) { + case att_rel_constraint_schema_name: + X.RDB$SCHEMA_NAME.NULL = FALSE; + GET_TEXT(X.RDB$SCHEMA_NAME); + break; + case att_rel_constraint_name: X.RDB$CONSTRAINT_NAME.NULL = FALSE; GET_TEXT(X.RDB$CONSTRAINT_NAME); @@ -8150,10 +8397,11 @@ bool get_rel_constraint(BurpGlobals* tdgbl) break; } } - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR return true; } @@ -8172,7 +8420,11 @@ bool get_relation_data(BurpGlobals* tdgbl, Coordinator* coord, RestoreRelationTa * find the relation named. If we can't find it, give up. * **************************************/ - BASED_ON RDB$RELATIONS.RDB$RELATION_NAME name; + QualifiedMetaString name; + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + name.schema = PUBLIC_SCHEMA; + + TEXT temp[GDS_NAME_LEN]; att_type attribute; scan_attr_t scan_next_attr; @@ -8183,9 +8435,15 @@ bool get_relation_data(BurpGlobals* tdgbl, Coordinator* coord, RestoreRelationTa { switch (attribute) { + case att_relation_schema_name: + GET_TEXT(temp); + name.schema = temp; + break; + case att_relation_name: - GET_TEXT(name); - relation = find_relation (tdgbl, name); + GET_TEXT(temp); + name.object = temp; + relation = find_relation(tdgbl, name); break; default: @@ -8257,6 +8515,118 @@ bool get_relation_data(BurpGlobals* tdgbl, Coordinator* coord, RestoreRelationTa return true; } +// Reconstruct a schema. +bool get_schema(BurpGlobals* tdgbl) +{ + att_type attribute; + scan_attr_t scan_next_attr; + + if (tdgbl->runtimeODS < DB_VERSION_DDL14) + { + skip_init(&scan_next_attr); + + while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end) + { + switch (attribute) + { + case att_schema_name: + eat_text(tdgbl); + break; + + case att_schema_charset_schema_name: + eat_text(tdgbl); + break; + + case att_schema_charset_name: + eat_text(tdgbl); + break; + + case att_schema_security_class: + eat_text(tdgbl); + break; + + case att_schema_owner_name: + eat_text(tdgbl); + break; + + case att_schema_description: + eat_blob(tdgbl); + break; + + default: + bad_attribute(scan_next_attr, attribute, 414); // msg 414 schema + break; + } + } + + return true; + } + + ITransaction* local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans; + + STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_schema_req_handle1) + X IN RDB$SCHEMAS + { + X.RDB$SCHEMA_NAME.NULL = TRUE; + X.RDB$CHARACTER_SET_SCHEMA_NAME.NULL = TRUE; + X.RDB$CHARACTER_SET_NAME.NULL = TRUE; + X.RDB$SECURITY_CLASS.NULL = TRUE; + X.RDB$OWNER_NAME.NULL = TRUE; + X.RDB$DESCRIPTION.NULL = TRUE; + X.RDB$SYSTEM_FLAG = 0; + + skip_init(&scan_next_attr); + + while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end) + { + switch (attribute) + { + case att_schema_name: + GET_TEXT(X.RDB$SCHEMA_NAME); + X.RDB$SCHEMA_NAME.NULL = FALSE; + BURP_verbose(413, MetaString(X.RDB$SCHEMA_NAME).toQuotedString().c_str()); // msg 413 restoring schema @1 + break; + + case att_schema_charset_schema_name: + GET_TEXT(X.RDB$CHARACTER_SET_SCHEMA_NAME); + X.RDB$CHARACTER_SET_SCHEMA_NAME.NULL = FALSE; + break; + + case att_schema_charset_name: + GET_TEXT(X.RDB$CHARACTER_SET_NAME); + X.RDB$CHARACTER_SET_NAME.NULL = FALSE; + break; + + case att_schema_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_schema_owner_name: + GET_TEXT(X.RDB$OWNER_NAME); + X.RDB$OWNER_NAME.NULL = FALSE; + break; + + case att_schema_description: + get_source_blob(tdgbl, X.RDB$DESCRIPTION, true); + X.RDB$DESCRIPTION.NULL = FALSE; + break; + + default: + bad_attribute(scan_next_attr, attribute, 414); // msg 414 schema + break; + } + } + } + END_STORE + ON_ERROR + general_on_error(); + END_ERROR + + return true; +} + bool get_sql_roles(BurpGlobals* tdgbl) { /************************************** @@ -8271,7 +8641,6 @@ bool get_sql_roles(BurpGlobals* tdgbl) **************************************/ att_type attribute; scan_attr_t scan_next_attr; - TEXT temp[GDS_NAME_LEN]; SSHORT l; if (tdgbl->runtimeODS >= DB_VERSION_DDL11) @@ -8292,10 +8661,9 @@ bool get_sql_roles(BurpGlobals* tdgbl) { case att_role_name: X.RDB$ROLE_NAME.NULL = FALSE; - l = GET_TEXT(X.RDB$ROLE_NAME); - MISC_terminate (X.RDB$ROLE_NAME, temp, l, sizeof(temp)); + GET_TEXT(X.RDB$ROLE_NAME); // msg 251, restoring SQL role: %s - BURP_verbose (251, temp); + BURP_verbose(251, MetaString(X.RDB$ROLE_NAME).toQuotedString().c_str()); break; case att_role_owner_name: @@ -8353,10 +8721,9 @@ bool get_sql_roles(BurpGlobals* tdgbl) { case att_role_name: X.RDB$ROLE_NAME.NULL = FALSE; - l = GET_TEXT(X.RDB$ROLE_NAME); - MISC_terminate (X.RDB$ROLE_NAME, temp, l, sizeof(temp)); + GET_TEXT(X.RDB$ROLE_NAME); // msg 251, restoring SQL role: %s - BURP_verbose (251, temp); + BURP_verbose(251, MetaString(X.RDB$ROLE_NAME).toQuotedString().c_str()); break; case att_role_owner_name: @@ -8474,7 +8841,7 @@ bool get_mapping(BurpGlobals* tdgbl) BURP_verbose(301); // msg 301, restoring names mapping - BURP_verbose (298, M.RDB$MAP_NAME); + BURP_verbose(298, MetaString(M.RDB$MAP_NAME).toQuotedString().c_str()); break; case att_map_name: @@ -8486,7 +8853,7 @@ bool get_mapping(BurpGlobals* tdgbl) BURP_verbose(301); // msg 301, restoring names mapping } - BURP_verbose (298, M.RDB$MAP_NAME); + BURP_verbose(298, MetaString(M.RDB$MAP_NAME).toQuotedString().c_str()); break; case att_map_using: @@ -8646,7 +9013,7 @@ bool get_mapping(BurpGlobals* tdgbl) return true; } - BURP_verbose(298, ADMIN_ROLE); + BURP_verbose(298, MetaString(ADMIN_ROLE).toQuotedString().c_str()); // msg 298, restoring map @1 Firebird::string sql; sql.printf("%s ('%s', %d) %s", @@ -8721,7 +9088,7 @@ bool get_db_creator(BurpGlobals* tdgbl) STORE (REQUEST_HANDLE tdgbl->handles_get_db_creators_req_handle1) C IN RDB$DB_CREATORS - BURP_verbose (393, usr); + BURP_verbose(393, MetaString(usr).toQuotedString().c_str()); if (strlen(usr) > sizeof(C.RDB$USER)) BURP_error_redirect(NULL, 46); @@ -8778,9 +9145,8 @@ bool get_security_class(BurpGlobals* tdgbl) * Restore a security class record including access control list. * **************************************/ + MetaString name; att_type attribute; - TEXT temp[GDS_NAME_LEN]; - SSHORT l = 0; scan_attr_t scan_next_attr; bool is_valid_sec_class = false; @@ -8795,7 +9161,8 @@ bool get_security_class(BurpGlobals* tdgbl) switch (attribute) { case att_class_security_class: - l = GET_TEXT(X.RDB$SECURITY_CLASS); + GET_TEXT(X.RDB$SECURITY_CLASS); + name = X.RDB$SECURITY_CLASS; // Bug fix for bug_no 7299: There was a V3 bug that inserted // garbage security class entry when doing GBAK. In order to @@ -8804,17 +9171,15 @@ bool get_security_class(BurpGlobals* tdgbl) // valid ASCII name. If not, skip this entry by setting // 'is_valid_sec_class' to false. - is_valid_sec_class = is_ascii_name(X.RDB$SECURITY_CLASS, l); + is_valid_sec_class = is_ascii_name(X.RDB$SECURITY_CLASS, name.length()); if (!is_valid_sec_class) { - MISC_terminate (X.RDB$SECURITY_CLASS, temp, l, sizeof(temp)); - BURP_print (false, 234, temp); + BURP_print(false, 234, name.toQuotedString().c_str()); // msg 234 Skipped bad security class entry: %s break; } - MISC_terminate (X.RDB$SECURITY_CLASS, temp, l, sizeof(temp)); - BURP_verbose (125, temp); + BURP_verbose(125, name.toQuotedString().c_str()); // msg 125 restoring security class %s break; @@ -9056,7 +9421,7 @@ bool get_trigger_old (BurpGlobals* tdgbl, burp_rel* relation) TEXT* p = X.RDB$TRIGGER_NAME; const TEXT* const end = p + 31; - const TEXT* q = relation->rel_name; + const TEXT* q = relation->rel_name.object.c_str(); while (*q) { *p++ = *q++; } @@ -9085,9 +9450,9 @@ bool get_trigger_old (BurpGlobals* tdgbl, burp_rel* relation) *p++ = *q++; } *p = 0; - BURP_verbose (126, X.RDB$TRIGGER_NAME); + BURP_verbose(126, MetaString(X.RDB$TRIGGER_NAME).toQuotedString().c_str()); // msg 126 restoring trigger %s - strncpy (X.RDB$RELATION_NAME, relation->rel_name, GDS_NAME_LEN); + strncpy (X.RDB$RELATION_NAME, relation->rel_name.object.c_str(), GDS_NAME_LEN); strcpy (name, X.RDB$TRIGGER_NAME); X.RDB$TRIGGER_SEQUENCE = TRIGGER_SEQUENCE_DEFAULT; @@ -9128,8 +9493,11 @@ bool get_trigger(BurpGlobals* tdgbl) * Get a trigger definition in rdb$triggers. * **************************************/ + QualifiedMetaString name; + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + name.schema = PUBLIC_SCHEMA; + att_type attribute; - BASED_ON RDB$TRIGGERS.RDB$TRIGGER_NAME name; BASED_ON RDB$TRIGGERS.RDB$RELATION_NAME relName; scan_attr_t scan_next_attr; bool skipTrig = false; @@ -9141,7 +9509,8 @@ bool get_trigger(BurpGlobals* tdgbl) STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_trigger_req_handle1) X IN RDB$TRIGGERS - + { + X.RDB$SCHEMA_NAME.NULL = TRUE; X.RDB$RELATION_NAME.NULL = TRUE; X.RDB$DESCRIPTION.NULL = TRUE; X.RDB$TRIGGER_BLR.NULL = TRUE; @@ -9191,10 +9560,16 @@ bool get_trigger(BurpGlobals* tdgbl) get_source_blob (tdgbl, X.RDB$TRIGGER_SOURCE, true); break; + case att_trig_schema_name: + GET_TEXT(X.RDB$SCHEMA_NAME); + X.RDB$SCHEMA_NAME.NULL = FALSE; + name.schema = X.RDB$SCHEMA_NAME; + break; + case att_trig_name: GET_TEXT(X.RDB$TRIGGER_NAME); - strcpy (name, X.RDB$TRIGGER_NAME); - BURP_verbose (126, X.RDB$TRIGGER_NAME); + name.object = X.RDB$TRIGGER_NAME; + BURP_verbose(126, name.toQuotedString().c_str()); // msg 126 restoring trigger %s break; @@ -9206,8 +9581,9 @@ bool get_trigger(BurpGlobals* tdgbl) // Check for trigger on system relation FOR (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_trigger_req_handle2) Y IN RDB$RELATIONS - WITH Y.RDB$RELATION_NAME EQ relName - AND Y.RDB$SYSTEM_FLAG EQ 1 + WITH Y.RDB$SCHEMA_NAME EQUIV NULLIF(name.schema.c_str(), '') AND + Y.RDB$RELATION_NAME EQ relName AND + Y.RDB$SYSTEM_FLAG EQ 1 skipTrig = true; END_FOR; @@ -9297,14 +9673,14 @@ bool get_trigger(BurpGlobals* tdgbl) // Skip trigger on system relation if (skipTrig) { - BURP_message(387, SafeArg() << name << relName); + BURP_message(387, SafeArg() << name.toQuotedString().c_str() << relName); return true; } - - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR } else { @@ -9351,8 +9727,8 @@ bool get_trigger(BurpGlobals* tdgbl) case att_trig_name: GET_TEXT(X.RDB$TRIGGER_NAME); - strcpy (name, X.RDB$TRIGGER_NAME); - BURP_verbose (126, X.RDB$TRIGGER_NAME); + name.object = X.RDB$TRIGGER_NAME; + BURP_verbose(126, name.toQuotedString().c_str()); // msg 126 restoring trigger %s break; @@ -9441,7 +9817,7 @@ bool get_trigger(BurpGlobals* tdgbl) // Skip trigger on system relation if (skipTrig) { - BURP_message(387, SafeArg() << name << relName); + BURP_message(387, SafeArg() << name.toQuotedString().c_str() << relName); return true; } @@ -9456,7 +9832,7 @@ bool get_trigger(BurpGlobals* tdgbl) COMMIT // existing ON_ERROR continues past error, beck ON_ERROR - BURP_print (false, 94, name); + BURP_print(false, 94, name.toQuotedString().c_str()); // msg 94 trigger %s is invalid BURP_print_status(false, &tdgbl->status_vector); ROLLBACK; @@ -9483,10 +9859,13 @@ bool get_trigger_message(BurpGlobals* tdgbl) * Get a trigger message text. * **************************************/ + QualifiedMetaString name; + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + name.schema = PUBLIC_SCHEMA; + att_type attribute; scan_attr_t scan_next_attr; - - BASED_ON RDB$TRIGGER_MESSAGES.RDB$TRIGGER_NAME name; + TEXT temp[GDS_NAME_LEN]; BASED_ON RDB$TRIGGER_MESSAGES.RDB$MESSAGE_NUMBER number = -1; BASED_ON RDB$TRIGGER_MESSAGES.RDB$MESSAGE message; @@ -9496,18 +9875,28 @@ bool get_trigger_message(BurpGlobals* tdgbl) { switch (attribute) { + case att_trigmsg_schema_name: + GET_TEXT(temp); + name.schema = temp; + break; + case att_trigmsg_name: - GET_TEXT(name); + GET_TEXT(temp); + name.object = temp; sysflag = false; FOR (REQUEST_HANDLE tdgbl->handles_get_trigger_message_req_handle1) FIRST 1 X IN RDB$TRIGGERS WITH - X.RDB$SYSTEM_FLAG EQ 1 AND X.RDB$TRIGGER_NAME EQ name + X.RDB$SYSTEM_FLAG = 1 AND + X.RDB$SCHEMA_NAME EQUIV NULLIF(name.schema.c_str(), '') AND + X.RDB$TRIGGER_NAME = name.object.c_str() + { sysflag = true; - END_FOR; + } + END_FOR ON_ERROR general_on_error (); - END_ERROR; - BURP_verbose (127, name); + END_ERROR + BURP_verbose(127, name.toQuotedString().c_str()); // msg 127 restoring trigger message for %s break; @@ -9538,20 +9927,30 @@ bool get_trigger_message(BurpGlobals* tdgbl) STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_trigger_message_req_handle2) X IN RDB$TRIGGER_MESSAGES - strcpy (X.RDB$TRIGGER_NAME, name); + { + X.RDB$SCHEMA_NAME.NULL = TRUE; + + if (name.schema.hasData()) + { + strcpy(X.RDB$SCHEMA_NAME, name.schema.c_str()); + X.RDB$SCHEMA_NAME.NULL = FALSE; + } + + strcpy(X.RDB$TRIGGER_NAME, name.object.c_str()); X.RDB$MESSAGE_NUMBER = number; - strcpy (X.RDB$MESSAGE, message); - END_STORE; + strcpy(X.RDB$MESSAGE, message); + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR if (tdgbl->gbl_sw_incremental) { COMMIT // existing ON_ERROR continues past error, beck ON_ERROR - BURP_print (false, 94, name); + BURP_print(false, 94, name.toQuotedString().c_str()); // msg 94 trigger %s is invalid BURP_print_status(false, &tdgbl->status_vector); ROLLBACK; @@ -9630,7 +10029,7 @@ bool get_type(BurpGlobals* tdgbl) } MISC_terminate (X.RDB$TYPE_NAME, temp, len, sizeof(temp)); - BURP_verbose (128, SafeArg() << temp << X.RDB$FIELD_NAME); + BURP_verbose (128, SafeArg() << temp << MetaString(X.RDB$FIELD_NAME).toQuotedString().c_str()); // msg 128 restoring type %s for field %s END_STORE; @@ -9658,11 +10057,11 @@ bool get_user_privilege(BurpGlobals* tdgbl) scan_attr_t scan_next_attr; USHORT flags = 0; - BASED_ON RDB$USER_PRIVILEGES.RDB$USER user; + QualifiedMetaString user, relation; + TEXT temp[GDS_NAME_LEN]; BASED_ON RDB$USER_PRIVILEGES.RDB$GRANTOR grantor; BASED_ON RDB$USER_PRIVILEGES.RDB$PRIVILEGE privilege; BASED_ON RDB$USER_PRIVILEGES.RDB$GRANT_OPTION grant_option = 0; - BASED_ON RDB$USER_PRIVILEGES.RDB$RELATION_NAME relation_name; BASED_ON RDB$USER_PRIVILEGES.RDB$FIELD_NAME field_name; BASED_ON RDB$USER_PRIVILEGES.RDB$USER_TYPE user_type; BASED_ON RDB$USER_PRIVILEGES.RDB$OBJECT_TYPE object_type; @@ -9676,11 +10075,17 @@ bool get_user_privilege(BurpGlobals* tdgbl) { switch (attribute) { + case att_priv_user_schema_name: + GET_TEXT(temp); + user.schema = temp; + break; + case att_priv_user: // default USER_TYPE to USER flags |= USER_PRIV_USER; - GET_TEXT(user); - BURP_verbose (123, user); + GET_TEXT(temp); + user.object = temp; + BURP_verbose(123, user.toQuotedString().c_str()); // msg 123 restoring privilege for user %s break; @@ -9699,10 +10104,16 @@ bool get_user_privilege(BurpGlobals* tdgbl) grant_option = (USHORT) get_int32(tdgbl); break; + case att_priv_object_schema_name: + GET_TEXT(temp); + relation.schema = temp; + break; + case att_priv_object_name: flags |= USER_PRIV_OBJECT_NAME; // default OBJECT_TYPE to RELATION - GET_TEXT(relation_name); + GET_TEXT(temp); + relation.object = temp; break; case att_priv_field_name: @@ -9738,9 +10149,9 @@ bool get_user_privilege(BurpGlobals* tdgbl) switch (object_type) { case obj_package_header: - { for (const burp_pkg* pkg = tdgbl->packages; pkg; pkg = pkg->pkg_next) - if (strcmp(pkg->pkg_name, relation_name) == 0) + { + if (pkg->pkg_name == relation) { exists = true; local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans; @@ -9750,9 +10161,9 @@ bool get_user_privilege(BurpGlobals* tdgbl) break; case obj_procedure: - { for (const burp_prc* proc = tdgbl->procedures; proc; proc = proc->prc_next) - if (!proc->prc_package[0] && strcmp(proc->prc_name, relation_name) == 0) + { + if (proc->prc_name.package.isEmpty() && proc->prc_name == relation) { exists = true; local_trans = tdgbl->global_trans ? tdgbl->global_trans : gds_trans; @@ -9762,9 +10173,9 @@ bool get_user_privilege(BurpGlobals* tdgbl) break; case obj_relation: - { for (const burp_rel* rel = tdgbl->relations; rel; rel = rel->rel_next) - if (strcmp(rel->rel_name, relation_name) == 0) + { + if (rel->rel_name == relation) { exists = true; if (rel->rel_flags & REL_view) @@ -9780,9 +10191,9 @@ bool get_user_privilege(BurpGlobals* tdgbl) case obj_udf: case obj_field: case obj_generator: - { for (burp_meta_obj* object = tdgbl->miss_privs; object; object = object->obj_next) - if (object->obj_type == object_type && strcmp(object->obj_name, relation_name) == 0) + { + if (object->obj_type == object_type && object->obj_name == relation) { if (object->obj_class) exists = true; @@ -9822,13 +10233,21 @@ bool get_user_privilege(BurpGlobals* tdgbl) STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_user_privilege_req_handle1) X IN RDB$USER_PRIVILEGES - + { + X.RDB$USER_SCHEMA_NAME.NULL = TRUE; + X.RDB$RELATION_SCHEMA_NAME.NULL = TRUE; X.RDB$FIELD_NAME.NULL = TRUE; X.RDB$OBJECT_TYPE.NULL = TRUE; X.RDB$GRANT_OPTION.NULL = TRUE; + if (user.schema.hasData()) + { + strcpy(X.RDB$USER_SCHEMA_NAME, user.schema.c_str()); + X.RDB$USER_SCHEMA_NAME.NULL = FALSE; + } + if (flags & USER_PRIV_USER) - strcpy (X.RDB$USER, user); + strcpy(X.RDB$USER, user.object.c_str()); if (flags & USER_PRIV_GRANTOR) strcpy (X.RDB$GRANTOR, grantor); @@ -9842,8 +10261,14 @@ bool get_user_privilege(BurpGlobals* tdgbl) X.RDB$GRANT_OPTION = grant_option; } + if (relation.schema.hasData()) + { + strcpy(X.RDB$RELATION_SCHEMA_NAME, relation.schema.c_str()); + X.RDB$RELATION_SCHEMA_NAME.NULL = FALSE; + } + if (flags & USER_PRIV_OBJECT_NAME) - strcpy (X.RDB$RELATION_NAME, relation_name); + strcpy(X.RDB$RELATION_NAME, relation.object.c_str()); if (flags & USER_PRIV_FIELD_NAME) { @@ -9871,7 +10296,7 @@ bool get_user_privilege(BurpGlobals* tdgbl) // used at all. The following code should be uncommented // in case we ever introduce obj_field to the picture. -/*********************************************************** + /*********************************************************** if ( !(flags & USER_PRIV_OBJECT_TYPE) ) { if ( flags & USER_PRIV_FIELD_NAME ) @@ -9879,9 +10304,9 @@ bool get_user_privilege(BurpGlobals* tdgbl) X.RDB$OBJECT_TYPE = obj_field; } } -***********************************************************/ - - END_STORE; + ***********************************************************/ + } + END_STORE ON_ERROR if (tdgbl->status_vector->getErrors()[1] == isc_integ_fail) { @@ -9890,7 +10315,7 @@ bool get_user_privilege(BurpGlobals* tdgbl) return true; } general_on_error (); - END_ERROR; + END_ERROR } return true; @@ -9920,8 +10345,17 @@ bool get_view(BurpGlobals* tdgbl, burp_rel* relation) STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_view_req_handle1) X IN RDB$VIEW_RELATIONS + { + if (relation->rel_name.schema.hasData()) + { + strcpy(X.RDB$SCHEMA_NAME, relation->rel_name.schema.c_str()); + X.RDB$SCHEMA_NAME.NULL = FALSE; + } + else + X.RDB$SCHEMA_NAME.NULL = TRUE; - strcpy (X.RDB$VIEW_NAME, relation->rel_name); + strcpy(X.RDB$VIEW_NAME, relation->rel_name.object.c_str()); + X.RDB$RELATION_SCHEMA_NAME.NULL = TRUE; X.RDB$CONTEXT_TYPE.NULL = TRUE; X.RDB$PACKAGE_NAME.NULL = TRUE; @@ -9930,6 +10364,11 @@ bool get_view(BurpGlobals* tdgbl, burp_rel* relation) { switch (attribute) { + case att_view_relation_schema_name: + GET_TEXT(X.RDB$RELATION_SCHEMA_NAME); + X.RDB$RELATION_SCHEMA_NAME.NULL = FALSE; + break; + case att_view_relation_name: GET_TEXT(X.RDB$RELATION_NAME); break; @@ -9973,18 +10412,19 @@ bool get_view(BurpGlobals* tdgbl, burp_rel* relation) break; } } - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR } else { STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_view_req_handle1) X IN RDB$VIEW_RELATIONS - - strcpy (X.RDB$VIEW_NAME, relation->rel_name); + { + strcpy(X.RDB$VIEW_NAME, relation->rel_name.object.c_str()); skip_init(&scan_next_attr); while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end) @@ -10028,7 +10468,8 @@ bool get_view(BurpGlobals* tdgbl, burp_rel* relation) break; } } - END_STORE; + } + END_STORE ON_ERROR general_on_error (); END_ERROR; @@ -10435,6 +10876,7 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file Firebird::IRequest* req_handle3 = nullptr; Firebird::IRequest* req_handle4 = nullptr; Firebird::IRequest* req_handle5 = nullptr; + Firebird::IRequest* reqHandleDflCharSetSchema = nullptr; // Collect system fields { @@ -10444,15 +10886,14 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file FOR(REQUEST_HANDLE req_handle) X IN RDB$FIELDS WITH X.RDB$SYSTEM_FLAG EQ 1 - - const auto len = MISC_symbol_length(X.RDB$FIELD_NAME, sizeof(X.RDB$FIELD_NAME)); - MetaString name(X.RDB$FIELD_NAME, len); + { + const QualifiedMetaString name(X.RDB$FIELD_NAME, (X.RDB$SCHEMA_NAME.NULL ? "" : X.RDB$SCHEMA_NAME)); tdgbl->systemFields.add(name); - - END_FOR; + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR MISC_release_request_silent(req_handle); tdgbl->systemFields.sort(); @@ -10474,6 +10915,7 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file case att_database_description2: FOR (REQUEST_HANDLE req_handle2) X IN RDB$DATABASE + { MODIFY X USING if (attribute == att_database_description2) get_source_blob (tdgbl, X.RDB$DESCRIPTION, false); @@ -10483,25 +10925,45 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file ON_ERROR general_on_error (); END_ERROR; - END_FOR; + } + END_FOR ON_ERROR general_on_error (); - END_ERROR; + END_ERROR + break; + + case att_database_dfl_charset_schema_name: + FOR (REQUEST_HANDLE reqHandleDflCharSetSchema) + X IN RDB$DATABASE + { + MODIFY X USING + GET_TEXT(X.RDB$CHARACTER_SET_SCHEMA_NAME); + END_MODIFY + ON_ERROR + general_on_error (); + END_ERROR + } + END_FOR + ON_ERROR + general_on_error (); + END_ERROR break; case att_database_dfl_charset: FOR (REQUEST_HANDLE req_handle3) X IN RDB$DATABASE + { MODIFY X USING GET_TEXT(X.RDB$CHARACTER_SET_NAME); - END_MODIFY; + END_MODIFY ON_ERROR general_on_error (); - END_ERROR; - END_FOR; + END_ERROR + } + END_FOR ON_ERROR general_on_error (); - END_ERROR; + END_ERROR break; case att_database_linger: @@ -10511,16 +10973,18 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file { FOR (REQUEST_HANDLE req_handle4) X IN RDB$DATABASE + { MODIFY X USING X.RDB$LINGER = get_int32(tdgbl); END_MODIFY; ON_ERROR general_on_error(); - END_ERROR; - END_FOR; + END_ERROR + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } else get_int32(tdgbl); @@ -10541,16 +11005,18 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file { FOR (REQUEST_HANDLE req_handle5) X IN RDB$DATABASE + { MODIFY X USING X.RDB$SQL_SECURITY = get_boolean(tdgbl, attribute == att_database_sql_security_deprecated); END_MODIFY; ON_ERROR general_on_error(); - END_ERROR; - END_FOR; + END_ERROR + } + END_FOR ON_ERROR general_on_error(); - END_ERROR; + END_ERROR } else get_boolean(tdgbl, attribute == att_database_sql_security_deprecated); @@ -10610,15 +11076,16 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file FOR (REQUEST_HANDLE req_handle3) X IN RDB$CHARACTER_SETS - WITH X.RDB$CHARACTER_SET_NAME EQ name.c_str() - + WITH (X.RDB$SCHEMA_NAME MISSING OR X.RDB$SCHEMA_NAME = SYSTEM_SCHEMA) AND + X.RDB$CHARACTER_SET_NAME EQ name.c_str() + { tdgbl->gbl_sw_fix_fss_data_id = X.RDB$CHARACTER_SET_ID; found = true; - - END_FOR; + } + END_FOR ON_ERROR general_on_error (); - END_ERROR; + END_ERROR MISC_release_request_silent(req_handle3); @@ -10636,15 +11103,16 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file FOR (REQUEST_HANDLE req_handle3) X IN RDB$CHARACTER_SETS - WITH X.RDB$CHARACTER_SET_NAME EQ name.c_str() - + WITH (X.RDB$SCHEMA_NAME MISSING OR X.RDB$SCHEMA_NAME = SYSTEM_SCHEMA) AND + X.RDB$CHARACTER_SET_NAME EQ name.c_str() + { tdgbl->gbl_sw_fix_fss_metadata_id = X.RDB$CHARACTER_SET_ID; found = true; - - END_FOR; + } + END_FOR ON_ERROR general_on_error (); - END_ERROR; + END_ERROR MISC_release_request_silent(req_handle3); @@ -10778,6 +11246,12 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file return false; break; + case rec_schema: + if (!get_schema(tdgbl)) + return false; + flag = true; + break; + case rec_trigger: // new trigger type if (!get_trigger(tdgbl)) return false; @@ -10848,31 +11322,37 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file if (!task.finish()) return false; - if (tdgbl->defaultCollations.getCount() > 0) + if (tdgbl->defaultCollations.hasData()) { Firebird::IRequest* req_handle5 = nullptr; FOR (REQUEST_HANDLE req_handle5) CS IN RDB$CHARACTER_SETS - - for (FB_SIZE_T i = 0; i < tdgbl->defaultCollations.getCount(); ++i) + { + if (const auto collationName = tdgbl->defaultCollations.get( + QualifiedMetaString(CS.RDB$CHARACTER_SET_NAME, CS.RDB$SCHEMA_NAME))) { - if (tdgbl->defaultCollations[i].first == CS.RDB$CHARACTER_SET_NAME) + MODIFY CS { - MODIFY CS; - CS.RDB$DEFAULT_COLLATE_NAME.NULL = FALSE; - strcpy(CS.RDB$DEFAULT_COLLATE_NAME, - tdgbl->defaultCollations[i].second.c_str()); - END_MODIFY; - ON_ERROR - general_on_error (); - END_ERROR; + if (collationName->schema.hasData()) + { + CS.RDB$DEFAULT_COLLATE_SCHEMA_NAME.NULL = FALSE; + strcpy(CS.RDB$DEFAULT_COLLATE_SCHEMA_NAME, collationName->schema.c_str()); + } + + CS.RDB$DEFAULT_COLLATE_NAME.NULL = FALSE; + strcpy(CS.RDB$DEFAULT_COLLATE_NAME, collationName->object.c_str()); } + END_MODIFY + ON_ERROR + general_on_error (); + END_ERROR } - END_FOR; + } + END_FOR ON_ERROR general_on_error (); - END_ERROR; + END_ERROR MISC_release_request_silent(req_handle5); } @@ -10927,6 +11407,7 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file FOR (REQUEST_HANDLE req_handle6) IND IN RDB$INDICES WITH IND.RDB$SYSTEM_FLAG EQ 1 + { MODIFY IND IND.RDB$STATISTICS.NULL = FALSE; IND.RDB$STATISTICS = -1; @@ -10934,10 +11415,11 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file ON_ERROR general_on_error (); END_ERROR; - END_FOR; + } + END_FOR ON_ERROR general_on_error (); - END_ERROR; + END_ERROR MISC_release_request_silent(req_handle6); @@ -10988,7 +11470,7 @@ void restore_security_class(BurpGlobals* tdgbl, const TEXT* owner_nm, const TEXT USHORT get_view_base_relation_count(BurpGlobals* tdgbl, - const TEXT* current_view_name, + const QualifiedMetaString& current_view_name, USHORT depth, bool* error) { @@ -11021,9 +11503,11 @@ USHORT get_view_base_relation_count(BurpGlobals* tdgbl, V IN RDB$VIEW_RELATIONS CROSS R IN RDB$RELATIONS WITH - V.RDB$VIEW_NAME EQ current_view_name AND + V.RDB$SCHEMA_NAME EQUIV NULLIF(current_view_name.schema.c_str(), '') AND + V.RDB$VIEW_NAME EQ current_view_name.object.c_str() AND + R.RDB$SCHEMA_NAME EQUIV V.RDB$RELATION_SCHEMA_NAME AND R.RDB$RELATION_NAME EQ V.RDB$RELATION_NAME - + { if (R.RDB$VIEW_BLR.NULL) { // This relation is a table, so increment count @@ -11032,16 +11516,22 @@ USHORT get_view_base_relation_count(BurpGlobals* tdgbl, else { // Call recursive for VIEWS that are referenced in VIEWS - result += get_view_base_relation_count(tdgbl, V.RDB$RELATION_NAME, depth, error); + result += get_view_base_relation_count(tdgbl, + QualifiedMetaString( + V.RDB$RELATION_NAME, + (V.RDB$RELATION_SCHEMA_NAME.NULL ? "" : V.RDB$RELATION_SCHEMA_NAME) + ), + depth, error); + if (*error) break; } - END_FOR; - + } + END_FOR ON_ERROR MISC_release_request_silent(req_handle1); general_on_error(); - END_ERROR; + END_ERROR MISC_release_request_silent(req_handle1); @@ -11049,7 +11539,7 @@ USHORT get_view_base_relation_count(BurpGlobals* tdgbl, } -void store_blr_gen_id(BurpGlobals* tdgbl, const TEXT* gen_name, SINT64 value, SINT64 initial_value, +void store_blr_gen_id(BurpGlobals* tdgbl, const QualifiedMetaString& gen_name, SINT64 value, SINT64 initial_value, const ISC_QUAD* gen_desc, const char* secclass, const char* ownername, fb_sysflag sysFlag, SLONG increment) { @@ -11067,8 +11557,16 @@ void store_blr_gen_id(BurpGlobals* tdgbl, const TEXT* gen_name, SINT64 value, SI { STORE (REQUEST_HANDLE tdgbl->handles_store_blr_gen_id_req_handle1) X IN RDB$GENERATORS + { + X.RDB$SCHEMA_NAME.NULL = TRUE; - strcpy (X.RDB$GENERATOR_NAME, gen_name); + if (gen_name.schema.hasData()) + { + strcpy(X.RDB$SCHEMA_NAME, gen_name.schema.c_str()); + X.RDB$SCHEMA_NAME.NULL = FALSE; + } + + strcpy(X.RDB$GENERATOR_NAME, gen_name.object.c_str()); X.RDB$DESCRIPTION.NULL = TRUE; X.RDB$SYSTEM_FLAG = (SSHORT) sysFlag; X.RDB$SECURITY_CLASS.NULL = TRUE; @@ -11092,10 +11590,11 @@ void store_blr_gen_id(BurpGlobals* tdgbl, const TEXT* gen_name, SINT64 value, SI X.RDB$INITIAL_VALUE.NULL = FALSE; X.RDB$INITIAL_VALUE = initial_value; X.RDB$GENERATOR_INCREMENT = increment; - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR collect_missing_privs(tdgbl, obj_generator, gen_name, secclass); } @@ -11103,8 +11602,8 @@ void store_blr_gen_id(BurpGlobals* tdgbl, const TEXT* gen_name, SINT64 value, SI { STORE (REQUEST_HANDLE tdgbl->handles_store_blr_gen_id_req_handle1) X IN RDB$GENERATORS - - strcpy (X.RDB$GENERATOR_NAME, gen_name); + { + strcpy(X.RDB$GENERATOR_NAME, gen_name.object.c_str()); X.RDB$DESCRIPTION.NULL = TRUE; X.RDB$SYSTEM_FLAG = 0; X.RDB$SYSTEM_FLAG.NULL = FALSE; @@ -11113,28 +11612,30 @@ void store_blr_gen_id(BurpGlobals* tdgbl, const TEXT* gen_name, SINT64 value, SI X.RDB$DESCRIPTION = *gen_desc; X.RDB$DESCRIPTION.NULL = FALSE; } - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR } else { STORE (REQUEST_HANDLE tdgbl->handles_store_blr_gen_id_req_handle1) X IN RDB$GENERATORS - - strcpy (X.RDB$GENERATOR_NAME, gen_name); + { + strcpy(X.RDB$GENERATOR_NAME, gen_name.object.c_str()); X.RDB$SYSTEM_FLAG = 0; X.RDB$SYSTEM_FLAG.NULL = FALSE; - END_STORE; + } + END_STORE ON_ERROR general_on_error (); - END_ERROR; + END_ERROR } if (!value) { - BURP_verbose (185, SafeArg() << gen_name << 0); + BURP_verbose (185, SafeArg() << gen_name.toQuotedString().c_str() << 0); // msg 185 restoring generator %s value: %ld return; } @@ -11170,8 +11671,20 @@ void store_blr_gen_id(BurpGlobals* tdgbl, const TEXT* gen_name, SINT64 value, SI } add_byte(blr, blr_begin); add_byte(blr, blr_assignment); - add_byte(blr, blr_gen_id); - add_string(blr, gen_name); + + if (tdgbl->runtimeODS >= DB_VERSION_DDL14) + { + add_byte(blr, blr_gen_id3); + add_string(blr, gen_name.schema.c_str()); + add_string(blr, gen_name.object.c_str()); + add_byte(blr, 1); + } + else + { + add_byte(blr, blr_gen_id); + add_string(blr, gen_name.object.c_str()); + } + if (tdgbl->runtimeODS >= DB_VERSION_DDL10) { add_byte(blr, blr_literal); @@ -11184,8 +11697,9 @@ void store_blr_gen_id(BurpGlobals* tdgbl, const TEXT* gen_name, SINT64 value, SI add_byte(blr, blr_literal); add_byte(blr, blr_long); add_byte(blr, 0); - add_long(blr, (SLONG)value); + add_long(blr, (SLONG) value); } + add_byte(blr, blr_variable); add_word(blr, 0); add_byte(blr, blr_end); @@ -11211,7 +11725,7 @@ void store_blr_gen_id(BurpGlobals* tdgbl, const TEXT* gen_name, SINT64 value, SI BURP_error_redirect(&status_vector, 42); // msg 42 Failed in store_blr_gen_id } - BURP_verbose (185, SafeArg() << gen_name << value); + BURP_verbose (185, SafeArg() << gen_name.toQuotedString().c_str() << value); // msg 185 restoring generator %s value: %ld } @@ -11234,9 +11748,12 @@ void update_global_field(BurpGlobals* tdgbl) for (gfld* gfield = tdgbl->gbl_global_fields; gfield; ) { FOR (TRANSACTION_HANDLE tdgbl->global_trans REQUEST_HANDLE req_handle1) - X IN RDB$FIELDS WITH X.RDB$FIELD_NAME EQ gfield->gfld_name + X IN RDB$FIELDS + WITH X.RDB$SCHEMA_NAME EQUIV NULLIF(gfield->gfld_name.schema.c_str(), '') AND + X.RDB$FIELD_NAME EQ gfield->gfld_name.object.c_str() + { MODIFY X - + { if (gfield->gfld_flags & GFLD_validation_blr) { X.RDB$VALIDATION_BLR.NULL = FALSE; @@ -11272,16 +11789,16 @@ void update_global_field(BurpGlobals* tdgbl) X.RDB$COMPUTED_SOURCE.NULL = FALSE; memcpy(&X.RDB$COMPUTED_SOURCE, &gfield->gfld_computed_source2, sizeof(ISC_QUAD)); } - - END_MODIFY; + } + END_MODIFY ON_ERROR general_on_error (); - END_ERROR; - - END_FOR; + END_ERROR + } + END_FOR ON_ERROR general_on_error (); - END_ERROR; + END_ERROR gfld* n_gfield = gfield->gfld_next; BURP_free (gfield); @@ -11309,15 +11826,16 @@ void update_ownership(BurpGlobals* tdgbl) { FOR (REQUEST_HANDLE req_handle6) X IN RDB$PACKAGES - WITH X.RDB$PACKAGE_NAME EQ package->pkg_name + WITH X.RDB$SCHEMA_NAME EQUIV NULLIF(package->pkg_name.schema.c_str(), '') AND + X.RDB$PACKAGE_NAME = package->pkg_name.object.c_str() { MODIFY X strcpy(X.RDB$OWNER_NAME, package->pkg_owner); - END_MODIFY; + END_MODIFY ON_ERROR MISC_release_request_silent(req_handle6); general_on_error(); - END_ERROR; + END_ERROR if (!X.RDB$SECURITY_CLASS.NULL) restore_security_class(tdgbl, package->pkg_owner, X.RDB$SECURITY_CLASS); @@ -11341,8 +11859,9 @@ void update_ownership(BurpGlobals* tdgbl) { FOR (REQUEST_HANDLE req_handle4) X IN RDB$PROCEDURES - WITH X.RDB$PROCEDURE_NAME EQ procedure->prc_name AND - X.RDB$PACKAGE_NAME EQUIV NULLIF(procedure->prc_package, '') + WITH X.RDB$SCHEMA_NAME EQUIV NULLIF(procedure->prc_name.schema.c_str(), '') AND + X.RDB$PROCEDURE_NAME EQ procedure->prc_name.object.c_str() AND + X.RDB$PACKAGE_NAME EQUIV NULLIF(procedure->prc_name.package.c_str(), '') { MODIFY X strcpy (X.RDB$OWNER_NAME, procedure->prc_owner); @@ -11364,7 +11883,7 @@ void update_ownership(BurpGlobals* tdgbl) else { FOR (REQUEST_HANDLE req_handle4) - X IN RDB$PROCEDURES WITH X.RDB$PROCEDURE_NAME EQ procedure->prc_name + X IN RDB$PROCEDURES WITH X.RDB$PROCEDURE_NAME EQ procedure->prc_name.object.c_str() { MODIFY X strcpy (X.RDB$OWNER_NAME, procedure->prc_owner); @@ -11394,23 +11913,26 @@ void update_ownership(BurpGlobals* tdgbl) if (relation->rel_owner[0]) { FOR (REQUEST_HANDLE req_handle2) - X IN RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ relation->rel_name + X IN RDB$RELATIONS + WITH X.RDB$SCHEMA_NAME EQUIV NULLIF(relation->rel_name.schema.c_str(), '') AND + X.RDB$RELATION_NAME EQ relation->rel_name.object.c_str() + { MODIFY X strcpy (X.RDB$OWNER_NAME, relation->rel_owner); - END_MODIFY; + END_MODIFY ON_ERROR MISC_release_request_silent(req_handle2); general_on_error (); - END_ERROR; + END_ERROR restore_security_class(tdgbl, relation->rel_owner, X.RDB$SECURITY_CLASS); restore_security_class(tdgbl, relation->rel_owner, X.RDB$DEFAULT_CLASS); - - END_FOR; + } + END_FOR ON_ERROR MISC_release_request_silent(req_handle2); general_on_error (); - END_ERROR; + END_ERROR } } @@ -11446,9 +11968,15 @@ void update_view_dbkey_lengths(BurpGlobals* tdgbl) WITH R.RDB$VIEW_BLR NOT MISSING AND (R.RDB$SYSTEM_FLAG NE 1 OR R.RDB$SYSTEM_FLAG MISSING) - + { bool error = false; - const USHORT result = get_view_base_relation_count(tdgbl, R.RDB$RELATION_NAME, 0, &error); + const USHORT result = get_view_base_relation_count(tdgbl, + QualifiedMetaString( + R.RDB$RELATION_NAME, + (R.RDB$SCHEMA_NAME.NULL ? "" : R.RDB$SCHEMA_NAME) + ), + 0, &error); + fb_utils::exact_name(R.RDB$RELATION_NAME); if (error) BURP_error(339, false, SafeArg() << MAX_UPDATE_DBKEY_RECURSION_DEPTH << R.RDB$RELATION_NAME); @@ -11464,13 +11992,12 @@ void update_view_dbkey_lengths(BurpGlobals* tdgbl) MISC_release_request_silent(req_handle2); general_on_error(); END_ERROR; - - END_FOR; - + } + END_FOR ON_ERROR MISC_release_request_silent(req_handle2); general_on_error(); - END_ERROR; + END_ERROR MISC_release_request_silent(req_handle2); } @@ -11487,14 +12014,14 @@ void fix_missing_privileges(BurpGlobals* tdgbl) FOR (REQUEST_HANDLE req_handle1) REL IN RDB$RELATIONS WITH REL.RDB$RELATION_ID = 1 - + { strcpy(owner_name, REL.RDB$OWNER_NAME); - - END_FOR; + } + END_FOR ON_ERROR MISC_release_request_silent(req_handle1); general_on_error(); - END_ERROR; + END_ERROR MISC_release_request_silent(req_handle1); @@ -11509,7 +12036,7 @@ void fix_missing_privileges(BurpGlobals* tdgbl) { STORE (REQUEST_HANDLE req_handle2) X IN RDB$USER_PRIVILEGES - + { X.RDB$FIELD_NAME.NULL = TRUE; X.RDB$GRANTOR.NULL = TRUE; @@ -11519,8 +12046,16 @@ void fix_missing_privileges(BurpGlobals* tdgbl) X.RDB$USER.NULL = FALSE; strcpy(X.RDB$USER, (i == 0) ? "PUBLIC" : owner_name); + if (object->obj_name.schema.hasData()) + { + X.RDB$RELATION_SCHEMA_NAME.NULL = FALSE; + strcpy(X.RDB$RELATION_SCHEMA_NAME, object->obj_name.schema.c_str()); + } + else + X.RDB$RELATION_SCHEMA_NAME.NULL = TRUE; + X.RDB$RELATION_NAME.NULL = FALSE; - strcpy(X.RDB$RELATION_NAME, object->obj_name); + strcpy(X.RDB$RELATION_NAME, object->obj_name.object.c_str()); X.RDB$USER_TYPE.NULL = FALSE; X.RDB$USER_TYPE = obj_user; @@ -11530,12 +12065,12 @@ void fix_missing_privileges(BurpGlobals* tdgbl) X.RDB$GRANT_OPTION.NULL = FALSE; X.RDB$GRANT_OPTION = i; - - END_STORE; + } + END_STORE ON_ERROR MISC_release_request_silent(req_handle2); general_on_error(); - END_ERROR; + END_ERROR } } @@ -11578,7 +12113,7 @@ void fix_generator(BurpGlobals* tdgbl, const FixGenerator* g) " " " currentGen = gen_id(%s, 0); " " IF (currentGen < maxInTable) THEN " - " EXECUTE STATEMENT 'SET GENERATOR %s TO ' || maxInTable; " + " EXECUTE STATEMENT 'SET GENERATOR SYSTEM.%s TO ' || maxInTable; " "END", /* SELECT 1 */ g->field, start, g->table, g->field, start, g->field, g->prefix, /* SELECT 2 */ g->name, @@ -11841,7 +12376,7 @@ IBatch* WriteRelationMeta::createBatch(BurpGlobals* tdgbl, IAttachment* att) if (m_batchOk) return batch; - BURP_verbose(371, m_relation->rel_name); + BURP_verbose(371, m_relation->rel_name.toQuotedString().c_str()); // msg 371 could not start batch when restoring table @1, trying old way //BURP_print_status(false, fbStatus); @@ -11870,10 +12405,7 @@ bool WriteRelationMeta::prepareBatch(BurpGlobals* tdgbl) try { - string name(m_relation->rel_name); - BURP_makeSymbol(tdgbl, name); - - m_sqlStatement.printf("insert into %s(", name.c_str()); + m_sqlStatement.printf("insert into %s(", m_relation->rel_name.toQuotedString().c_str()); RefPtr builder(REF_NO_INCR, MasterInterfacePtr()->getMetadataBuilder(fbStatus, count)); @@ -11933,9 +12465,7 @@ bool WriteRelationMeta::prepareBatch(BurpGlobals* tdgbl) builder->setScale(&tdgbl->throwStatus, count, sqlScale); builder->setCharSet(&tdgbl->throwStatus, count, characterSetId); - name = field->fld_name; - BURP_makeSymbol(tdgbl, name); - m_sqlStatement += name; + m_sqlStatement += MetaString(field->fld_name).toQuotedString(); m_sqlStatement += ", "; field->fld_parameter = count++; @@ -12015,7 +12545,8 @@ void WriteRelationMeta::prepareRequest(BurpGlobals* tdgbl) // Time to generate blr to store data. Whoppee. - UCHAR* blr = m_blr.getBuffer(200 + length + count * 18); + UCHAR* blr = m_blr.getBuffer(200 + m_relation->rel_name.schema.length() + m_relation->rel_name.object.length() + + length + count * 18); add_byte(blr, blr_version4); add_byte(blr, blr_begin); @@ -12162,8 +12693,19 @@ void WriteRelationMeta::prepareRequest(BurpGlobals* tdgbl) add_byte(blr, 1); add_byte(blr, 0x10); // must be Jrd::StatementNode::MARK_BULK_INSERT - add_byte(blr, blr_relation); - add_string(blr, m_relation->rel_name); + if (m_relation->rel_name.schema.hasData()) + { + add_byte(blr, blr_relation3); + add_string(blr, m_relation->rel_name.schema.c_str()); + add_string(blr, m_relation->rel_name.object.c_str()); + add_string(blr, ""); + } + else + { + add_byte(blr, blr_relation); + add_string(blr, m_relation->rel_name.object.c_str()); + } + add_byte(blr, 0); // context variable add_byte(blr, blr_begin); @@ -12196,6 +12738,7 @@ void WriteRelationMeta::prepareRequest(BurpGlobals* tdgbl) add_byte(blr, blr_end); add_byte(blr, blr_eoc); + fb_assert(blr < m_blr.end()); const FB_SIZE_T blr_length = blr - m_blr.begin(); m_blr.shrink(blr_length); } @@ -12350,7 +12893,7 @@ bool RestoreRelationTask::fileReader(Item& item) BurpGlobals* tdgbl = item.m_gbl; fb_assert(tdgbl == m_masterGbl); - BURP_verbose(124, m_relation->rel_name); // msg 124 restoring data for relation %s + BURP_verbose(124, m_relation->rel_name.toQuotedString().c_str()); // msg 124 restoring data for relation %s const RCRD_LENGTH length = m_metadata.m_inMsgLen; // full record length diff --git a/src/common/IntlParametersBlock.cpp b/src/common/IntlParametersBlock.cpp index df92765bcc..bc2577b69b 100644 --- a/src/common/IntlParametersBlock.cpp +++ b/src/common/IntlParametersBlock.cpp @@ -195,6 +195,7 @@ IntlParametersBlock::TagType IntlDpb::checkTag(UCHAR tag, const char** tagName) FB_IPB_TAG(isc_dpb_host_name); FB_IPB_TAG(isc_dpb_os_user); FB_IPB_TAG(isc_dpb_owner); + FB_IPB_TAG(isc_dpb_search_path); return TAG_STRING; } @@ -324,6 +325,8 @@ IntlParametersBlock::TagType IntlSpbStart::checkTag(UCHAR tag, const char** tagN case isc_action_svc_validate: switch (tag) { + FB_IPB_TAG(isc_spb_val_sch_incl); + FB_IPB_TAG(isc_spb_val_sch_excl); FB_IPB_TAG(isc_spb_val_tab_incl); FB_IPB_TAG(isc_spb_val_tab_excl); FB_IPB_TAG(isc_spb_val_idx_incl); diff --git a/src/common/MsgMetadata.cpp b/src/common/MsgMetadata.cpp index fa428a7cda..657f4f2d01 100644 --- a/src/common/MsgMetadata.cpp +++ b/src/common/MsgMetadata.cpp @@ -149,6 +149,21 @@ void MetadataBuilder::setField(CheckStatusWrapper* status, unsigned index, const } } +void MetadataBuilder::setSchema(CheckStatusWrapper* status, unsigned index, const char* schema) +{ + try + { + MutexLockGuard g(mtx, FB_FUNCTION); + + indexError(index, "setSchema"); + msgMetadata->items[index].schema = schema; + } + catch (const Exception& ex) + { + ex.stuffException(status); + } +} + void MetadataBuilder::setRelation(CheckStatusWrapper* status, unsigned index, const char* relation) { try @@ -407,6 +422,9 @@ void MsgMetadata::assign(IMessageMetadata* from) items[index].field = from->getField(&status, index); check(&status); + items[index].schema = from->getSchema(&status, index); + check(&status); + items[index].relation = from->getRelation(&status, index); check(&status); diff --git a/src/common/MsgMetadata.h b/src/common/MsgMetadata.h index f39307764e..cfd241daa9 100644 --- a/src/common/MsgMetadata.h +++ b/src/common/MsgMetadata.h @@ -50,6 +50,7 @@ public: { explicit Item(MemoryPool& pool) : field(pool), + schema(pool), relation(pool), owner(pool), alias(pool), @@ -67,6 +68,7 @@ public: Item(MemoryPool& pool, const Item& v) : field(pool, v.field), + schema(pool, v.schema), relation(pool, v.relation), owner(pool, v.owner), alias(pool, v.alias), @@ -83,6 +85,7 @@ public: } string field; + string schema; string relation; string owner; string alias; @@ -165,6 +168,15 @@ public: return NULL; } + const char* getSchema(CheckStatusWrapper* status, unsigned index) + { + if (index < items.getCount()) + return items[index].schema.c_str(); + + raiseIndexError(status, index, "getSchema"); + return NULL; + } + const char* getRelation(CheckStatusWrapper* status, unsigned index) { if (index < items.getCount()) @@ -329,6 +341,7 @@ public: unsigned addField(CheckStatusWrapper* status); IMessageMetadata* getMetadata(CheckStatusWrapper* status); void setField(CheckStatusWrapper* status, unsigned index, const char* field); + void setSchema(CheckStatusWrapper* status, unsigned index, const char* schema); void setRelation(CheckStatusWrapper* status, unsigned index, const char* relation); void setOwner(CheckStatusWrapper* status, unsigned index, const char* owner); void setAlias(CheckStatusWrapper* status, unsigned index, const char* alias); diff --git a/src/common/ParserTokens.h b/src/common/ParserTokens.h index a45da1c81a..d1269cbf04 100644 --- a/src/common/ParserTokens.h +++ b/src/common/ParserTokens.h @@ -104,6 +104,7 @@ PARSER_TOKEN(TOK_BODY, "BODY", true) PARSER_TOKEN(TOK_BOOLEAN, "BOOLEAN", false) PARSER_TOKEN(TOK_BOTH, "BOTH", false) PARSER_TOKEN(TOK_BREAK, "BREAK", true) +PARSER_TOKEN(TOK_BTRIM, "BTRIM", false) PARSER_TOKEN(TOK_BY, "BY", false) PARSER_TOKEN(TOK_CALL, "CALL", false) PARSER_TOKEN(TOK_CALLER, "CALLER", true) @@ -157,6 +158,7 @@ PARSER_TOKEN(TOK_CURRENT, "CURRENT", false) PARSER_TOKEN(TOK_CURRENT_CONNECTION, "CURRENT_CONNECTION", false) PARSER_TOKEN(TOK_CURRENT_DATE, "CURRENT_DATE", false) PARSER_TOKEN(TOK_CURRENT_ROLE, "CURRENT_ROLE", false) +PARSER_TOKEN(TOK_CURRENT_SCHEMA, "CURRENT_SCHEMA", false) PARSER_TOKEN(TOK_CURRENT_TIME, "CURRENT_TIME", false) PARSER_TOKEN(TOK_CURRENT_TIMESTAMP, "CURRENT_TIMESTAMP", false) PARSER_TOKEN(TOK_CURRENT_TRANSACTION, "CURRENT_TRANSACTION", false) @@ -297,6 +299,7 @@ PARSER_TOKEN(TOK_LONG, "LONG", false) PARSER_TOKEN(TOK_LOWER, "LOWER", false) PARSER_TOKEN(TOK_LPAD, "LPAD", true) PARSER_TOKEN(TOK_LPARAM, "LPARAM", true) +PARSER_TOKEN(TOK_LTRIM, "LTRIM", false) PARSER_TOKEN(TOK_MAKE_DBKEY, "MAKE_DBKEY", true) PARSER_TOKEN(TOK_MANUAL, "MANUAL", true) PARSER_TOKEN(TOK_MAPPING, "MAPPING", true) @@ -440,11 +443,13 @@ PARSER_TOKEN(TOK_RSA_PRIVATE, "RSA_PRIVATE", true) PARSER_TOKEN(TOK_RSA_PUBLIC, "RSA_PUBLIC", true) PARSER_TOKEN(TOK_RSA_SIGN_HASH, "RSA_SIGN_HASH", true) PARSER_TOKEN(TOK_RSA_VERIFY_HASH, "RSA_VERIFY_HASH", true) +PARSER_TOKEN(TOK_RTRIM, "RTRIM", false) PARSER_TOKEN(TOK_SALT_LENGTH, "SALT_LENGTH", true) PARSER_TOKEN(TOK_SAVEPOINT, "SAVEPOINT", false) PARSER_TOKEN(TOK_SCALAR_ARRAY, "SCALAR_ARRAY", true) -PARSER_TOKEN(TOK_DATABASE, "SCHEMA", false) // Alias of DATABASE +PARSER_TOKEN(TOK_SCHEMA, "SCHEMA", false) PARSER_TOKEN(TOK_SCROLL, "SCROLL", false) +PARSER_TOKEN(TOK_SEARCH_PATH, "SEARCH_PATH", true) PARSER_TOKEN(TOK_SECOND, "SECOND", false) PARSER_TOKEN(TOK_SECURITY, "SECURITY", true) PARSER_TOKEN(TOK_SEGMENT, "SEGMENT", true) @@ -509,9 +514,6 @@ PARSER_TOKEN(TOK_TRANSACTION, "TRANSACTION", true) PARSER_TOKEN(TOK_TRAPS, "TRAPS", true) PARSER_TOKEN(TOK_TRIGGER, "TRIGGER", false) PARSER_TOKEN(TOK_TRIM, "TRIM", false) -PARSER_TOKEN(TOK_BTRIM, "BTRIM", false) -PARSER_TOKEN(TOK_LTRIM, "LTRIM", false) -PARSER_TOKEN(TOK_RTRIM, "RTRIM", false) PARSER_TOKEN(TOK_TRUE, "TRUE", false) PARSER_TOKEN(TOK_TRUNC, "TRUNC", true) PARSER_TOKEN(TOK_TRUSTED, "TRUSTED", true) diff --git a/src/common/StatementMetadata.cpp b/src/common/StatementMetadata.cpp index 11ddc467e7..2350d9bc07 100644 --- a/src/common/StatementMetadata.cpp +++ b/src/common/StatementMetadata.cpp @@ -43,6 +43,7 @@ static const UCHAR DESCRIBE_VARS[] = isc_info_sql_scale, isc_info_sql_length, isc_info_sql_field, + isc_info_sql_relation_schema, isc_info_sql_relation, isc_info_sql_owner, isc_info_sql_alias, @@ -337,6 +338,10 @@ void StatementMetadata::parse(unsigned bufferLength, const UCHAR* buffer) getStringInfo(&buffer, bufferEnd, ¶m->field); break; + case isc_info_sql_relation_schema: + getStringInfo(&buffer, bufferEnd, ¶m->schema); + break; + case isc_info_sql_relation: getStringInfo(&buffer, bufferEnd, ¶m->relation); break; diff --git a/src/common/TextType.h b/src/common/TextType.h index 858b9fb5c8..420d3ed292 100644 --- a/src/common/TextType.h +++ b/src/common/TextType.h @@ -30,7 +30,7 @@ #ifndef COMMON_TEXTTYPE_H #define COMMON_TEXTTYPE_H -#include "../common/classes/MetaString.h" +#include "../common/classes/QualifiedMetaString.h" struct texttype; @@ -96,7 +96,7 @@ public: USHORT getFlags() const; public: - Firebird::MetaString name; + Firebird::QualifiedMetaString name; protected: texttype* tt; diff --git a/src/common/classes/BlrReader.h b/src/common/classes/BlrReader.h index 8a8f9b9eac..cc654220d2 100644 --- a/src/common/classes/BlrReader.h +++ b/src/common/classes/BlrReader.h @@ -33,6 +33,12 @@ namespace Firebird { class BlrReader { +public: + struct Flags + { + bool searchSystemSchema = false; + }; + public: BlrReader(const UCHAR* buffer, unsigned maxLen) : start(buffer), @@ -121,6 +127,50 @@ public: return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1; } + UCHAR parseHeader(Flags* flags = nullptr) + { + const auto version = getByte(); + + switch (version) + { + case blr_version4: + case blr_version5: + //case blr_version6: + break; + + default: + status_exception::raise( + Arg::Gds(isc_metadata_corrupt) << + Arg::Gds(isc_wroblrver2) << Arg::Num(blr_version4) << Arg::Num(blr_version5/*6*/) << + Arg::Num(version)); + } + + auto code = getByte(); + + if (code == blr_flags) + { + while ((code = getByte()) != blr_end) + { + if (flags) + { + switch (code) + { + case blr_flags_search_system_schema: + flags->searchSystemSchema = true; + break; + } + } + + const auto len = getWord(); + seekForward(len); + } + } + else + seekBackward(1); + + return version; + } + UCHAR checkByte(UCHAR expected) { UCHAR byte = getByte(); diff --git a/src/common/classes/ClumpletReader.cpp b/src/common/classes/ClumpletReader.cpp index df1232e2cd..36cf84bc8b 100644 --- a/src/common/classes/ClumpletReader.cpp +++ b/src/common/classes/ClumpletReader.cpp @@ -490,6 +490,8 @@ ClumpletReader::ClumpletType ClumpletReader::getClumpletType(UCHAR tag) const case isc_action_svc_validate: switch (tag) { + case isc_spb_val_sch_incl: + case isc_spb_val_sch_excl: case isc_spb_val_tab_incl: case isc_spb_val_tab_excl: case isc_spb_val_idx_incl: diff --git a/src/common/classes/MetaString.h b/src/common/classes/MetaString.h index 6c954d3c07..38fc2c2d0b 100644 --- a/src/common/classes/MetaString.h +++ b/src/common/classes/MetaString.h @@ -31,7 +31,11 @@ #include "../common/classes/fb_string.h" #include "../common/classes/fb_pair.h" +#include "../common/classes/objects_array.h" +#include "../common/StatusArg.h" #include "../jrd/constants.h" +#include +#include #ifdef SFIO #include @@ -68,6 +72,119 @@ public: MetaString(MemoryPool&, const MetaString& m) { set(m); } MetaString(MemoryPool&, const AbstractString& s) { assign(s.c_str(), s.length()); } +public: + static void parseList(const string& str, ObjectsArray& list) + { + auto pos = str.begin(); + + const auto skipSpaces = [&pos, &str] + { + while (pos != str.end() && (*pos == ' ' || *pos == '\t' || *pos == '\f' || *pos == '\r' || *pos == '\n')) + ++pos; + + return pos != str.end(); + }; + + const auto isQuoted = [](const string& name) -> bool + { + return name.length() >= 2 && name[0] == '"' && name[name.length() - 1] == '"'; + }; + + const auto unquote = [&](const string& name) -> string + { + if (!isQuoted(name)) + return name; + + string result; + + for (size_t i = 1; i < name.length() - 1; ++i) + { + if (name[i] == '"') + { + if (i + 1 < name.length() - 1 && name[i + 1] == '"') + ++i; + else + (Arg::Gds(isc_invalid_unqualified_name_list) << str).raise(); + } + + result += name[i]; + } + + return result; + }; + + const auto validateUnquotedIdentifier = [&](const string& name) + { + bool first = true; + + for (const auto c : name) + { + if (!((c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + c == '{' || + c == '}' || + (!first && c >= '0' && c <= '9') || + (!first && c == '$') || + (!first && c == '_'))) + { + (Arg::Gds(isc_invalid_unqualified_name_list) << str).raise(); + } + + first = false; + } + + return true; + }; + + list.clear(); + + if (!skipSpaces()) + return; + + do + { + const auto nameStart = pos; + auto nameEnd = pos; + bool inQuotes = false; + + while (pos != str.end()) + { + if (*pos == '"') + inQuotes = !inQuotes; + else if (*pos == ',' && !inQuotes) + break; + + nameEnd = ++pos; + skipSpaces(); + } + + string name(nameStart, nameEnd); + + if (isQuoted(name)) + name = unquote(name); + else + { + validateUnquotedIdentifier(name); + std::transform(name.begin(), name.end(), name.begin(), ::toupper); + } + + if (name.isEmpty()) + (Arg::Gds(isc_invalid_unqualified_name_list) << str).raise(); + + list.add(name); + + if (pos == str.end()) + break; + + if (*pos == ',') + { + ++pos; + skipSpaces(); + } + } while(true); + } + +public: MetaString& assign(const char* s, FB_SIZE_T l); MetaString& assign(const char* s) { return assign(s, s ? fb_strlen(s) : 0); } MetaString& clear() { return assign(nullptr, 0); } diff --git a/src/common/classes/QualifiedMetaString.h b/src/common/classes/QualifiedMetaString.h new file mode 100644 index 0000000000..f99777cc59 --- /dev/null +++ b/src/common/classes/QualifiedMetaString.h @@ -0,0 +1,272 @@ +/* + * 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 Adriano dos Santos Fernandes + * for the Firebird Open Source RDBMS project. + * + * Copyright (c) 2024 Adriano dos Santos Fernandes + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + */ + +#ifndef QUALIFIED_METASTRING_H +#define QUALIFIED_METASTRING_H + +#include "../common/classes/MetaString.h" +#include "../common/StatusArg.h" +#include +#include + +namespace Firebird { + +template +class BaseQualifiedName +{ +public: + explicit BaseQualifiedName(MemoryPool& p, const T& aObject, + const T& aSchema = {}, const T& aPackage = {}) + : object(p, aObject), + schema(p, aSchema), + package(p, aPackage) + { + } + + explicit BaseQualifiedName(const T& aObject, const T& aSchema = {}, const T& aPackage = {}) + : object(aObject), + schema(aSchema), + package(aPackage) + { + } + + BaseQualifiedName(MemoryPool& p, const BaseQualifiedName& src) + : object(p, src.object), + schema(p, src.schema), + package(p, src.package) + { + } + + BaseQualifiedName(const BaseQualifiedName& src) + : object(src.object), + schema(src.schema), + package(src.package) + { + } + + template + BaseQualifiedName(const BaseQualifiedName& src) + : object(src.object), + schema(src.schema), + package(src.package) + { + } + + explicit BaseQualifiedName(MemoryPool& p) + : object(p), + schema(p), + package(p) + { + } + + BaseQualifiedName() + { + } + +public: + static BaseQualifiedName parseSchemaObject(const string& str) + { + const auto isQuoted = [](const string& name) -> bool + { + return name.length() >= 2 && name[0] == '"' && name[name.length() - 1] == '"'; + }; + + const auto unquote = [&](const string& name) -> string + { + if (!isQuoted(name)) + return name; + + string result; + + for (size_t i = 1; i < name.length() - 1; ++i) + { + if (name[i] == '"') + { + if (i + 1 < name.length() - 1 && name[i + 1] == '"') + ++i; + else + (Arg::Gds(isc_invalid_name) << str).raise(); + } + + result += name[i]; + } + + return result; + }; + + const auto validateUnquotedIdentifier = [&](const string& name) + { + bool first = true; + + for (const auto c : name) + { + if (!((c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + c == '{' || + c == '}' || + (!first && c >= '0' && c <= '9') || + (!first && c == '$') || + (!first && c == '_'))) + { + (Arg::Gds(isc_invalid_name) << str).raise(); + } + + first = false; + } + + return true; + }; + + BaseQualifiedName result; + string schema, object; + + // Find the last unquoted dot to determine schema and object + bool inQuotes = false; + auto lastDotPos = string::npos; + + for (size_t i = 0; i < str.size(); ++i) + { + if (str[i] == '"') + inQuotes = !inQuotes; + else if (str[i] == '.' && !inQuotes) + lastDotPos = i; + } + + if (lastDotPos != string::npos) + { + schema = str.substr(0, lastDotPos); + object = str.substr(lastDotPos + 1); + } + else + object = str; + + schema.trim(" \t\f\r\n"); + object.trim(" \t\f\r\n"); + + // Process schema if it exists + if (schema.hasData()) + { + if (isQuoted(schema)) + result.schema = unquote(schema); + else + { + validateUnquotedIdentifier(schema); + + std::transform(schema.begin(), schema.end(), schema.begin(), ::toupper); + result.schema = schema; + } + } + + if (lastDotPos != string::npos && result.schema.isEmpty()) + (Arg::Gds(isc_invalid_name) << str).raise(); + + // Process object + if (isQuoted(object)) + result.object = unquote(object); + else + { + validateUnquotedIdentifier(object); + + std::transform(object.begin(), object.end(), object.begin(), ::toupper); + result.object = object; + } + + if (result.object.isEmpty()) + (Arg::Gds(isc_invalid_name) << str).raise(); + + return result; + } + +public: + bool operator<(const BaseQualifiedName& m) const + { + return schema < m.schema || + (schema == m.schema && object < m.object) || + (schema == m.schema && object == m.object && package < m.package); + } + + bool operator>(const BaseQualifiedName& m) const + { + return schema > m.schema || + (schema == m.schema && object > m.object) || + (schema == m.schema && object == m.object && package > m.package); + } + + bool operator==(const BaseQualifiedName& m) const + { + return schema == m.schema && object == m.object && package == m.package; + } + + bool operator!=(const BaseQualifiedName& m) const + { + return !(*this == m); + } + +public: + BaseQualifiedName getSchemaAndPackage() const + { + return BaseQualifiedName(package, schema); + } + + void clear() + { + object = {}; + schema = {}; + package = {}; + } + + Firebird::string toQuotedString() const + { + Firebird::string s; + + const auto appendName = [&s](const T& name) { + if (name.hasData()) + { + s += name.toQuotedString(); + return true; + } + + return false; + }; + + if (appendName(schema)) + s.append("."); + + if (appendName(package)) + s.append("."); + + appendName(object); + + return s; + } + +public: + T object; + T schema; + T package; +}; + +using QualifiedMetaString = Firebird::BaseQualifiedName; + +} // namespace Firebird + +#endif // QUALIFIED_METASTRING_H diff --git a/src/common/classes/array.h b/src/common/classes/array.h index 8b3ff24d9d..648fa7c1ff 100644 --- a/src/common/classes/array.h +++ b/src/common/classes/array.h @@ -145,6 +145,13 @@ public: add(item); } + Array(std::initializer_list items) + : Array() + { + for (auto& item : items) + add(item); + } + ~Array() { freeData(); diff --git a/src/common/classes/objects_array.h b/src/common/classes/objects_array.h index 449173d09b..c7fb9f58a6 100644 --- a/src/common/classes/objects_array.h +++ b/src/common/classes/objects_array.h @@ -306,12 +306,24 @@ namespace Firebird return iterator(this, getCount()); } + const T& front() const + { + fb_assert(getCount() > 0); + return *begin(); + } + T& front() { - fb_assert(getCount() > 0); + fb_assert(getCount() > 0); return *begin(); } + const T& back() const + { + fb_assert(getCount() > 0); + return *iterator(this, getCount() - 1); + } + T& back() { fb_assert(getCount() > 0); @@ -372,6 +384,13 @@ namespace Firebird add(item); } + ObjectsArray(std::initializer_list items) + : A() + { + for (auto& item : items) + add(item); + } + ObjectsArray() : A() { diff --git a/src/common/classes/tests/MetaStringTest.cpp b/src/common/classes/tests/MetaStringTest.cpp new file mode 100644 index 0000000000..d3cd101508 --- /dev/null +++ b/src/common/classes/tests/MetaStringTest.cpp @@ -0,0 +1,74 @@ +#include "boost/test/unit_test.hpp" +#include "boost/test/data/test_case.hpp" +#include "../common/classes/MetaString.h" +#include "../common/classes/objects_array.h" +#include +#include +#include + +using namespace Firebird; +using std::make_tuple; + + +BOOST_AUTO_TEST_SUITE(MetaStringSuite) +BOOST_AUTO_TEST_SUITE(MetaStringTests) + + +const auto parseTestData = boost::unit_test::data::make({ + make_tuple("Object1", "\"OBJECT1\""), + make_tuple(" Object2 ", "\"OBJECT2\""), + make_tuple(" Object3 , Object4 ", "\"OBJECT3\", \"OBJECT4\""), + make_tuple(" \"Object5 \" , \" Object6 \" ", "\"Object5\", \" Object6\""), + make_tuple(" Object7 , \" Object8 \" ", "\"OBJECT7\", \" Object8\""), + make_tuple(" Object9 , Object10 ", "\"OBJECT9\", \"OBJECT10\""), +}); + +BOOST_DATA_TEST_CASE(ParseTest, parseTestData, input, formattedList) +{ + const auto parseAndFormatList = [](const char* input) -> std::string + { + ObjectsArray list; + MetaString::parseList(input, list); + + if (list.hasData()) + { + return std::accumulate( + std::next(list.begin()), + list.end(), + std::string(list[0].toQuotedString().c_str()), + [](const auto& a, const auto& b) { + return a + ", " + (b.hasData() ? b.toQuotedString().c_str() : "\" \""); + } + ); + } + else + return {}; + }; + + BOOST_TEST(parseAndFormatList(input) == formattedList); +} + + +const auto parseErrorTestData = boost::unit_test::data::make({ + "1Object", + "_Object", + "$Object", + "\"\"name\"", + "Na me", + "Na.me", + "Name," + "Name, " + "," + "Name,,Name", +}); + +BOOST_DATA_TEST_CASE(ParseErrorTest, parseErrorTestData, input) +{ + ObjectsArray array; + BOOST_CHECK_THROW(MetaString::parseList(input, array), status_exception); +} + + + +BOOST_AUTO_TEST_SUITE_END() // MetaStringTests +BOOST_AUTO_TEST_SUITE_END() // MetaStringSuite diff --git a/src/common/classes/tests/QualifiedMetaStringTest.cpp b/src/common/classes/tests/QualifiedMetaStringTest.cpp new file mode 100644 index 0000000000..47f8f76d13 --- /dev/null +++ b/src/common/classes/tests/QualifiedMetaStringTest.cpp @@ -0,0 +1,64 @@ +#include "boost/test/unit_test.hpp" +#include "boost/test/data/test_case.hpp" +#include "../common/classes/QualifiedMetaString.h" +#include + +using namespace Firebird; +using std::make_tuple; + + +BOOST_AUTO_TEST_SUITE(QualifiedMetaStringSuite) +BOOST_AUTO_TEST_SUITE(QualifiedMetaStringTests) + + +const auto parseTestData = boost::unit_test::data::make({ + make_tuple("Object", "", "OBJECT"), + make_tuple("Schema$_0.{Object}", "SCHEMA$_0", "{OBJECT}"), + make_tuple("Schema.Object", "SCHEMA", "OBJECT"), + make_tuple("\"A\"\"name\"", "", "A\"name"), + make_tuple("Schema.\"Name\"", "SCHEMA", "Name"), + make_tuple("\"Schema\".Name", "Schema", "NAME"), + make_tuple("\"Sche ma\".\"Na me\"", "Sche ma", "Na me"), + make_tuple(" x . y ", "X", "Y"), + make_tuple(" \" x \" . \" y \" ", " x ", " y "), + make_tuple(" \"x\" . \"y\" ", "x", "y"), + make_tuple(" \"Sch\"\"ma\" . \"Obj\"\"ect\" ", "Sch\"ma", "Obj\"ect"), +}); + +BOOST_DATA_TEST_CASE(ParseTest, parseTestData, input, expectedSchema, expectedObject) +{ + const auto name = QualifiedMetaString::parseSchemaObject(input); + BOOST_TEST(name.schema == MetaString(expectedSchema)); + BOOST_TEST(name.object == MetaString(expectedObject)); +} + + +const auto parseErrorTestData = boost::unit_test::data::make({ + "1Object", + "_Object", + "$Object", + "\"\"name\"", + "Sche ma.Na me", + "Sch.ema.\"Na.me\"", + "a.b.c", + "a\"b\".c\"d\"", + "", + " ", + ".", + " . ", + "\"\"", + "\" \"", + "\"\".\"\"", + "\" \".\" \"", + "\" \" . \" \"", +}); + +BOOST_DATA_TEST_CASE(ParseErrorTest, parseErrorTestData, input) +{ + BOOST_CHECK_THROW(QualifiedMetaString::parseSchemaObject(input), status_exception); +} + + + +BOOST_AUTO_TEST_SUITE_END() // QualifiedMetaStringTests +BOOST_AUTO_TEST_SUITE_END() // QualifiedMetaStringSuite diff --git a/src/common/pretty.cpp b/src/common/pretty.cpp index d1a0e6956d..b744fb9547 100644 --- a/src/common/pretty.cpp +++ b/src/common/pretty.cpp @@ -815,6 +815,7 @@ static int print_sdl_verb( ctl* control, SSHORT level) return 0; case isc_sdl_field: + case isc_sdl_schema: case isc_sdl_relation: print_string(control, offset); break; diff --git a/src/common/sdl.cpp b/src/common/sdl.cpp index 0059a6bda3..a730dad586 100644 --- a/src/common/sdl.cpp +++ b/src/common/sdl.cpp @@ -175,7 +175,8 @@ ISC_STATUS SDL_info(CheckStatusWrapper* status_vector, const UCHAR* p = sdl; info->sdl_info_fid = info->sdl_info_rid = 0; - info->sdl_info_relation = info->sdl_info_field = ""; + info->sdl_info_relation.clear(); + info->sdl_info_field.clear(); if (*p++ != isc_sdl_version1) return error(status_vector, Arg::Gds(isc_invalid_sdl) << Arg::Num(0)); @@ -207,9 +208,15 @@ ISC_STATUS SDL_info(CheckStatusWrapper* status_vector, p += n; break; + case isc_sdl_schema: + n = *p++; + info->sdl_info_relation.schema.assign(reinterpret_cast(p), n); + p += n; + break; + case isc_sdl_relation: n = *p++; - info->sdl_info_relation.assign(reinterpret_cast(p), n); + info->sdl_info_relation.object.assign(reinterpret_cast(p), n); p += n; break; @@ -281,6 +288,7 @@ int SDL_walk(CheckStatusWrapper* status_vector, break; case isc_sdl_field: + case isc_sdl_schema: case isc_sdl_relation: n = *p++; p += n; diff --git a/src/common/sdl.h b/src/common/sdl.h index ff8016a3a1..f3914f04a3 100644 --- a/src/common/sdl.h +++ b/src/common/sdl.h @@ -25,6 +25,7 @@ #define JRD_SDL_H #include "../common/classes/MetaString.h" +#include "../common/classes/QualifiedMetaString.h" #include "../common/dsc.h" struct sdl_info @@ -32,7 +33,7 @@ struct sdl_info USHORT sdl_info_fid; USHORT sdl_info_rid; Firebird::MetaString sdl_info_field; - Firebird::MetaString sdl_info_relation; + Firebird::QualifiedMetaString sdl_info_relation; dsc sdl_info_element; USHORT sdl_info_dimensions; SLONG sdl_info_lower[MAX_ARRAY_DIMENSIONS]; diff --git a/src/dbs/security.sql b/src/dbs/security.sql index c184981707..8c3b908ac9 100644 --- a/src/dbs/security.sql +++ b/src/dbs/security.sql @@ -23,8 +23,8 @@ */ /* Domain definitions */ -CREATE DOMAIN PLG$PASSWD AS VARBINARY(64); -CREATE DOMAIN PLG$ID AS INTEGER; +CREATE DOMAIN PUBLIC.PLG$PASSWD AS VARBINARY(64); +CREATE DOMAIN PUBLIC.PLG$ID AS INTEGER; COMMIT; @@ -36,41 +36,41 @@ COMMIT; /* Table: RDB$USERS */ -CREATE TABLE PLG$USERS ( - PLG$USER_NAME SEC$USER_NAME NOT NULL PRIMARY KEY, - PLG$GROUP_NAME SEC$USER_NAME, - PLG$UID PLG$ID, - PLG$GID PLG$ID, - PLG$PASSWD PLG$PASSWD NOT NULL, - PLG$COMMENT RDB$DESCRIPTION, - PLG$FIRST_NAME SEC$NAME_PART, - PLG$MIDDLE_NAME SEC$NAME_PART, - PLG$LAST_NAME SEC$NAME_PART); +CREATE TABLE PUBLIC.PLG$USERS ( + PLG$USER_NAME SYSTEM.SEC$USER_NAME NOT NULL PRIMARY KEY, + PLG$GROUP_NAME SYSTEM.SEC$USER_NAME, + PLG$UID PUBLIC.PLG$ID, + PLG$GID PUBLIC.PLG$ID, + PLG$PASSWD PUBLIC.PLG$PASSWD NOT NULL, + PLG$COMMENT SYSTEM.RDB$DESCRIPTION, + PLG$FIRST_NAME SYSTEM.SEC$NAME_PART, + PLG$MIDDLE_NAME SYSTEM.SEC$NAME_PART, + PLG$LAST_NAME SYSTEM.SEC$NAME_PART); COMMIT; /* VIEW: PLG$VIEW_USERS */ -CREATE VIEW PLG$VIEW_USERS (PLG$USER_NAME, PLG$GROUP_NAME, PLG$UID, PLG$GID, PLG$PASSWD, +CREATE VIEW PUBLIC.PLG$VIEW_USERS (PLG$USER_NAME, PLG$GROUP_NAME, PLG$UID, PLG$GID, PLG$PASSWD, PLG$COMMENT, PLG$FIRST_NAME, PLG$MIDDLE_NAME, PLG$LAST_NAME) AS SELECT PLG$USER_NAME, PLG$GROUP_NAME, PLG$UID, PLG$GID, PLG$PASSWD, PLG$COMMENT, PLG$FIRST_NAME, PLG$MIDDLE_NAME, PLG$LAST_NAME - FROM PLG$USERS + FROM PUBLIC.PLG$USERS WHERE CURRENT_USER = 'SYSDBA' OR CURRENT_ROLE = 'RDB$ADMIN' OR CURRENT_USER = PLG$USERS.PLG$USER_NAME; /* Access rights */ -GRANT ALL ON PLG$USERS to VIEW PLG$VIEW_USERS; -GRANT SELECT ON PLG$VIEW_USERS to PUBLIC; +GRANT ALL ON PUBLIC.PLG$USERS to VIEW PUBLIC.PLG$VIEW_USERS; +GRANT SELECT ON PUBLIC.PLG$VIEW_USERS to PUBLIC; GRANT UPDATE(PLG$PASSWD, PLG$GROUP_NAME, PLG$UID, PLG$GID, PLG$FIRST_NAME, PLG$MIDDLE_NAME, PLG$LAST_NAME) - ON PLG$VIEW_USERS TO PUBLIC; + ON PUBLIC.PLG$VIEW_USERS TO PUBLIC; COMMIT; /* Needed record - with PASSWD = random + SHA1 (random + 'SYSDBA' + crypt('masterke')) */ -INSERT INTO PLG$USERS(PLG$USER_NAME, PLG$PASSWD, PLG$FIRST_NAME, PLG$MIDDLE_NAME, PLG$LAST_NAME) +INSERT INTO PUBLIC.PLG$USERS(PLG$USER_NAME, PLG$PASSWD, PLG$FIRST_NAME, PLG$MIDDLE_NAME, PLG$LAST_NAME) VALUES ('SYSDBA', 'NLtwcs9LrxLMOYhG0uGM9i6KS7mf3QAKvFVpmRg=', 'Sql', 'Server', 'Administrator'); COMMIT; diff --git a/src/dsql/BlrDebugWriter.cpp b/src/dsql/BlrDebugWriter.cpp index 864264b066..a6b43aeaf0 100644 --- a/src/dsql/BlrDebugWriter.cpp +++ b/src/dsql/BlrDebugWriter.cpp @@ -142,7 +142,7 @@ void BlrDebugWriter::putDebugSubFunction(DeclareSubFuncNode* subFuncNode) debugData.add(fb_dbg_subfunc); dsql_udf* subFunc = subFuncNode->dsqlFunction; - const MetaName& name = subFunc->udf_name.identifier; + const auto& name = subFunc->udf_name.object; USHORT len = MIN(name.length(), MAX_UCHAR); debugData.add(len); @@ -162,7 +162,7 @@ void BlrDebugWriter::putDebugSubProcedure(DeclareSubProcNode* subProcNode) debugData.add(fb_dbg_subproc); dsql_prc* subProc = subProcNode->dsqlProcedure; - const MetaName& name = subProc->prc_name.identifier; + const auto& name = subProc->prc_name.object; USHORT len = MIN(name.length(), MAX_UCHAR); debugData.add(len); diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 5a3cd5eed3..f4a93444f8 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -70,35 +70,35 @@ namespace Jrd { using namespace Firebird; static void checkForeignKeyTempScope(thread_db* tdbb, jrd_tra* transaction, - const MetaName& childRelName, const MetaName& masterIndexName); + const QualifiedName& childRelName, const QualifiedName& masterIndexName); static void checkSpTrigDependency(thread_db* tdbb, jrd_tra* transaction, - const MetaName& relationName, const MetaName& fieldName); + const QualifiedName& relationName, const MetaName& fieldName); static void checkViewDependency(thread_db* tdbb, jrd_tra* transaction, - const MetaName& relationName, const MetaName& fieldName); + const QualifiedName& relationName, const MetaName& fieldName); static void clearPermanentField(dsql_rel* relation, bool permanent); static void defineComputed(DsqlCompilerScratch* dsqlScratch, RelationSourceNode* relation, dsql_fld* field, ValueSourceClause* clause, string& source, BlrDebugWriter::BlrData& value); static void deleteKeyConstraint(thread_db* tdbb, jrd_tra* transaction, - const MetaName& relationName, const MetaName& constraintName, const MetaName& indexName); -static bool fieldExists(thread_db* tdbb, jrd_tra* transaction, const MetaName& relationName, + const QualifiedName& relationName, const MetaName& constraintName, const MetaName& indexName); +static bool fieldExists(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& relationName, const MetaName& fieldName); static bool isItSqlRole(thread_db* tdbb, jrd_tra* transaction, const MetaName& inputName, MetaName& outputName); static int getGrantorOption(thread_db* tdbb, jrd_tra* transaction, const MetaName& grantor, int grantorType, const MetaName& roleName); -static MetaName getIndexRelationName(thread_db* tdbb, jrd_tra* transaction, - const MetaName& indexName, bool& systemIndex, bool silent = false); +static QualifiedName getIndexRelationName(thread_db* tdbb, jrd_tra* transaction, + const QualifiedName& indexName, bool& systemIndex, bool silent = false); static const char* getRelationScopeName(const rel_t type); -static void makeRelationScopeName(string& to, const MetaName& name, const rel_t type); -static void checkRelationType(const rel_t type, const MetaName& name); -static void checkFkPairTypes(const rel_t masterType, const MetaName& masterName, - const rel_t childType, const MetaName& childName); +static void makeRelationScopeName(string& to, const QualifiedName& name, const rel_t type); +static void checkRelationType(const rel_t type, const QualifiedName& name); +static void checkFkPairTypes(const rel_t masterType, const QualifiedName& masterName, + const rel_t childType, const QualifiedName& childName); static void modifyLocalFieldPosition(thread_db* tdbb, jrd_tra* transaction, - const MetaName& relationName, const MetaName& fieldName, USHORT newPosition); + const QualifiedName& relationName, const MetaName& fieldName, USHORT newPosition); static rel_t relationType(SSHORT relationTypeNull, SSHORT relationType); static void saveField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, const MetaName& fieldName); static void saveRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - const MetaName& relationName, bool view, bool creating); + const QualifiedName& relationName, bool view, bool creating); static void updateRdbFields(const TypeClause* type, SSHORT& fieldType, SSHORT& fieldLength, @@ -180,10 +180,10 @@ void ExecInSecurityDb::executeInSecurityDb(jrd_tra* localTransaction) // Check temporary table reference rules between given child relation and master // relation (owner of given PK/UK index). static void checkForeignKeyTempScope(thread_db* tdbb, jrd_tra* transaction, - const MetaName& childRelName, const MetaName& masterIndexName) + const QualifiedName& childRelName, const QualifiedName& masterIndexName) { AutoCacheRequest request(tdbb, drq_l_rel_info, DYN_REQUESTS); - MetaName masterRelName; + QualifiedName masterRelName; rel_t masterType, childType; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) @@ -192,20 +192,22 @@ static void checkForeignKeyTempScope(thread_db* tdbb, jrd_tra* transaction, REL_M IN RDB$RELATIONS WITH (RLC_M.RDB$CONSTRAINT_TYPE EQ UNIQUE_CNSTRT OR RLC_M.RDB$CONSTRAINT_TYPE EQ PRIMARY_KEY) AND - RLC_M.RDB$INDEX_NAME EQ masterIndexName.c_str() AND - REL_C.RDB$RELATION_NAME EQ childRelName.c_str() AND + RLC_M.RDB$SCHEMA_NAME EQ masterIndexName.schema.c_str() AND + RLC_M.RDB$INDEX_NAME EQ masterIndexName.object.c_str() AND + REL_C.RDB$SCHEMA_NAME EQ childRelName.schema.c_str() AND + REL_C.RDB$RELATION_NAME EQ childRelName.object.c_str() AND + REL_M.RDB$SCHEMA_NAME EQ RLC_M.RDB$SCHEMA_NAME AND REL_M.RDB$RELATION_NAME EQ RLC_M.RDB$RELATION_NAME { - fb_assert(masterRelName.isEmpty()); + fb_assert(masterRelName.object.isEmpty()); - masterRelName = REL_M.RDB$RELATION_NAME; + masterRelName = QualifiedName(REL_M.RDB$RELATION_NAME, REL_M.RDB$SCHEMA_NAME); masterType = relationType(REL_M.RDB$RELATION_TYPE.NULL, REL_M.RDB$RELATION_TYPE); childType = relationType(REL_C.RDB$RELATION_TYPE.NULL, REL_C.RDB$RELATION_TYPE); - } END_FOR - if (masterRelName.hasData()) + if (masterRelName.object.hasData()) { checkRelationType(masterType, masterRelName); checkRelationType(childType, childRelName); @@ -216,7 +218,7 @@ static void checkForeignKeyTempScope(thread_db* tdbb, jrd_tra* transaction, // Check temporary table reference rules between just created child relation and all // its master relations. static void checkRelationTempScope(thread_db* tdbb, jrd_tra* transaction, - const MetaName& childRelName, const rel_t childType) + const QualifiedName& childRelName, const rel_t childType) { if (childType != rel_persistent && childType != rel_global_temp_preserve && @@ -226,7 +228,7 @@ static void checkRelationTempScope(thread_db* tdbb, jrd_tra* transaction, } AutoCacheRequest request(tdbb, drq_l_rel_info2, DYN_REQUESTS); - MetaName masterRelName; + QualifiedName masterRelName; rel_t masterType; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) @@ -235,19 +237,23 @@ static void checkRelationTempScope(thread_db* tdbb, jrd_tra* transaction, IND_M IN RDB$INDICES CROSS REL_M IN RDB$RELATIONS WITH RLC_C.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY AND - RLC_C.RDB$RELATION_NAME EQ childRelName.c_str() AND + RLC_C.RDB$SCHEMA_NAME EQ childRelName.schema.c_str() AND + RLC_C.RDB$RELATION_NAME EQ childRelName.object.c_str() AND + IND_C.RDB$SCHEMA_NAME EQ RLC_C.RDB$SCHEMA_NAME AND IND_C.RDB$INDEX_NAME EQ RLC_C.RDB$INDEX_NAME AND + IND_M.RDB$SCHEMA_NAME EQ IND_C.RDB$FOREIGN_KEY_SCHEMA_NAME AND IND_M.RDB$INDEX_NAME EQ IND_C.RDB$FOREIGN_KEY AND + IND_M.RDB$SCHEMA_NAME EQ REL_M.RDB$SCHEMA_NAME AND IND_M.RDB$RELATION_NAME EQ REL_M.RDB$RELATION_NAME { - fb_assert(masterRelName.isEmpty()); + fb_assert(masterRelName.object.isEmpty()); masterType = relationType(REL_M.RDB$RELATION_TYPE.NULL, REL_M.RDB$RELATION_TYPE); - masterRelName = REL_M.RDB$RELATION_NAME; + masterRelName = QualifiedName(REL_M.RDB$RELATION_NAME, REL_M.RDB$SCHEMA_NAME); } END_FOR - if (masterRelName.hasData()) + if (masterRelName.object.hasData()) { checkRelationType(masterType, masterRelName); checkFkPairTypes(masterType, masterRelName, childType, childRelName); @@ -257,29 +263,30 @@ static void checkRelationTempScope(thread_db* tdbb, jrd_tra* transaction, // Checks to see if the given field is referenced in a stored procedure or trigger. // If the field is referenced, throw. static void checkSpTrigDependency(thread_db* tdbb, jrd_tra* transaction, - const MetaName& relationName, const MetaName& fieldName) + const QualifiedName& relationName, const MetaName& fieldName) { AutoRequest request; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) FIRST 1 DEP IN RDB$DEPENDENCIES - WITH DEP.RDB$DEPENDED_ON_NAME EQ relationName.c_str() AND + WITH DEP.RDB$DEPENDED_ON_SCHEMA_NAME EQ relationName.schema.c_str() AND + DEP.RDB$DEPENDED_ON_NAME EQ relationName.object.c_str() AND DEP.RDB$DEPENDED_ON_TYPE EQ obj_relation AND DEP.RDB$FIELD_NAME EQ fieldName.c_str() { - MetaName depName(DEP.RDB$DEPENDENT_NAME); + const QualifiedName depName(DEP.RDB$DEPENDENT_NAME, DEP.RDB$DEPENDENT_SCHEMA_NAME); // msg 206: Column %s from table %s is referenced in %s. status_exception::raise( - Arg::PrivateDyn(206) << fieldName << relationName << depName); + Arg::PrivateDyn(206) << fieldName << relationName.toQuotedString() << depName.toQuotedString()); } END_FOR } // Checks to see if the given field is referenced in a view. If it is, throw. static void checkViewDependency(thread_db* tdbb, jrd_tra* transaction, - const MetaName& relationName, const MetaName& fieldName) + const QualifiedName& relationName, const MetaName& fieldName) { AutoRequest request; @@ -288,19 +295,23 @@ static void checkViewDependency(thread_db* tdbb, jrd_tra* transaction, X IN RDB$RELATION_FIELDS CROSS Y IN RDB$RELATION_FIELDS CROSS Z IN RDB$VIEW_RELATIONS - WITH X.RDB$RELATION_NAME EQ relationName.c_str() AND + WITH X.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + X.RDB$RELATION_NAME EQ relationName.object.c_str() AND X.RDB$FIELD_NAME EQ fieldName.c_str() AND X.RDB$FIELD_NAME EQ Y.RDB$BASE_FIELD AND + X.RDB$FIELD_SOURCE_SCHEMA_NAME EQ Y.RDB$FIELD_SOURCE_SCHEMA_NAME AND X.RDB$FIELD_SOURCE EQ Y.RDB$FIELD_SOURCE AND + Y.RDB$SCHEMA_NAME EQ Z.RDB$SCHEMA_NAME AND Y.RDB$RELATION_NAME EQ Z.RDB$VIEW_NAME AND + X.RDB$SCHEMA_NAME EQ Z.RDB$RELATION_SCHEMA_NAME AND X.RDB$RELATION_NAME EQ Z.RDB$RELATION_NAME AND Y.RDB$VIEW_CONTEXT EQ Z.RDB$VIEW_CONTEXT { - MetaName viewName(Z.RDB$VIEW_NAME); + QualifiedName viewName(Z.RDB$VIEW_NAME, Z.RDB$SCHEMA_NAME); // msg 206: Column %s from table %s is referenced in %s. status_exception::raise( - Arg::PrivateDyn(206) << fieldName << relationName << viewName); + Arg::PrivateDyn(206) << fieldName << relationName.toQuotedString() << viewName.toQuotedString()); } END_FOR } @@ -312,8 +323,8 @@ static void clearPermanentField(dsql_rel* relation, bool permanent) { relation->rel_fields->fld_procedure = NULL; relation->rel_fields->ranges = NULL; - relation->rel_fields->charSet = NULL; - relation->rel_fields->subTypeName = NULL; + relation->rel_fields->charSet.clear(); + relation->rel_fields->subTypeName = nullptr; relation->rel_fields->fld_relation = relation; } } @@ -460,7 +471,7 @@ void definePartial(DsqlCompilerScratch* dsqlScratch, RelationSourceNode* relatio // RDB$INDEX_SEGMENTS.RDB$INDEX_NAME = // RDB$RELATION_CONSTRAINTS.RDB$INDEX_NAME static void deleteKeyConstraint(thread_db* tdbb, jrd_tra* transaction, - const MetaName& relationName, const MetaName& constraintName, const MetaName& indexName) + const QualifiedName& relationName, const MetaName& constraintName, const MetaName& indexName) { SET_TDBB(tdbb); @@ -471,7 +482,8 @@ static void deleteKeyConstraint(thread_db* tdbb, jrd_tra* transaction, RC IN RDB$RELATION_CONSTRAINTS WITH RC.RDB$CONSTRAINT_NAME EQ constraintName.c_str() AND RC.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY AND - RC.RDB$RELATION_NAME EQ relationName.c_str() AND + RC.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + RC.RDB$RELATION_NAME EQ relationName.object.c_str() AND RC.RDB$INDEX_NAME EQ indexName.c_str() { found = true; @@ -482,13 +494,12 @@ static void deleteKeyConstraint(thread_db* tdbb, jrd_tra* transaction, if (!found) { // msg 130: "CONSTRAINT %s does not exist." - status_exception::raise( - Arg::PrivateDyn(130) << constraintName); + status_exception::raise(Arg::PrivateDyn(130) << constraintName); } } // Checks to see if the given field already exists in a relation. -static bool fieldExists(thread_db* tdbb, jrd_tra* transaction, const MetaName& relationName, +static bool fieldExists(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& relationName, const MetaName& fieldName) { AutoRequest request; @@ -496,7 +507,8 @@ static bool fieldExists(thread_db* tdbb, jrd_tra* transaction, const MetaName& r FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) FLD IN RDB$RELATION_FIELDS - WITH FLD.RDB$RELATION_NAME EQ relationName.c_str() AND + WITH FLD.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + FLD.RDB$RELATION_NAME EQ relationName.object.c_str() AND FLD.RDB$FIELD_NAME EQ fieldName.c_str() { found = true; @@ -525,15 +537,15 @@ static bool isItSqlRole(thread_db* tdbb, jrd_tra* transaction, const MetaName& i } // Make string with relation name and type of its temporary scope. -static void makeRelationScopeName(string& to, const MetaName& name, const rel_t type) +static void makeRelationScopeName(string& to, const QualifiedName& name, const rel_t type) { const char* scope = getRelationScopeName(type); - to.printf(scope, name.c_str()); + to.printf(scope, name.toQuotedString().c_str()); } // Get relation name of an index. -static MetaName getIndexRelationName(thread_db* tdbb, jrd_tra* transaction, - const MetaName& indexName, bool& systemIndex, bool silent) +static QualifiedName getIndexRelationName(thread_db* tdbb, jrd_tra* transaction, + const QualifiedName& indexName, bool& systemIndex, bool silent) { systemIndex = false; @@ -541,10 +553,11 @@ static MetaName getIndexRelationName(thread_db* tdbb, jrd_tra* transaction, FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) IDX IN RDB$INDICES - WITH IDX.RDB$INDEX_NAME EQ indexName.c_str() + WITH IDX.RDB$SCHEMA_NAME EQ indexName.schema.c_str() AND + IDX.RDB$INDEX_NAME EQ indexName.object.c_str() { systemIndex = IDX.RDB$SYSTEM_FLAG == 1; - return IDX.RDB$RELATION_NAME; + return QualifiedName(IDX.RDB$RELATION_NAME, IDX.RDB$SCHEMA_NAME); } END_FOR @@ -558,20 +571,21 @@ static MetaName getIndexRelationName(thread_db* tdbb, jrd_tra* transaction, } // Get relation name of an trigger. -static MetaName getTriggerRelationName(thread_db* tdbb, jrd_tra* transaction, - const MetaName& triggerName) +static QualifiedName getTriggerRelationName(thread_db* tdbb, jrd_tra* transaction, + const QualifiedName& triggerName) { AutoCacheRequest request(tdbb, drq_l_trigger_relname, DYN_REQUESTS); FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$TRIGGERS - WITH X.RDB$TRIGGER_NAME EQ triggerName.c_str() + WITH X.RDB$SCHEMA_NAME EQ triggerName.schema.c_str() AND + X.RDB$TRIGGER_NAME EQ triggerName.object.c_str() { - return X.RDB$RELATION_NAME; + return QualifiedName(X.RDB$RELATION_NAME, X.RDB$SCHEMA_NAME); } END_FOR - return ""; + return {}; } // Get relation type name @@ -595,7 +609,7 @@ static const char* getRelationScopeName(const rel_t type) } // Check, can relation of given type be used in FK? -static void checkRelationType(const rel_t type, const MetaName& name) +static void checkRelationType(const rel_t type, const QualifiedName& name) { if (type == rel_persistent || type == rel_global_temp_preserve || @@ -610,8 +624,8 @@ static void checkRelationType(const rel_t type, const MetaName& name) } // Check, can a pair of relations be used in FK -static void checkFkPairTypes(const rel_t masterType, const MetaName& masterName, - const rel_t childType, const MetaName& childName) +static void checkFkPairTypes(const rel_t masterType, const QualifiedName& masterName, + const rel_t childType, const QualifiedName& childName) { if (masterType != childType && !(masterType == rel_global_temp_preserve && childType == rel_global_temp_delete)) @@ -644,7 +658,7 @@ static void checkFkPairTypes(const rel_t masterType, const MetaName& masterName, // // if new_position == original_position -- no_op static void modifyLocalFieldPosition(thread_db* tdbb, jrd_tra* transaction, - const MetaName& relationName, const MetaName& fieldName, USHORT newPosition) + const QualifiedName& relationName, const MetaName& fieldName, USHORT newPosition) { USHORT existingPosition = 0; bool found = false; @@ -657,7 +671,8 @@ static void modifyLocalFieldPosition(thread_db* tdbb, jrd_tra* transaction, FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) FLD IN RDB$RELATION_FIELDS - WITH FLD.RDB$RELATION_NAME EQ relationName.c_str() + WITH FLD.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + FLD.RDB$RELATION_NAME EQ relationName.object.c_str() SORTED BY ASCENDING FLD.RDB$FIELD_POSITION { if (FLD.RDB$FIELD_POSITION != newPos) @@ -680,7 +695,7 @@ static void modifyLocalFieldPosition(thread_db* tdbb, jrd_tra* transaction, if (!found) { // msg 176: "column %s does not exist in table/view %s" - status_exception::raise(Arg::PrivateDyn(176) << fieldName << relationName); + status_exception::raise(Arg::PrivateDyn(176) << fieldName << relationName.toQuotedString()); } // Find the position of the last field in the relation. @@ -699,9 +714,10 @@ static void modifyLocalFieldPosition(thread_db* tdbb, jrd_tra* transaction, FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) FLD IN RDB$RELATION_FIELDS - WITH FLD.RDB$RELATION_NAME EQ relationName.c_str() AND - FLD.RDB$FIELD_POSITION >= MIN(newPosition, existingPosition) AND - FLD.RDB$FIELD_POSITION <= MAX(newPosition, existingPosition) + WITH FLD.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + FLD.RDB$RELATION_NAME EQ relationName.object.c_str() AND + FLD.RDB$FIELD_POSITION >= MIN(newPosition, existingPosition) AND + FLD.RDB$FIELD_POSITION <= MAX(newPosition, existingPosition) { MODIFY FLD USING // If the field is the one we want, change the position, otherwise @@ -747,7 +763,7 @@ static void saveField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, const M MemoryPool& p = relation->rel_flags & REL_new_relation ? *tdbb->getDefaultPool() : dsqlScratch->getAttachment()->dbb_pool; dsql_fld* field = FB_NEW_POOL(p) dsql_fld(p); - field->fld_name = fieldName.c_str(); + field->fld_name = fieldName; field->fld_next = relation->rel_fields; relation->rel_fields = field; } @@ -755,7 +771,7 @@ static void saveField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, const M // Save the name of the relation or view currently being defined. This is done to support definition // of triggers which will depend on the metadata created in this statement. static void saveRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - const MetaName& relationName, bool view, bool creating) + const QualifiedName& relationName, bool view, bool creating) { if (dsqlScratch->flags & DsqlCompilerScratch::FLAG_METADATA_SAVED) return; @@ -874,8 +890,7 @@ static void updateRdbFields(const TypeClause* type, // Delete a security class. -bool DdlNode::deleteSecurityClass(thread_db* tdbb, jrd_tra* transaction, - const MetaName& secClass) +bool DdlNode::deleteSecurityClass(thread_db* tdbb, jrd_tra* transaction, const MetaName& secClass) { AutoCacheRequest request(tdbb, drq_e_class, DYN_REQUESTS); bool found = false; @@ -893,7 +908,7 @@ bool DdlNode::deleteSecurityClass(thread_db* tdbb, jrd_tra* transaction, } void DdlNode::storePrivileges(thread_db* tdbb, jrd_tra* transaction, - const MetaName& name, int type, + const QualifiedName& name, int type, const char* privileges) { Attachment* const attachment = transaction->tra_attachment; @@ -906,7 +921,22 @@ void DdlNode::storePrivileges(thread_db* tdbb, jrd_tra* transaction, STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$USER_PRIVILEGES { - strcpy(X.RDB$RELATION_NAME, name.c_str()); + if (name.schema.hasData()) + { + strcpy(X.RDB$RELATION_SCHEMA_NAME, name.schema.c_str()); + X.RDB$RELATION_SCHEMA_NAME.NULL = FALSE; + } + else + X.RDB$RELATION_SCHEMA_NAME.NULL = TRUE; + + if (name.object.hasData()) + { + strcpy(X.RDB$RELATION_NAME, name.object.c_str()); + X.RDB$RELATION_NAME.NULL = FALSE; + } + else + X.RDB$RELATION_NAME.NULL = TRUE; + strcpy(X.RDB$USER, ownerName.c_str()); X.RDB$USER_TYPE = obj_user; X.RDB$OBJECT_TYPE = type; @@ -919,13 +949,14 @@ void DdlNode::storePrivileges(thread_db* tdbb, jrd_tra* transaction, } void DdlNode::deletePrivilegesByRelName(thread_db* tdbb, jrd_tra* transaction, - const MetaName& name, int type) + const QualifiedName& name, int type) { AutoCacheRequest request(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 + WITH PRIV.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(name.schema.c_str(), '') AND + PRIV.RDB$RELATION_NAME EQ name.object.c_str() AND PRIV.RDB$OBJECT_TYPE = type AND PRIV.RDB$GRANTOR NOT MISSING { @@ -935,7 +966,7 @@ void DdlNode::deletePrivilegesByRelName(thread_db* tdbb, jrd_tra* transaction, } void DdlNode::executeDdlTrigger(thread_db* tdbb, jrd_tra* transaction, DdlTriggerWhen when, - int action, const MetaName& objectName, const MetaName& oldNewObjectName, const string& sqlText) + int action, const QualifiedName& objectName, const QualifiedName& oldNewObjectName, const string& sqlText) { Attachment* const attachment = transaction->tra_attachment; @@ -950,7 +981,7 @@ void DdlNode::executeDdlTrigger(thread_db* tdbb, jrd_tra* transaction, DdlTrigge context.objectName = objectName; context.sqlText = sqlText; - if (oldNewObjectName.hasData()) + if (oldNewObjectName.object.hasData()) { context.oldObjectName = when == DTW_BEFORE ? objectName : oldNewObjectName; context.newObjectName = when == DTW_BEFORE ? oldNewObjectName : objectName; @@ -965,14 +996,14 @@ void DdlNode::executeDdlTrigger(thread_db* tdbb, jrd_tra* transaction, DdlTrigge } void DdlNode::executeDdlTrigger(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - jrd_tra* transaction, DdlTriggerWhen when, int action, const MetaName& objectName, - const MetaName& oldNewObjectName) + jrd_tra* transaction, DdlTriggerWhen when, int action, const QualifiedName& objectName, + const QualifiedName& oldNewObjectName) { executeDdlTrigger(tdbb, transaction, when, action, objectName, oldNewObjectName, *dsqlScratch->getDsqlStatement()->getSqlText()); } -void DdlNode::storeGlobalField(thread_db* tdbb, jrd_tra* transaction, MetaName& name, +void DdlNode::storeGlobalField(thread_db* tdbb, jrd_tra* transaction, QualifiedName& name, const TypeClause* field, const string& computedSource, const BlrDebugWriter::BlrData& computedValue) { Attachment* const attachment = transaction->tra_attachment; @@ -988,7 +1019,7 @@ void DdlNode::storeGlobalField(thread_db* tdbb, jrd_tra* transaction, MetaName& Arg::Gds(isc_dsql_max_arr_dim_exceeded)); } - if (name.isEmpty()) + if (name.object.isEmpty()) DYN_UTIL_generate_field_name(tdbb, name); AutoCacheRequest requestHandle(tdbb, drq_s_fld_src, DYN_REQUESTS); @@ -997,7 +1028,8 @@ void DdlNode::storeGlobalField(thread_db* tdbb, jrd_tra* transaction, MetaName& FLD IN RDB$FIELDS { FLD.RDB$SYSTEM_FLAG = 0; - strcpy(FLD.RDB$FIELD_NAME, name.c_str()); + strcpy(FLD.RDB$SCHEMA_NAME, name.schema.c_str()); + strcpy(FLD.RDB$FIELD_NAME, name.object.c_str()); FLD.RDB$OWNER_NAME.NULL = FALSE; strcpy(FLD.RDB$OWNER_NAME, ownerName.c_str()); @@ -1064,7 +1096,8 @@ void DdlNode::storeGlobalField(thread_db* tdbb, jrd_tra* transaction, MetaName& STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) DIM IN RDB$FIELD_DIMENSIONS { - strcpy(DIM.RDB$FIELD_NAME, name.c_str()); + strcpy(DIM.RDB$SCHEMA_NAME, name.schema.c_str()); + strcpy(DIM.RDB$FIELD_NAME, name.object.c_str()); DIM.RDB$DIMENSION = position; DIM.RDB$UPPER_BOUND = hrange; DIM.RDB$LOWER_BOUND = lrange; @@ -1132,19 +1165,20 @@ void AlterCharSetNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch FOR (REQUEST_HANDLE requestHandle1 TRANSACTION_HANDLE transaction) CS IN RDB$CHARACTER_SETS - WITH CS.RDB$CHARACTER_SET_NAME EQ charSet.c_str() + WITH CS.RDB$SCHEMA_NAME EQ charSet.schema.c_str() AND + CS.RDB$CHARACTER_SET_NAME EQ charSet.object.c_str() { charSetFound = true; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_ALTER_CHARACTER_SET, charSet, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_CHARACTER_SET, charSet, {}); AutoCacheRequest requestHandle2(tdbb, drq_l_collation, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle2 TRANSACTION_HANDLE transaction) COLL IN RDB$COLLATIONS WITH COLL.RDB$CHARACTER_SET_ID EQ CS.RDB$CHARACTER_SET_ID AND - COLL.RDB$COLLATION_NAME EQ defaultCollation.c_str() + COLL.RDB$SCHEMA_NAME EQ defaultCollation.schema.c_str() AND + COLL.RDB$COLLATION_NAME EQ defaultCollation.object.c_str() { collationFound = true; } @@ -1153,24 +1187,26 @@ void AlterCharSetNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch if (collationFound) { MODIFY CS + CS.RDB$DEFAULT_COLLATE_SCHEMA_NAME.NULL = FALSE; + strcpy(CS.RDB$DEFAULT_COLLATE_SCHEMA_NAME, defaultCollation.schema.c_str()); + CS.RDB$DEFAULT_COLLATE_NAME.NULL = FALSE; - strcpy(CS.RDB$DEFAULT_COLLATE_NAME, defaultCollation.c_str()); + strcpy(CS.RDB$DEFAULT_COLLATE_NAME, defaultCollation.object.c_str()); END_MODIFY } } END_FOR if (!charSetFound) - status_exception::raise(Arg::Gds(isc_charset_not_found) << Arg::Str(charSet)); + status_exception::raise(Arg::Gds(isc_charset_not_found) << charSet.toQuotedString()); if (!collationFound) { status_exception::raise( - Arg::Gds(isc_collation_not_found) << Arg::Str(defaultCollation) << Arg::Str(charSet)); + Arg::Gds(isc_collation_not_found) << defaultCollation.toQuotedString() << charSet.toQuotedString()); } - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, - DDL_TRIGGER_ALTER_CHARACTER_SET, charSet, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_CHARACTER_SET, charSet, {}); } @@ -1270,7 +1306,7 @@ string CommentOnNode::internalPrint(NodePrinter& printer) const DdlNode::internalPrint(printer); NODE_PRINT(printer, objType); - NODE_PRINT(printer, objName); + NODE_PRINT(printer, name); NODE_PRINT(printer, subName); NODE_PRINT(printer, text); NODE_PRINT(printer, str); @@ -1278,24 +1314,28 @@ string CommentOnNode::internalPrint(NodePrinter& printer) const return "CommentOnNode"; } -void CommentOnNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +DdlNode* CommentOnNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { - Attachment* const attachment = transaction->tra_attachment; - - Arg::StatusVector status; - string objNameStr = objName.toString(); + thread_db* tdbb = JRD_get_thread_data(); + const auto transaction = dsqlScratch->getTransaction(); if (objType == obj_parameter) { fb_assert(subName.hasData()); - AutoRequest requestHandle; + auto nameCopy = name; + dsqlScratch->qualifyExistingName(nameCopy, obj_udf); + + static const CachedRequestId funcCachedHandleId; + AutoCacheRequest requestHandle(tdbb, funcCachedHandleId); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) FUN IN RDB$FUNCTIONS CROSS ARG IN RDB$FUNCTION_ARGUMENTS - WITH FUN.RDB$FUNCTION_NAME EQ objName.identifier.c_str() AND - FUN.RDB$PACKAGE_NAME EQUIV NULLIF(objName.package.c_str(), '') AND + WITH FUN.RDB$SCHEMA_NAME EQ nameCopy.schema.c_str() AND + FUN.RDB$FUNCTION_NAME EQ nameCopy.object.c_str() AND + FUN.RDB$PACKAGE_NAME EQUIV NULLIF(nameCopy.package.c_str(), '') AND + ARG.RDB$SCHEMA_NAME EQ FUN.RDB$SCHEMA_NAME AND ARG.RDB$FUNCTION_NAME EQ FUN.RDB$FUNCTION_NAME AND ARG.RDB$PACKAGE_NAME EQUIV FUN.RDB$PACKAGE_NAME AND ARG.RDB$ARGUMENT_NAME EQ subName.c_str() @@ -1304,13 +1344,19 @@ void CommentOnNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) } END_FOR - requestHandle.reset(); + nameCopy = name; + dsqlScratch->qualifyExistingName(nameCopy, obj_procedure); + + static const CachedRequestId procCachedHandleId; + requestHandle.reset(tdbb, procCachedHandleId); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PRC IN RDB$PROCEDURES CROSS PRM IN RDB$PROCEDURE_PARAMETERS - WITH PRC.RDB$PROCEDURE_NAME EQ objName.identifier.c_str() AND - PRC.RDB$PACKAGE_NAME EQUIV NULLIF(objName.package.c_str(), '') AND + WITH PRC.RDB$SCHEMA_NAME EQ nameCopy.schema.c_str() AND + PRC.RDB$PROCEDURE_NAME EQ nameCopy.object.c_str() AND + PRC.RDB$PACKAGE_NAME EQUIV NULLIF(nameCopy.package.c_str(), '') AND + PRM.RDB$SCHEMA_NAME EQ PRC.RDB$SCHEMA_NAME AND PRM.RDB$PROCEDURE_NAME EQ PRC.RDB$PROCEDURE_NAME AND PRM.RDB$PACKAGE_NAME EQUIV PRC.RDB$PACKAGE_NAME AND PRM.RDB$PARAMETER_NAME EQ subName.c_str() @@ -1320,7 +1366,7 @@ void CommentOnNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) else { status_exception::raise(Arg::Gds(isc_dyn_routine_param_ambiguous) << - Arg::Str(subName) << Arg::Str(objNameStr)); + Arg::Str(subName) << name.toQuotedString()); } } END_FOR @@ -1328,88 +1374,115 @@ void CommentOnNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) if (objType == obj_parameter) { status_exception::raise(Arg::Gds(isc_dyn_routine_param_not_found) << - Arg::Str(subName) << Arg::Str(objNameStr)); + Arg::Str(subName) << name.toQuotedString()); } + else + name = nameCopy; } - dsc dscName; - MetaName relationName; + dsqlScratch->ddlSchema = name.schema; switch (objType) { case obj_database: + case obj_schema: + case obj_blob_filter: + case obj_sql_role: + fb_assert(name.schema.isEmpty()); + break; + + default: + dsqlScratch->qualifyExistingName(name, objType); + break; + } + + return DdlNode::dsqlPass(dsqlScratch); +} + +void CommentOnNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + Attachment* const attachment = transaction->tra_attachment; + + Arg::StatusVector status; + + switch (objType) + { + case obj_database: + fb_assert(name.schema.isEmpty()); SCL_check_database(tdbb, SCL_alter); break; + case obj_schema: + fb_assert(name.schema.isEmpty()); + SCL_check_schema(tdbb, name.object, SCL_alter); + break; + case obj_field: - SCL_check_domain(tdbb, objName.identifier, SCL_alter); + SCL_check_domain(tdbb, name, SCL_alter); break; case obj_relation: - dscName.makeText(objNameStr.length(), CS_METADATA, (UCHAR*) objName.identifier.c_str()); - SCL_check_relation(tdbb, &dscName, SCL_alter); + SCL_check_relation(tdbb, name, SCL_alter); break; case obj_view: - dscName.makeText(objNameStr.length(), CS_METADATA, (UCHAR*) objName.identifier.c_str()); - SCL_check_view(tdbb, &dscName, SCL_alter); + SCL_check_view(tdbb, name, SCL_alter); break; case obj_procedure: - dscName.makeText(objNameStr.length(), CS_METADATA, (UCHAR*) objName.identifier.c_str()); - SCL_check_procedure(tdbb, &dscName, SCL_alter); + SCL_check_procedure(tdbb, name, SCL_alter); break; case obj_trigger: - relationName = getTriggerRelationName(tdbb, transaction, objName.identifier); - if (relationName.isEmpty()) + { + const auto relationName = getTriggerRelationName(tdbb, transaction, name); + if (relationName.object.isEmpty()) SCL_check_database(tdbb, SCL_alter); else - { - dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) relationName.c_str()); - SCL_check_relation(tdbb, &dscName, SCL_alter); - } + SCL_check_relation(tdbb, relationName, SCL_alter); break; + } case obj_udf: - dscName.makeText(objName.identifier.length(), CS_METADATA, (UCHAR*) objName.identifier.c_str()); - SCL_check_function(tdbb, &dscName, SCL_alter); + SCL_check_function(tdbb, name, SCL_alter); break; case obj_blob_filter: - SCL_check_filter(tdbb, objName.identifier, SCL_alter); + fb_assert(name.schema.isEmpty()); + SCL_check_filter(tdbb, name.object, SCL_alter); break; case obj_exception: - SCL_check_exception(tdbb, objName.identifier, SCL_alter); + SCL_check_exception(tdbb, name, SCL_alter); break; case obj_generator: - SCL_check_generator(tdbb, objName.identifier, SCL_alter); + SCL_check_generator(tdbb, name, SCL_alter); break; case obj_index: + { bool systemIndex; - relationName = getIndexRelationName(tdbb, transaction, objName.identifier, systemIndex); - dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) relationName.c_str()); - SCL_check_relation(tdbb, &dscName, SCL_alter, systemIndex); + const auto relationName = getIndexRelationName(tdbb, transaction, name, systemIndex); + SCL_check_relation(tdbb, relationName, SCL_alter, systemIndex); break; + } case obj_sql_role: - SCL_check_role(tdbb, objName.identifier, SCL_alter); + fb_assert(name.schema.isEmpty()); + SCL_check_role(tdbb, name.object, SCL_alter); break; case obj_charset: - SCL_check_charset(tdbb, objName.identifier, SCL_alter); + SCL_check_charset(tdbb, name, SCL_alter); break; case obj_collation: - SCL_check_collation(tdbb, objName.identifier, SCL_alter); + SCL_check_collation(tdbb, name, SCL_alter); break; case obj_package_header: - dscName.makeText(objName.identifier.length(), CS_METADATA, (UCHAR*) objName.identifier.c_str()); - SCL_check_package(tdbb, &dscName, SCL_alter); + SCL_check_package(tdbb, name, SCL_alter); break; default: @@ -1426,12 +1499,13 @@ void CommentOnNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, { Attachment* const attachment = transaction->tra_attachment; - const char* tableClause = NULL; - const char* columnClause = NULL; - const char* subColumnClause = NULL; - const char* addWhereClause = NULL; + const char* tableClause = nullptr; + const char* columnClause = nullptr; + const char* subColumnClause = nullptr; + const char* addWhereClause = nullptr; + bool useSchemaClause = true; Arg::StatusVector status; - string objNameStr = objName.toString(); + const string objNameStr = name.toQuotedString(); fb_assert(objType != obj_parameter); @@ -1439,6 +1513,14 @@ void CommentOnNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, { case obj_database: tableClause = "rdb$database"; + useSchemaClause = false; + break; + + case obj_schema: + tableClause = "rdb$schemas"; + columnClause = "rdb$schema_name"; + useSchemaClause = false; + status << Arg::Gds(isc_dyn_schema_not_found) << Arg::Str(objNameStr); break; case obj_field: @@ -1538,6 +1620,7 @@ void CommentOnNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, case obj_sql_role: tableClause = "rdb$roles"; columnClause = "rdb$role_name"; + useSchemaClause = false; status << Arg::Gds(isc_dyn_role_not_found) << Arg::Str(objNameStr); break; @@ -1569,18 +1652,21 @@ void CommentOnNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, description = text; PreparedStatement::Builder sql; - sql << "update" << tableClause << "set rdb$description =" << description << "where 1 = 1"; + sql << "update system." << tableClause << "set rdb$description =" << description << "where 1 = 1"; + + if (useSchemaClause) + sql << "and rdb$schema_name = " << name.schema; if (columnClause) { - sql << "and" << columnClause << "=" << objName.identifier; + sql << "and" << columnClause << "=" << name.object; if (subColumnClause) sql << "and" << subColumnClause << "=" << subName; } if (objType == obj_procedure || objType == obj_udf) - sql << "and rdb$package_name is not distinct from nullif(" << objName.package << ", '')"; + sql << "and rdb$package_name is not distinct from nullif(" << name.package << ", '')"; if (addWhereClause) sql << "and" << addWhereClause; @@ -1611,7 +1697,6 @@ string CreateAlterFunctionNode::internalPrint(NodePrinter& printer) const NODE_PRINT(printer, body); NODE_PRINT(printer, compiled); NODE_PRINT(printer, invalid); - NODE_PRINT(printer, package); NODE_PRINT(printer, packageOwner); NODE_PRINT(printer, privateScope); NODE_PRINT(printer, udfReturnPos); @@ -1621,6 +1706,14 @@ string CreateAlterFunctionNode::internalPrint(NodePrinter& printer) const DdlNode* CreateAlterFunctionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { + if (create) + dsqlScratch->qualifyNewName(name); + else + dsqlScratch->qualifyExistingName(name, obj_udf); + + protectSystemSchema(name.schema, obj_udf); + dsqlScratch->ddlSchema = name.schema; + dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_FUNCTION); dsqlScratch->reserveInitialVarNumbers(1); @@ -1656,7 +1749,7 @@ DdlNode* CreateAlterFunctionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) returnType->type->resolve(dsqlScratch); // check SQL SECURITY is not set if function declared in package - if (package.hasData() && ssDefiner.has_value()) + if (name.package.hasData() && ssDefiner.has_value()) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) << Arg::Gds(isc_invalid_clause) << Arg::Str("SQL SECURITY for functions is prohibit in packages")); @@ -1667,19 +1760,16 @@ DdlNode* CreateAlterFunctionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) void CreateAlterFunctionNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - dsc dscName; - dscName.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str()); if (alter) { - if (SCL_check_function(tdbb, &dscName, SCL_alter) || !create) + if (SCL_check_function(tdbb, name, SCL_alter) || !create) return; } - SCL_check_create_access(tdbb, obj_functions); + SCL_check_create_access(tdbb, obj_functions, name.schema); } -void CreateAlterFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - jrd_tra* transaction) +void CreateAlterFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { fb_assert(create || alter); @@ -1695,20 +1785,18 @@ void CreateAlterFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsql if (executeAlterIndividualParameters(tdbb, dsqlScratch, transaction, false, true)) altered = true; else - status_exception::raise(Arg::Gds(isc_dyn_func_not_found) << Arg::Str(name)); + status_exception::raise(Arg::Gds(isc_dyn_func_not_found) << name.toQuotedString()); } else if (alter) { if (executeAlter(tdbb, dsqlScratch, transaction, false, true)) - { altered = true; - } else { if (create) // create or alter executeCreate(tdbb, dsqlScratch, transaction); else - status_exception::raise(Arg::Gds(isc_dyn_func_not_found) << Arg::Str(name)); + status_exception::raise(Arg::Gds(isc_dyn_func_not_found) << name.toQuotedString()); } } else if (!executeCreate(tdbb, dsqlScratch, transaction)) @@ -1722,10 +1810,10 @@ void CreateAlterFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsql else executeAlter(tdbb, dsqlScratch, transaction, true, false); - if (package.isEmpty()) + if (name.package.isEmpty()) { executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, - (altered ? DDL_TRIGGER_ALTER_FUNCTION : DDL_TRIGGER_CREATE_FUNCTION), name, NULL); + (altered ? DDL_TRIGGER_ALTER_FUNCTION : DDL_TRIGGER_CREATE_FUNCTION), name, {}); } savePoint.release(); // everything is ok @@ -1733,24 +1821,23 @@ void CreateAlterFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsql if (alter) { // Update DSQL cache - METD_drop_function(transaction, QualifiedName(name, package)); - MET_dsql_cache_release(tdbb, SYM_udf, name, package); + METD_drop_function(transaction, name); + MET_dsql_cache_release(tdbb, SYM_udf, name); } } -bool CreateAlterFunctionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - jrd_tra* transaction) +bool CreateAlterFunctionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { Attachment* const attachment = transaction->getAttachment(); const MetaString& ownerName = attachment->getEffectiveUserName(); - if (package.isEmpty()) + if (name.package.isEmpty()) { if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_udf)) return false; executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_CREATE_FUNCTION, name, NULL); + DDL_TRIGGER_CREATE_FUNCTION, name, {}); DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_udf); } @@ -1774,12 +1861,13 @@ bool CreateAlterFunctionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch { FUN.RDB$FUNCTION_ID = id; FUN.RDB$SYSTEM_FLAG = 0; - strcpy(FUN.RDB$FUNCTION_NAME, name.c_str()); + strcpy(FUN.RDB$SCHEMA_NAME, name.schema.c_str()); + strcpy(FUN.RDB$FUNCTION_NAME, name.object.c_str()); - if (package.hasData()) + if (name.package.hasData()) { FUN.RDB$PACKAGE_NAME.NULL = FALSE; - strcpy(FUN.RDB$PACKAGE_NAME, package.c_str()); + strcpy(FUN.RDB$PACKAGE_NAME, name.package.c_str()); FUN.RDB$PRIVATE_FLAG.NULL = FALSE; FUN.RDB$PRIVATE_FLAG = privateScope; @@ -1818,7 +1906,7 @@ bool CreateAlterFunctionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch } } - if (package.isEmpty()) + if (name.package.isEmpty()) storePrivileges(tdbb, transaction, name, obj_udf, EXEC_PRIVILEGES); executeAlter(tdbb, dsqlScratch, transaction, false, false); @@ -1838,20 +1926,19 @@ bool CreateAlterFunctionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) FUN IN RDB$FUNCTIONS - WITH FUN.RDB$FUNCTION_NAME EQ name.c_str() AND - FUN.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '') + WITH FUN.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + FUN.RDB$FUNCTION_NAME EQ name.object.c_str() AND + FUN.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') { if (FUN.RDB$SYSTEM_FLAG) { status_exception::raise( - Arg::Gds(isc_dyn_cannot_mod_sysfunc) << MetaName(FUN.RDB$FUNCTION_NAME)); + Arg::Gds(isc_dyn_cannot_mod_sysfunc) << + name.toQuotedString()); } - if (!secondPass && runTriggers && package.isEmpty()) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_ALTER_FUNCTION, name, NULL); - } + if (!secondPass && runTriggers && name.package.isEmpty()) + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_FUNCTION, name, {}); MODIFY FUN if (secondPass) @@ -1866,7 +1953,7 @@ bool CreateAlterFunctionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* FUN.RDB$ENTRYPOINT.NULL = TRUE; FUN.RDB$VALID_BLR.NULL = TRUE; - FUN.RDB$FUNCTION_SOURCE.NULL = !(source.hasData() && (external || package.isEmpty())); + FUN.RDB$FUNCTION_SOURCE.NULL = !(source.hasData() && (external || name.package.isEmpty())); if (!FUN.RDB$FUNCTION_SOURCE.NULL) attachment->storeMetaDataBlob(tdbb, transaction, &FUN.RDB$FUNCTION_SOURCE, source); @@ -1998,7 +2085,7 @@ bool CreateAlterFunctionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* } } - if (package.hasData()) + if (name.package.hasData()) { FUN.RDB$PRIVATE_FLAG.NULL = FALSE; FUN.RDB$PRIVATE_FLAG = privateScope; @@ -2018,7 +2105,7 @@ bool CreateAlterFunctionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* collectParameters(tdbb, transaction, collectedParameters); // delete all old arguments - DropFunctionNode::dropArguments(tdbb, transaction, name, package); + DropFunctionNode::dropArguments(tdbb, transaction, name); // and insert the new ones @@ -2041,7 +2128,8 @@ bool CreateAlterFunctionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* return modified; } -bool CreateAlterFunctionNode::executeAlterIndividualParameters(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, bool secondPass, bool runTriggers) +bool CreateAlterFunctionNode::executeAlterIndividualParameters(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, + jrd_tra* transaction, bool secondPass, bool runTriggers) { Attachment* const attachment = transaction->getAttachment(); @@ -2051,20 +2139,19 @@ bool CreateAlterFunctionNode::executeAlterIndividualParameters(thread_db* tdbb, FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) FUN IN RDB$FUNCTIONS - WITH FUN.RDB$FUNCTION_NAME EQ name.c_str() AND - FUN.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '') + WITH FUN.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + FUN.RDB$FUNCTION_NAME EQ name.object.c_str() AND + FUN.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') { if (FUN.RDB$SYSTEM_FLAG) { status_exception::raise( - Arg::Gds(isc_dyn_cannot_mod_sysfunc) << MetaName(FUN.RDB$FUNCTION_NAME)); + Arg::Gds(isc_dyn_cannot_mod_sysfunc) << + name.toQuotedString()); } - if (!secondPass && runTriggers && package.isEmpty()) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_ALTER_FUNCTION, name, NULL); - } + if (!secondPass && runTriggers && name.package.isEmpty()) + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_FUNCTION, name, {}); MODIFY FUN if (deterministic.isAssigned()) @@ -2103,14 +2190,14 @@ void CreateAlterFunctionNode::storeArgument(thread_db* tdbb, DsqlCompilerScratch STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) ARG IN RDB$FUNCTION_ARGUMENTS { - ARG.RDB$FUNCTION_NAME.NULL = FALSE; - strcpy(ARG.RDB$FUNCTION_NAME, name.c_str()); + strcpy(ARG.RDB$SCHEMA_NAME, name.schema.c_str()); + strcpy(ARG.RDB$FUNCTION_NAME, name.object.c_str()); ARG.RDB$ARGUMENT_NAME.NULL = (SSHORT) parameter->name.isEmpty(); strcpy(ARG.RDB$ARGUMENT_NAME, parameter->name.c_str()); - ARG.RDB$PACKAGE_NAME.NULL = (SSHORT) package.isEmpty(); - strcpy(ARG.RDB$PACKAGE_NAME, package.c_str()); + ARG.RDB$PACKAGE_NAME.NULL = (SSHORT) name.package.isEmpty(); + strcpy(ARG.RDB$PACKAGE_NAME, name.package.c_str()); ARG.RDB$SYSTEM_FLAG = 0; ARG.RDB$SYSTEM_FLAG.NULL = FALSE; @@ -2119,8 +2206,10 @@ void CreateAlterFunctionNode::storeArgument(thread_db* tdbb, DsqlCompilerScratch ARG.RDB$ARGUMENT_POSITION = pos; ARG.RDB$NULL_FLAG.NULL = TRUE; + ARG.RDB$RELATION_SCHEMA_NAME.NULL = TRUE; ARG.RDB$RELATION_NAME.NULL = TRUE; ARG.RDB$FIELD_NAME.NULL = TRUE; + ARG.RDB$FIELD_SOURCE_SCHEMA_NAME.NULL = TRUE; ARG.RDB$FIELD_SOURCE.NULL = TRUE; ARG.RDB$DEFAULT_VALUE.NULL = TRUE; ARG.RDB$DEFAULT_SOURCE.NULL = TRUE; @@ -2139,7 +2228,7 @@ void CreateAlterFunctionNode::storeArgument(thread_db* tdbb, DsqlCompilerScratch if (!isUdf()) { ARG.RDB$ARGUMENT_MECHANISM.NULL = FALSE; - ARG.RDB$ARGUMENT_MECHANISM = (USHORT) (type->fullDomain || type->typeOfName.isEmpty() ? + ARG.RDB$ARGUMENT_MECHANISM = (USHORT) (type->fullDomain || type->typeOfName.object.isEmpty() ? prm_mech_normal : prm_mech_type_of); } @@ -2149,12 +2238,15 @@ void CreateAlterFunctionNode::storeArgument(thread_db* tdbb, DsqlCompilerScratch ARG.RDB$NULL_FLAG = TRUE; } - if (type->typeOfTable.isEmpty()) + if (type->typeOfTable.object.isEmpty()) { - if (type->typeOfName.hasData()) + if (type->typeOfName.object.hasData()) { + ARG.RDB$FIELD_SOURCE_SCHEMA_NAME.NULL = FALSE; + strcpy(ARG.RDB$FIELD_SOURCE_SCHEMA_NAME, type->typeOfName.schema.c_str()); + ARG.RDB$FIELD_SOURCE.NULL = FALSE; - strcpy(ARG.RDB$FIELD_SOURCE, type->typeOfName.c_str()); + strcpy(ARG.RDB$FIELD_SOURCE, type->typeOfName.object.c_str()); } else { @@ -2177,30 +2269,39 @@ void CreateAlterFunctionNode::storeArgument(thread_db* tdbb, DsqlCompilerScratch } else { - MetaName fieldName; + QualifiedName fieldName({}, name.schema); storeGlobalField(tdbb, transaction, fieldName, type); + ARG.RDB$FIELD_SOURCE_SCHEMA_NAME.NULL = FALSE; + strcpy(ARG.RDB$FIELD_SOURCE_SCHEMA_NAME, fieldName.schema.c_str()); + ARG.RDB$FIELD_SOURCE.NULL = FALSE; - strcpy(ARG.RDB$FIELD_SOURCE, fieldName.c_str()); + strcpy(ARG.RDB$FIELD_SOURCE, fieldName.object.c_str()); } } } else { + ARG.RDB$RELATION_SCHEMA_NAME.NULL = FALSE; + strcpy(ARG.RDB$RELATION_SCHEMA_NAME, type->typeOfTable.schema.c_str()); + ARG.RDB$RELATION_NAME.NULL = FALSE; - strcpy(ARG.RDB$RELATION_NAME, type->typeOfTable.c_str()); + strcpy(ARG.RDB$RELATION_NAME, type->typeOfTable.object.c_str()); ARG.RDB$FIELD_NAME.NULL = FALSE; - strcpy(ARG.RDB$FIELD_NAME, type->typeOfName.c_str()); + strcpy(ARG.RDB$FIELD_NAME, type->typeOfName.object.c_str()); + + ARG.RDB$FIELD_SOURCE_SCHEMA_NAME.NULL = FALSE; + strcpy(ARG.RDB$FIELD_SOURCE_SCHEMA_NAME, type->fieldSource.schema.c_str()); ARG.RDB$FIELD_SOURCE.NULL = FALSE; - strcpy(ARG.RDB$FIELD_SOURCE, type->fieldSource.c_str()); + strcpy(ARG.RDB$FIELD_SOURCE, type->fieldSource.object.c_str()); } // ASF: If we used a collate with a domain or table.column type, write it // into RDB$FUNCTION_ARGUMENTS. - if (type->collate.hasData() && type->typeOfName.hasData()) + if (type->collate.object.hasData() && type->typeOfName.object.hasData()) { ARG.RDB$COLLATION_ID.NULL = FALSE; ARG.RDB$COLLATION_ID = type->collationId; @@ -2216,8 +2317,8 @@ void CreateAlterFunctionNode::storeArgument(thread_db* tdbb, DsqlCompilerScratch { status_exception::raise( Arg::Gds(isc_dyn_defvaldecl_package_func) << - package.c_str() << - name.c_str()); + name.getSchemaAndPackage().toQuotedString() << + name.object); } ARG.RDB$DEFAULT_VALUE.NULL = FALSE; @@ -2282,7 +2383,7 @@ void CreateAlterFunctionNode::storeArgument(thread_db* tdbb, DsqlCompilerScratch void CreateAlterFunctionNode::compile(thread_db* /*tdbb*/, DsqlCompilerScratch* dsqlScratch) { if (invalid) - status_exception::raise(Arg::Gds(isc_dyn_invalid_ddl_func) << name); + status_exception::raise(Arg::Gds(isc_dyn_invalid_ddl_func) << name.toQuotedString()); if (compiled) return; @@ -2332,7 +2433,7 @@ void CreateAlterFunctionNode::compile(thread_db* /*tdbb*/, DsqlCompilerScratch* } dsql_var* const variable = dsqlScratch->outputVariables[0]; - dsqlScratch->putLocalVariable(variable, nullptr, {}); + dsqlScratch->putLocalVariable(variable); // ASF: This is here to not change the old logic (proc_flag) // of previous calls to PASS1_node and PASS1_statement. @@ -2376,8 +2477,9 @@ void CreateAlterFunctionNode::collectParameters(thread_db* tdbb, jrd_tra* transa FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) ARG IN RDB$FUNCTION_ARGUMENTS - WITH ARG.RDB$FUNCTION_NAME EQ name.c_str() AND - ARG.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '') + WITH ARG.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + ARG.RDB$FUNCTION_NAME EQ name.object.c_str() AND + ARG.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') { CollectedParameter parameter; parameter.comment = ARG.RDB$DESCRIPTION; @@ -2404,9 +2506,7 @@ string AlterExternalFunctionNode::internalPrint(NodePrinter& printer) const void AlterExternalFunctionNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - dsc dscName; - dscName.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str()); - SCL_check_function(tdbb, &dscName, SCL_alter); + SCL_check_function(tdbb, name, SCL_alter); } // Allow changing the entry point and/or the module name of a UDF. @@ -2430,16 +2530,17 @@ void AlterExternalFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* ds FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) FUN IN RDB$FUNCTIONS - WITH FUN.RDB$FUNCTION_NAME EQ name.c_str() AND + WITH FUN.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + FUN.RDB$FUNCTION_NAME EQ name.object.c_str() AND FUN.RDB$PACKAGE_NAME MISSING { found = true; executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_FUNCTION, - name, NULL); + name, {}); if (!FUN.RDB$ENGINE_NAME.NULL || !FUN.RDB$FUNCTION_BLR.NULL) - status_exception::raise(Arg::Gds(isc_dyn_newfc_oldsyntax) << name); + status_exception::raise(Arg::Gds(isc_dyn_newfc_oldsyntax) << name.toQuotedString()); MODIFY FUN if (clauses.name.hasData()) @@ -2464,36 +2565,33 @@ void AlterExternalFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* ds END_FOR if (found) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_FUNCTION, - name, NULL); - } + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_FUNCTION, name, {}); else { // msg 41: "Function %s not found" - status_exception::raise(Arg::PrivateDyn(41) << name); + status_exception::raise(Arg::PrivateDyn(41) << name.toQuotedString()); } savePoint.release(); // everything is ok // Update DSQL cache - METD_drop_function(transaction, QualifiedName(name, "")); - MET_dsql_cache_release(tdbb, SYM_udf, name, ""); + METD_drop_function(transaction, name); + MET_dsql_cache_release(tdbb, SYM_udf, name); } //---------------------- -void DropFunctionNode::dropArguments(thread_db* tdbb, jrd_tra* transaction, - const MetaName& functionName, const MetaName& packageName) +void DropFunctionNode::dropArguments(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& functionName) { AutoCacheRequest requestHandle(tdbb, drq_e_func_args, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) ARG IN RDB$FUNCTION_ARGUMENTS - WITH ARG.RDB$FUNCTION_NAME EQ functionName.c_str() AND - ARG.RDB$PACKAGE_NAME EQUIV NULLIF(packageName.c_str(), '') + WITH ARG.RDB$SCHEMA_NAME EQ functionName.schema.c_str() AND + ARG.RDB$FUNCTION_NAME EQ functionName.object.c_str() AND + ARG.RDB$PACKAGE_NAME EQUIV NULLIF(functionName.package.c_str(), '') { // get rid of arguments in rdb$fields if (!ARG.RDB$FIELD_SOURCE.NULL && ARG.RDB$RELATION_NAME.NULL && ARG.RDB$FIELD_NAME.NULL) @@ -2502,7 +2600,8 @@ void DropFunctionNode::dropArguments(thread_db* tdbb, jrd_tra* transaction, FOR (REQUEST_HANDLE requestHandle2 TRANSACTION_HANDLE transaction) FLD IN RDB$FIELDS - WITH FLD.RDB$FIELD_NAME EQ ARG.RDB$FIELD_SOURCE AND + WITH FLD.RDB$SCHEMA_NAME EQ ARG.RDB$FIELD_SOURCE_SCHEMA_NAME AND + FLD.RDB$FIELD_NAME EQ ARG.RDB$FIELD_SOURCE AND FLD.RDB$FIELD_NAME STARTING WITH IMPLICIT_DOMAIN_PREFIX AND FLD.RDB$SYSTEM_FLAG EQ 0 { @@ -2511,7 +2610,8 @@ void DropFunctionNode::dropArguments(thread_db* tdbb, jrd_tra* transaction, if (!FLD.RDB$SECURITY_CLASS.NULL) deleteSecurityClass(tdbb, transaction, FLD.RDB$SECURITY_CLASS); - deletePrivilegesByRelName(tdbb, transaction, FLD.RDB$FIELD_NAME, obj_field); + deletePrivilegesByRelName(tdbb, transaction, + QualifiedName(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME), obj_field); } END_FOR } @@ -2527,52 +2627,55 @@ string DropFunctionNode::internalPrint(NodePrinter& printer) const NODE_PRINT(printer, name); NODE_PRINT(printer, silent); - NODE_PRINT(printer, package); return "DropFunctionNode"; } DdlNode* DropFunctionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { + if (recreate) + dsqlScratch->qualifyNewName(name); + else + dsqlScratch->qualifyExistingName(name, obj_exception); + + protectSystemSchema(name.schema, obj_udf); + dsqlScratch->ddlSchema = name.schema; + dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_FUNCTION); + return DdlNode::dsqlPass(dsqlScratch); } void DropFunctionNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - dsc dscName; - dscName.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str()); - SCL_check_function(tdbb, &dscName, SCL_drop); + SCL_check_function(tdbb, name, SCL_drop); } -void DropFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - jrd_tra* transaction) +void DropFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); bool found = false; - dropArguments(tdbb, transaction, name, package); + dropArguments(tdbb, transaction, name); AutoCacheRequest requestHandle(tdbb, drq_e_funcs, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) FUN IN RDB$FUNCTIONS - WITH FUN.RDB$FUNCTION_NAME EQ name.c_str() AND - FUN.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '') + WITH FUN.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + FUN.RDB$FUNCTION_NAME EQ name.object.c_str() AND + FUN.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') { if (FUN.RDB$SYSTEM_FLAG) { status_exception::raise( Arg::Gds(isc_dyn_cannot_mod_sysfunc) << - MetaName(FUN.RDB$FUNCTION_NAME)); + name.toQuotedString()); } - if (package.isEmpty()) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_FUNCTION, - name, NULL); - } + if (name.package.isEmpty()) + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_FUNCTION, name, {}); ERASE FUN; @@ -2584,35 +2687,34 @@ void DropFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch END_FOR if (!found && !silent) - status_exception::raise(Arg::Gds(isc_dyn_func_not_found) << Arg::Str(name)); + status_exception::raise(Arg::Gds(isc_dyn_func_not_found) << name.toQuotedString()); - if (package.isEmpty()) + if (name.package.isEmpty()) { deletePrivilegesByRelName(tdbb, transaction, name, obj_udf); requestHandle.reset(tdbb, drq_e_fun_prv, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) - PRIV IN RDB$USER_PRIVILEGES WITH PRIV.RDB$USER EQ name.c_str() - AND PRIV.RDB$USER_TYPE = obj_udf - AND PRIV.RDB$GRANTOR NOT MISSING + PRIV IN RDB$USER_PRIVILEGES + WITH PRIV.RDB$USER_SCHEMA_NAME EQ name.schema.c_str() AND + PRIV.RDB$USER EQ name.object.c_str() AND + PRIV.RDB$USER_TYPE = obj_udf AND + PRIV.RDB$GRANTOR NOT MISSING { ERASE PRIV; } END_FOR } - if (found && package.isEmpty()) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_FUNCTION, - name, NULL); - } + if (found && name.package.isEmpty()) + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_FUNCTION, name, {}); savePoint.release(); // everything is ok // Update DSQL cache - METD_drop_function(transaction, QualifiedName(name, package)); - MET_dsql_cache_release(tdbb, SYM_udf, name, package); + METD_drop_function(transaction, name); + MET_dsql_cache_release(tdbb, SYM_udf, name); } @@ -2634,7 +2736,6 @@ string CreateAlterProcedureNode::internalPrint(NodePrinter& printer) const NODE_PRINT(printer, body); NODE_PRINT(printer, compiled); NODE_PRINT(printer, invalid); - NODE_PRINT(printer, package); NODE_PRINT(printer, packageOwner); NODE_PRINT(printer, privateScope); @@ -2643,6 +2744,14 @@ string CreateAlterProcedureNode::internalPrint(NodePrinter& printer) const DdlNode* CreateAlterProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { + if (create) + dsqlScratch->qualifyNewName(name); + else + dsqlScratch->qualifyExistingName(name, obj_procedure); + + protectSystemSchema(name.schema, obj_procedure); + dsqlScratch->ddlSchema = name.schema; + dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_PROCEDURE); dsqlScratch->reserveInitialVarNumbers(returns.getCount()); @@ -2678,7 +2787,7 @@ DdlNode* CreateAlterProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) returns[i]->type->resolve(dsqlScratch); // check SQL SECURITY is not set if procedure declared in package - if (package.hasData() && ssDefiner.has_value()) + if (name.package.hasData() && ssDefiner.has_value()) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) << Arg::Gds(isc_invalid_clause) << Arg::Str("SQL SECURITY for procedures is prohibit in packages")); @@ -2689,19 +2798,16 @@ DdlNode* CreateAlterProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) void CreateAlterProcedureNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - dsc dscName; - dscName.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str()); if (alter) { - if (SCL_check_procedure(tdbb, &dscName, SCL_alter) || !create) + if (SCL_check_procedure(tdbb, name, SCL_alter) || !create) return; } - SCL_check_create_access(tdbb, obj_procedures); + SCL_check_create_access(tdbb, obj_procedures, name.schema); } -void CreateAlterProcedureNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - jrd_tra* transaction) +void CreateAlterProcedureNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { fb_assert(create || alter); @@ -2717,7 +2823,7 @@ void CreateAlterProcedureNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsq if (executeAlterIndividualParameters(tdbb, dsqlScratch, transaction, false, true)) altered = true; else - status_exception::raise(Arg::Gds(isc_dyn_proc_not_found) << Arg::Str(name)); + status_exception::raise(Arg::Gds(isc_dyn_proc_not_found) << name.toQuotedString()); } else if (alter) { @@ -2728,7 +2834,7 @@ void CreateAlterProcedureNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsq if (create) // create or alter executeCreate(tdbb, dsqlScratch, transaction); else - status_exception::raise(Arg::Gds(isc_dyn_proc_not_found) << Arg::Str(name)); + status_exception::raise(Arg::Gds(isc_dyn_proc_not_found) << name.toQuotedString()); } } else if (!executeCreate(tdbb, dsqlScratch, transaction)) @@ -2742,10 +2848,10 @@ void CreateAlterProcedureNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsq else executeAlter(tdbb, dsqlScratch, transaction, true, false); - if (package.isEmpty()) + if (name.package.isEmpty()) { executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, - (altered ? DDL_TRIGGER_ALTER_PROCEDURE : DDL_TRIGGER_CREATE_PROCEDURE), name, NULL); + (altered ? DDL_TRIGGER_ALTER_PROCEDURE : DDL_TRIGGER_CREATE_PROCEDURE), name, {}); } savePoint.release(); // everything is ok @@ -2753,8 +2859,8 @@ void CreateAlterProcedureNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsq if (alter) { // Update DSQL cache - METD_drop_procedure(transaction, QualifiedName(name, package)); - MET_dsql_cache_release(tdbb, SYM_procedure, name, package); + METD_drop_procedure(transaction, name); + MET_dsql_cache_release(tdbb, SYM_procedure, name); } } @@ -2764,13 +2870,12 @@ bool CreateAlterProcedureNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc Attachment* const attachment = transaction->getAttachment(); const MetaString& ownerName = attachment->getEffectiveUserName(); - if (package.isEmpty()) + if (name.package.isEmpty()) { if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_procedure)) return false; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_CREATE_PROCEDURE, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_PROCEDURE, name, {}); DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_procedure); } @@ -2794,12 +2899,13 @@ bool CreateAlterProcedureNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc { P.RDB$PROCEDURE_ID = id; P.RDB$SYSTEM_FLAG = 0; - strcpy(P.RDB$PROCEDURE_NAME, name.c_str()); + strcpy(P.RDB$SCHEMA_NAME, name.schema.c_str()); + strcpy(P.RDB$PROCEDURE_NAME, name.object.c_str()); - if (package.hasData()) + if (name.package.hasData()) { P.RDB$PACKAGE_NAME.NULL = FALSE; - strcpy(P.RDB$PACKAGE_NAME, package.c_str()); + strcpy(P.RDB$PACKAGE_NAME, name.package.c_str()); P.RDB$PRIVATE_FLAG.NULL = FALSE; P.RDB$PRIVATE_FLAG = privateScope; @@ -2830,7 +2936,7 @@ bool CreateAlterProcedureNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc } } - if (package.isEmpty()) + if (name.package.isEmpty()) storePrivileges(tdbb, transaction, name, obj_procedure, EXEC_PRIVILEGES); executeAlter(tdbb, dsqlScratch, transaction, false, false); @@ -2849,21 +2955,19 @@ bool CreateAlterProcedureNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) P IN RDB$PROCEDURES - WITH P.RDB$PROCEDURE_NAME EQ name.c_str() AND - P.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '') + WITH P.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + P.RDB$PROCEDURE_NAME EQ name.object.c_str() AND + P.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') { if (P.RDB$SYSTEM_FLAG) { status_exception::raise( Arg::Gds(isc_dyn_cannot_mod_sysproc) << - MetaName(P.RDB$PROCEDURE_NAME)); + name.toQuotedString()); } - if (!secondPass && runTriggers && package.isEmpty()) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_ALTER_PROCEDURE, name, NULL); - } + if (!secondPass && runTriggers && name.package.isEmpty()) + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_PROCEDURE, name, {}); MODIFY P if (secondPass) @@ -2882,11 +2986,11 @@ bool CreateAlterProcedureNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch P.RDB$PROCEDURE_SOURCE.NULL = TRUE; P.RDB$VALID_BLR.NULL = TRUE; - P.RDB$PROCEDURE_SOURCE.NULL = !(source.hasData() && (external || package.isEmpty())); + P.RDB$PROCEDURE_SOURCE.NULL = !(source.hasData() && (external || name.package.isEmpty())); if (!P.RDB$PROCEDURE_SOURCE.NULL) attachment->storeMetaDataBlob(tdbb, transaction, &P.RDB$PROCEDURE_SOURCE, source); - if (package.hasData()) + if (name.package.hasData()) { P.RDB$PRIVATE_FLAG.NULL = FALSE; P.RDB$PRIVATE_FLAG = privateScope; @@ -2956,7 +3060,7 @@ bool CreateAlterProcedureNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch collectParameters(tdbb, transaction, collectedParameters); // Delete all old input and output parameters. - DropProcedureNode::dropParameters(tdbb, transaction, name, package); + DropProcedureNode::dropParameters(tdbb, transaction, name); // And insert the new ones. @@ -2988,17 +3092,21 @@ bool CreateAlterProcedureNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch PRM IN RDB$PROCEDURE_PARAMETERS CROSS RFR IN RDB$RELATION_FIELDS CROSS VRL IN RDB$VIEW_RELATIONS - WITH PRM.RDB$PROCEDURE_NAME EQ name.c_str() AND - PRM.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '') AND + WITH PRM.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + PRM.RDB$PROCEDURE_NAME EQ name.object.c_str() AND + PRM.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') AND + VRL.RDB$RELATION_SCHEMA_NAME EQ PRM.RDB$SCHEMA_NAME AND VRL.RDB$RELATION_NAME EQ PRM.RDB$PROCEDURE_NAME AND VRL.RDB$PACKAGE_NAME EQUIV PRM.RDB$PACKAGE_NAME AND VRL.RDB$CONTEXT_TYPE EQ VCT_PROCEDURE AND + RFR.RDB$SCHEMA_NAME EQ VRL.RDB$SCHEMA_NAME AND RFR.RDB$RELATION_NAME EQ VRL.RDB$VIEW_NAME AND RFR.RDB$VIEW_CONTEXT EQ VRL.RDB$VIEW_CONTEXT AND RFR.RDB$BASE_FIELD = PRM.RDB$PARAMETER_NAME { MODIFY RFR { + strcpy(RFR.RDB$FIELD_SOURCE_SCHEMA_NAME, PRM.RDB$FIELD_SOURCE_SCHEMA_NAME); strcpy(RFR.RDB$FIELD_SOURCE, PRM.RDB$FIELD_SOURCE); } END_MODIFY @@ -3009,7 +3117,8 @@ bool CreateAlterProcedureNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch return modified; } -bool CreateAlterProcedureNode::executeAlterIndividualParameters(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, bool secondPass, bool runTriggers) +bool CreateAlterProcedureNode::executeAlterIndividualParameters(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, + jrd_tra* transaction, bool secondPass, bool runTriggers) { Attachment* const attachment = transaction->getAttachment(); @@ -3019,21 +3128,19 @@ bool CreateAlterProcedureNode::executeAlterIndividualParameters(thread_db* tdbb, FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) P IN RDB$PROCEDURES - WITH P.RDB$PROCEDURE_NAME EQ name.c_str() AND - P.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '') + WITH P.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + P.RDB$PROCEDURE_NAME EQ name.object.c_str() AND + P.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') { if (P.RDB$SYSTEM_FLAG) { status_exception::raise( Arg::Gds(isc_dyn_cannot_mod_sysproc) << - MetaName(P.RDB$PROCEDURE_NAME)); + name.toQuotedString()); } - if (!secondPass && runTriggers && package.isEmpty()) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_ALTER_PROCEDURE, name, NULL); - } + if (!secondPass && runTriggers && name.package.isEmpty()) + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_PROCEDURE, name, {}); MODIFY P if (ssDefiner.has_value()) @@ -3067,16 +3174,15 @@ void CreateAlterProcedureNode::storeParameter(thread_db* tdbb, DsqlCompilerScrat STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PRM IN RDB$PROCEDURE_PARAMETERS { - PRM.RDB$PARAMETER_NAME.NULL = FALSE; strcpy(PRM.RDB$PARAMETER_NAME, parameter->name.c_str()); - PRM.RDB$PROCEDURE_NAME.NULL = FALSE; - strcpy(PRM.RDB$PROCEDURE_NAME, name.c_str()); + strcpy(PRM.RDB$SCHEMA_NAME, name.schema.c_str()); + strcpy(PRM.RDB$PROCEDURE_NAME, name.object.c_str()); - if (package.hasData()) + if (name.package.hasData()) { PRM.RDB$PACKAGE_NAME.NULL = FALSE; - strcpy(PRM.RDB$PACKAGE_NAME, package.c_str()); + strcpy(PRM.RDB$PACKAGE_NAME, name.package.c_str()); } else PRM.RDB$PACKAGE_NAME.NULL = TRUE; @@ -3091,39 +3197,45 @@ void CreateAlterProcedureNode::storeParameter(thread_db* tdbb, DsqlCompilerScrat PRM.RDB$PARAMETER_TYPE = parameterType; PRM.RDB$PARAMETER_MECHANISM.NULL = FALSE; - PRM.RDB$PARAMETER_MECHANISM = (USHORT) (type->fullDomain || type->typeOfName.isEmpty() ? + PRM.RDB$PARAMETER_MECHANISM = (USHORT) (type->fullDomain || type->typeOfName.object.isEmpty() ? prm_mech_normal : prm_mech_type_of); PRM.RDB$NULL_FLAG.NULL = !type->notNull; PRM.RDB$NULL_FLAG = type->notNull; - PRM.RDB$RELATION_NAME.NULL = type->typeOfTable.isEmpty(); - PRM.RDB$FIELD_NAME.NULL = PRM.RDB$RELATION_NAME.NULL || type->typeOfName.isEmpty(); + PRM.RDB$RELATION_SCHEMA_NAME.NULL = PRM.RDB$RELATION_NAME.NULL = type->typeOfTable.object.isEmpty(); + PRM.RDB$FIELD_NAME.NULL = PRM.RDB$RELATION_NAME.NULL || type->typeOfName.object.isEmpty(); PRM.RDB$FIELD_SOURCE.NULL = FALSE; if (PRM.RDB$RELATION_NAME.NULL) { - if (type->typeOfName.hasData()) - strcpy(PRM.RDB$FIELD_SOURCE, type->typeOfName.c_str()); + if (type->typeOfName.object.hasData()) + { + strcpy(PRM.RDB$FIELD_SOURCE_SCHEMA_NAME, type->typeOfName.schema.c_str()); + strcpy(PRM.RDB$FIELD_SOURCE, type->typeOfName.object.c_str()); + } else { - MetaName fieldName; + QualifiedName fieldName({}, name.schema); storeGlobalField(tdbb, transaction, fieldName, type); - strcpy(PRM.RDB$FIELD_SOURCE, fieldName.c_str()); + strcpy(PRM.RDB$FIELD_SOURCE_SCHEMA_NAME, fieldName.schema.c_str()); + strcpy(PRM.RDB$FIELD_SOURCE, fieldName.object.c_str()); } } else { - strcpy(PRM.RDB$RELATION_NAME, type->typeOfTable.c_str()); - strcpy(PRM.RDB$FIELD_NAME, type->typeOfName.c_str()); - strcpy(PRM.RDB$FIELD_SOURCE, type->fieldSource.c_str()); + strcpy(PRM.RDB$RELATION_SCHEMA_NAME, type->typeOfTable.schema.c_str()); + strcpy(PRM.RDB$RELATION_NAME, type->typeOfTable.object.c_str()); + strcpy(PRM.RDB$FIELD_NAME, type->typeOfName.object.c_str()); + strcpy(PRM.RDB$FIELD_SOURCE_SCHEMA_NAME, type->fieldSource.schema.c_str()); + strcpy(PRM.RDB$FIELD_SOURCE, type->fieldSource.object.c_str()); } // ASF: If we used a collate with a domain or table.column type, write it // in RDB$PROCEDURE_PARAMETERS. - PRM.RDB$COLLATION_ID.NULL = !(type->collate.hasData() && type->typeOfName.hasData()); + PRM.RDB$COLLATION_ID.NULL = !(type->collate.object.hasData() && type->typeOfName.object.hasData()); if (!PRM.RDB$COLLATION_ID.NULL) PRM.RDB$COLLATION_ID = type->collationId; @@ -3141,8 +3253,8 @@ void CreateAlterProcedureNode::storeParameter(thread_db* tdbb, DsqlCompilerScrat { status_exception::raise( Arg::Gds(isc_dyn_defvaldecl_package_proc) << - package.c_str() << - name.c_str()); + name.getSchemaAndPackage().toQuotedString() << + name.object); } attachment->storeMetaDataBlob(tdbb, transaction, &PRM.RDB$DEFAULT_SOURCE, @@ -3183,7 +3295,7 @@ void CreateAlterProcedureNode::storeParameter(thread_db* tdbb, DsqlCompilerScrat void CreateAlterProcedureNode::compile(thread_db* /*tdbb*/, DsqlCompilerScratch* dsqlScratch) { if (invalid) - status_exception::raise(Arg::Gds(isc_dyn_invalid_ddl_proc) << name); + status_exception::raise(Arg::Gds(isc_dyn_invalid_ddl_proc) << name.toQuotedString()); if (compiled) return; @@ -3236,7 +3348,7 @@ void CreateAlterProcedureNode::compile(thread_db* /*tdbb*/, DsqlCompilerScratch* i != dsqlScratch->outputVariables.end(); ++i) { - dsqlScratch->putLocalVariable(*i, nullptr, {}); + dsqlScratch->putLocalVariable(*i); } // ASF: This is here to not change the old logic (proc_flag) @@ -3280,8 +3392,9 @@ void CreateAlterProcedureNode::collectParameters(thread_db* tdbb, jrd_tra* trans FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PRM IN RDB$PROCEDURE_PARAMETERS - WITH PRM.RDB$PROCEDURE_NAME EQ name.c_str() AND - PRM.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '') + WITH PRM.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + PRM.RDB$PROCEDURE_NAME EQ name.object.c_str() AND + PRM.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') { CollectedParameter parameter; parameter.comment = PRM.RDB$DESCRIPTION; @@ -3296,15 +3409,15 @@ void CreateAlterProcedureNode::collectParameters(thread_db* tdbb, jrd_tra* trans //---------------------- -void DropProcedureNode::dropParameters(thread_db* tdbb, jrd_tra* transaction, - const MetaName& procedureName, const MetaName& packageName) +void DropProcedureNode::dropParameters(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& procedureName) { AutoCacheRequest requestHandle(tdbb, drq_e_prms2, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PRM IN RDB$PROCEDURE_PARAMETERS - WITH PRM.RDB$PROCEDURE_NAME EQ procedureName.c_str() AND - PRM.RDB$PACKAGE_NAME EQUIV NULLIF(packageName.c_str(), '') + WITH PRM.RDB$SCHEMA_NAME EQ procedureName.schema.c_str() AND + PRM.RDB$PROCEDURE_NAME EQ procedureName.object.c_str() AND + PRM.RDB$PACKAGE_NAME EQUIV NULLIF(procedureName.package.c_str(), '') { // get rid of parameters in rdb$fields if (!PRM.RDB$FIELD_SOURCE.NULL && PRM.RDB$RELATION_NAME.NULL && PRM.RDB$FIELD_NAME.NULL) @@ -3313,7 +3426,8 @@ void DropProcedureNode::dropParameters(thread_db* tdbb, jrd_tra* transaction, FOR (REQUEST_HANDLE requestHandle2 TRANSACTION_HANDLE transaction) FLD IN RDB$FIELDS - WITH FLD.RDB$FIELD_NAME EQ PRM.RDB$FIELD_SOURCE AND + WITH FLD.RDB$SCHEMA_NAME EQ PRM.RDB$FIELD_SOURCE_SCHEMA_NAME AND + FLD.RDB$FIELD_NAME EQ PRM.RDB$FIELD_SOURCE AND FLD.RDB$FIELD_NAME STARTING WITH IMPLICIT_DOMAIN_PREFIX AND FLD.RDB$SYSTEM_FLAG EQ 0 { @@ -3322,7 +3436,8 @@ void DropProcedureNode::dropParameters(thread_db* tdbb, jrd_tra* transaction, if (!FLD.RDB$SECURITY_CLASS.NULL) deleteSecurityClass(tdbb, transaction, FLD.RDB$SECURITY_CLASS); - deletePrivilegesByRelName(tdbb, transaction, FLD.RDB$FIELD_NAME, obj_field); + deletePrivilegesByRelName(tdbb, transaction, + QualifiedName(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME), obj_field); } END_FOR } @@ -3338,52 +3453,55 @@ string DropProcedureNode::internalPrint(NodePrinter& printer) const NODE_PRINT(printer, name); NODE_PRINT(printer, silent); - NODE_PRINT(printer, package); return "DropProcedureNode"; } DdlNode* DropProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { + if (recreate) + dsqlScratch->qualifyNewName(name); + else + dsqlScratch->qualifyExistingName(name, obj_exception); + + protectSystemSchema(name.schema, obj_procedure); + dsqlScratch->ddlSchema = name.schema; + dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_PROCEDURE); + return DdlNode::dsqlPass(dsqlScratch); } void DropProcedureNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - dsc dscName; - dscName.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str()); - SCL_check_procedure(tdbb, &dscName, SCL_drop); + SCL_check_procedure(tdbb, name, SCL_drop); } -void DropProcedureNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - jrd_tra* transaction) +void DropProcedureNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); bool found = false; - dropParameters(tdbb, transaction, name, package); + dropParameters(tdbb, transaction, name); AutoCacheRequest requestHandle(tdbb, drq_e_prcs2, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PRC IN RDB$PROCEDURES - WITH PRC.RDB$PROCEDURE_NAME EQ name.c_str() AND - PRC.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '') + WITH PRC.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + PRC.RDB$PROCEDURE_NAME EQ name.object.c_str() AND + PRC.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') { if (PRC.RDB$SYSTEM_FLAG) { status_exception::raise( Arg::Gds(isc_dyn_cannot_mod_sysproc) << - MetaName(PRC.RDB$PROCEDURE_NAME)); + name.toQuotedString()); } - if (package.isEmpty()) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_DROP_PROCEDURE, name, NULL); - } + if (name.package.isEmpty()) + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_PROCEDURE, name, {}); ERASE PRC; @@ -3395,35 +3513,34 @@ void DropProcedureNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc END_FOR if (!found && !silent) - status_exception::raise(Arg::Gds(isc_dyn_proc_not_found) << Arg::Str(name)); + status_exception::raise(Arg::Gds(isc_dyn_proc_not_found) << name.toQuotedString()); - if (package.isEmpty()) + if (name.package.isEmpty()) { deletePrivilegesByRelName(tdbb, transaction, name, obj_procedure); requestHandle.reset(tdbb, drq_e_prc_prv, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) - PRIV IN RDB$USER_PRIVILEGES WITH PRIV.RDB$USER EQ name.c_str() - AND PRIV.RDB$USER_TYPE = obj_procedure - AND PRIV.RDB$GRANTOR NOT MISSING + PRIV IN RDB$USER_PRIVILEGES + WITH PRIV.RDB$USER_SCHEMA_NAME EQ name.schema.c_str() AND + PRIV.RDB$USER EQ name.object.c_str() AND + PRIV.RDB$USER_TYPE = obj_procedure AND + PRIV.RDB$GRANTOR NOT MISSING { ERASE PRIV; } END_FOR } - if (found && package.isEmpty()) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_PROCEDURE, - name, NULL); - } + if (found && name.package.isEmpty()) + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_PROCEDURE, name, {}); savePoint.release(); // everything is ok // Update DSQL cache - METD_drop_procedure(transaction, QualifiedName(name, package)); - MET_dsql_cache_release(tdbb, SYM_procedure, name, package); + METD_drop_procedure(transaction, name); + MET_dsql_cache_release(tdbb, SYM_procedure, name); } @@ -3432,7 +3549,9 @@ void DropProcedureNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc void TriggerDefinition::store(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { - if (name.isEmpty()) + fb_assert(relationName.object.isEmpty() || name.schema == relationName.schema); + + if (name.object.isEmpty()) DYN_UTIL_generate_trigger_name(tdbb, transaction, name); AutoCacheRequest requestHandle(tdbb, drq_s_triggers, DYN_REQUESTS); @@ -3442,10 +3561,12 @@ void TriggerDefinition::store(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, { TRG.RDB$SYSTEM_FLAG = SSHORT(systemFlag); TRG.RDB$FLAGS = TRG_sql | (fkTrigger ? TRG_ignore_perm : 0); - strcpy(TRG.RDB$TRIGGER_NAME, name.c_str()); - TRG.RDB$RELATION_NAME.NULL = relationName.isEmpty(); - strcpy(TRG.RDB$RELATION_NAME, relationName.c_str()); + strcpy(TRG.RDB$SCHEMA_NAME, name.schema.c_str()); + strcpy(TRG.RDB$TRIGGER_NAME, name.object.c_str()); + + TRG.RDB$RELATION_NAME.NULL = relationName.object.isEmpty(); + strcpy(TRG.RDB$RELATION_NAME, relationName.object.c_str()); fb_assert(type.has_value()); TRG.RDB$TRIGGER_TYPE = type.value(); @@ -3458,8 +3579,7 @@ void TriggerDefinition::store(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, modify(tdbb, dsqlScratch, transaction); } -bool TriggerDefinition::modify(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - jrd_tra* transaction) +bool TriggerDefinition::modify(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { Attachment* const attachment = transaction->getAttachment(); bool modified = false; @@ -3468,7 +3588,8 @@ bool TriggerDefinition::modify(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) TRG IN RDB$TRIGGERS - WITH TRG.RDB$TRIGGER_NAME EQ name.c_str() + WITH TRG.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + TRG.RDB$TRIGGER_NAME EQ name.object.c_str() { if (type.has_value() && type != (FB_UINT64) TRG.RDB$TRIGGER_TYPE && TRG.RDB$RELATION_NAME.NULL) @@ -3489,8 +3610,8 @@ bool TriggerDefinition::modify(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch break; case fb_sysflag_system: - status_exception::raise( - Arg::Gds(isc_dyn_cannot_mod_systrig) << MetaName(TRG.RDB$TRIGGER_NAME)); + status_exception::raise(Arg::Gds(isc_dyn_cannot_mod_systrig) << + QualifiedName(TRG.RDB$TRIGGER_NAME, TRG.RDB$SCHEMA_NAME).toQuotedString()); break; default: @@ -3513,9 +3634,10 @@ bool TriggerDefinition::modify(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch TRG.RDB$VALID_BLR.NULL = TRUE; } - TRG.RDB$RELATION_NAME.NULL = relationName.isEmpty(); - if (relationName.hasData()) - strcpy(TRG.RDB$RELATION_NAME, relationName.c_str()); + fb_assert(relationName.object.isEmpty() || name.schema == relationName.schema); + TRG.RDB$RELATION_NAME.NULL = relationName.object.isEmpty(); + if (relationName.object.hasData()) + strcpy(TRG.RDB$RELATION_NAME, relationName.object.c_str()); if (type.has_value()) TRG.RDB$TRIGGER_TYPE = type.value(); @@ -3600,14 +3722,40 @@ string CreateAlterTriggerNode::internalPrint(NodePrinter& printer) const DdlNode* CreateAlterTriggerNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { + dsqlScratch->qualifyExistingName(relationName, obj_relation); + + if (name.schema.isEmpty()) + name.schema = relationName.schema; + + if (relationName.object.isEmpty()) + { + if (create) + dsqlScratch->qualifyNewName(name); + else + dsqlScratch->qualifyExistingName(name, obj_trigger); + } + else + { + if (name.schema != relationName.schema) + { + status_exception::raise( + Arg::Gds(isc_dyn_trig_schema_must_match_table) << + name.schema.toQuotedString() << + relationName.schema.toQuotedString()); + } + } + + protectSystemSchema(name.schema, obj_trigger); + dsqlScratch->ddlSchema = name.schema; + dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_TRIGGER); if (type.has_value()) { if (create && // ALTER TRIGGER doesn't accept table name - ((relationName.hasData() && + ((relationName.object.hasData() && (type.value() & (unsigned) TRIGGER_TYPE_MASK) != (unsigned) TRIGGER_TYPE_DML) || - (relationName.isEmpty() && + (relationName.object.isEmpty() && (type.value() & (unsigned) TRIGGER_TYPE_MASK) != (unsigned) TRIGGER_TYPE_DB && (type.value() & (unsigned) TRIGGER_TYPE_MASK) != (unsigned) TRIGGER_TYPE_DDL))) { @@ -3631,26 +3779,23 @@ void CreateAlterTriggerNode::checkPermission(thread_db* tdbb, jrd_tra* transacti FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) TRG IN RDB$TRIGGERS - WITH TRG.RDB$TRIGGER_NAME EQ name.c_str() + WITH TRG.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + TRG.RDB$TRIGGER_NAME EQ name.object.c_str() { if (!type.has_value() && !TRG.RDB$TRIGGER_TYPE.NULL) type = TRG.RDB$TRIGGER_TYPE; - if (relationName.isEmpty() && !TRG.RDB$RELATION_NAME.NULL) - relationName = TRG.RDB$RELATION_NAME; + if (relationName.object.isEmpty() && !TRG.RDB$RELATION_NAME.NULL) + relationName = QualifiedName(TRG.RDB$RELATION_NAME, TRG.RDB$SCHEMA_NAME); } END_FOR if (!type.has_value()) - status_exception::raise(Arg::Gds(isc_dyn_trig_not_found) << Arg::Str(name)); + status_exception::raise(Arg::Gds(isc_dyn_trig_not_found) << name.toQuotedString()); } - if (relationName.hasData()) - { - dsc dscName; - dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) relationName.c_str()); - SCL_check_relation(tdbb, &dscName, SCL_alter); - } + if (relationName.object.hasData()) + SCL_check_relation(tdbb, relationName, SCL_alter); else SCL_check_database(tdbb, SCL_alter); } @@ -3679,7 +3824,7 @@ void CreateAlterTriggerNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlS if (create) // create or alter executeCreate(tdbb, dsqlScratch, transaction); else - status_exception::raise(Arg::Gds(isc_dyn_trig_not_found) << Arg::Str(name)); + status_exception::raise(Arg::Gds(isc_dyn_trig_not_found) << name.toQuotedString()); } } else @@ -3694,21 +3839,19 @@ void CreateAlterTriggerNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_trigger)) return; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_TRIGGER, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_TRIGGER, name, {}); DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_trigger); store(tdbb, dsqlScratch, transaction); - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_TRIGGER, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_TRIGGER, name, {}); } void CreateAlterTriggerNode::compile(thread_db* /*tdbb*/, DsqlCompilerScratch* dsqlScratch) { if (invalid) - status_exception::raise(Arg::Gds(isc_dyn_invalid_ddl_trig) << name); + status_exception::raise(Arg::Gds(isc_dyn_invalid_ddl_trig) << name.toQuotedString()); if (compiled) return; @@ -3728,12 +3871,12 @@ void CreateAlterTriggerNode::compile(thread_db* /*tdbb*/, DsqlCompilerScratch* d if (dsqlScratch->contextNumber) dsqlScratch->resetTriggerContextStack(); - if (relationName.hasData()) + if (relationName.object.hasData()) { RelationSourceNode* relationNode = FB_NEW_POOL(dsqlScratch->getPool()) RelationSourceNode( dsqlScratch->getPool(), relationName); - const string temp = relationNode->alias; // always empty? + const auto temp = relationNode->alias; // always empty? if (hasOldContext(type.value())) { @@ -3822,37 +3965,42 @@ string DropTriggerNode::internalPrint(NodePrinter& printer) const DdlNode* DropTriggerNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { + if (recreate) + dsqlScratch->qualifyNewName(name); + else + dsqlScratch->qualifyExistingName(name, obj_trigger); + + protectSystemSchema(name.schema, obj_trigger); + dsqlScratch->ddlSchema = name.schema; + dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_TRIGGER); + return DdlNode::dsqlPass(dsqlScratch); } void DropTriggerNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - MetaName relationName = getTriggerRelationName(tdbb, transaction, name); + const auto relationName = getTriggerRelationName(tdbb, transaction, name); - if (relationName.isEmpty()) + if (relationName.object.isEmpty()) SCL_check_database(tdbb, SCL_alter); else - { - dsc dscName; - dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) relationName.c_str()); - SCL_check_relation(tdbb, &dscName, SCL_alter); - } + SCL_check_relation(tdbb, relationName, SCL_alter); } -void DropTriggerNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - jrd_tra* transaction) +void DropTriggerNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); bool found = false; - MetaName relationName; + QualifiedName relationName; AutoCacheRequest requestHandle(tdbb, drq_e_trigger3, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) X IN RDB$TRIGGERS - WITH X.RDB$TRIGGER_NAME EQ name.c_str() + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$TRIGGER_NAME EQ name.object.c_str() { switch (X.RDB$SYSTEM_FLAG) { @@ -3863,31 +4011,31 @@ void DropTriggerNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, break; case fb_sysflag_system: - status_exception::raise( - Arg::Gds(isc_dyn_cannot_mod_systrig) << MetaName(X.RDB$TRIGGER_NAME)); + status_exception::raise(Arg::Gds(isc_dyn_cannot_mod_systrig) << + name.toQuotedString()); break; default: break; } - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_TRIGGER, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_TRIGGER, name, {}); - relationName = X.RDB$RELATION_NAME; + relationName = QualifiedName(X.RDB$RELATION_NAME, X.RDB$SCHEMA_NAME); ERASE X; found = true; } END_FOR if (!found && !silent) - status_exception::raise(Arg::Gds(isc_dyn_trig_not_found) << Arg::Str(name)); + status_exception::raise(Arg::Gds(isc_dyn_trig_not_found) << name.toQuotedString()); requestHandle.reset(tdbb, drq_e_trg_msgs3, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) TM IN RDB$TRIGGER_MESSAGES - WITH TM.RDB$TRIGGER_NAME EQ name.c_str() + WITH TM.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + TM.RDB$TRIGGER_NAME EQ name.object.c_str() { ERASE TM; } @@ -3897,7 +4045,8 @@ void DropTriggerNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PRIV IN RDB$USER_PRIVILEGES - WITH PRIV.RDB$USER EQ name.c_str() AND + WITH PRIV.RDB$USER_SCHEMA_NAME EQ name.schema.c_str() AND + PRIV.RDB$USER EQ name.object.c_str() AND PRIV.RDB$USER_TYPE = obj_trigger AND PRIV.RDB$GRANTOR NOT MISSING { @@ -3905,44 +4054,48 @@ void DropTriggerNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, } END_FOR - // Clear the update flags on the fields if this is the last remaining - // trigger that changes a view. - - bool viewFound = false; - requestHandle.reset(tdbb, drq_e_trg_prv3, DYN_REQUESTS); - - FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) - FIRST 1 V IN RDB$VIEW_RELATIONS - CROSS F IN RDB$RELATION_FIELDS - CROSS T IN RDB$TRIGGERS - WITH V.RDB$VIEW_NAME EQ relationName.c_str() AND - F.RDB$RELATION_NAME EQ V.RDB$VIEW_NAME AND - F.RDB$RELATION_NAME EQ T.RDB$RELATION_NAME + if (relationName.object.hasData()) { - viewFound = true; - } - END_FOR + // Clear the update flags on the fields if this is the last remaining trigger that changes a view. - if (!viewFound) - { - requestHandle.reset(tdbb, drq_m_rel_flds2, DYN_REQUESTS); + bool viewFound = false; + + requestHandle.reset(tdbb, drq_e_trg_prv3, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) - F IN RDB$RELATION_FIELDS - WITH F.RDB$RELATION_NAME EQ relationName.c_str() + FIRST 1 V IN RDB$VIEW_RELATIONS + CROSS F IN RDB$RELATION_FIELDS + CROSS T IN RDB$TRIGGERS + WITH V.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + V.RDB$VIEW_NAME EQ relationName.object.c_str() AND + F.RDB$SCHEMA_NAME EQ V.RDB$SCHEMA_NAME AND + F.RDB$RELATION_NAME EQ V.RDB$VIEW_NAME AND + T.RDB$SCHEMA_NAME EQ F.RDB$SCHEMA_NAME AND + T.RDB$RELATION_NAME EQ F.RDB$RELATION_NAME { - MODIFY F USING - F.RDB$UPDATE_FLAG = FALSE; - END_MODIFY + viewFound = true; } END_FOR + + if (!viewFound) + { + requestHandle.reset(tdbb, drq_m_rel_flds2, DYN_REQUESTS); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + F IN RDB$RELATION_FIELDS + WITH F.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + F.RDB$RELATION_NAME EQ relationName.object.c_str() + { + MODIFY F USING + F.RDB$UPDATE_FLAG = FALSE; + END_MODIFY + } + END_FOR + } } if (found) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_TRIGGER, - name, NULL); - } + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_TRIGGER, name, {}); savePoint.release(); // everything is ok } @@ -3970,7 +4123,7 @@ string CreateCollationNode::internalPrint(NodePrinter& printer) const void CreateCollationNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - SCL_check_create_access(tdbb, obj_collations); + SCL_check_create_access(tdbb, obj_collations, name.schema); } void CreateCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, @@ -3985,8 +4138,7 @@ void CreateCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_collation)) return; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_CREATE_COLLATION, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_COLLATION, name, {}); DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_collation); @@ -3996,7 +4148,9 @@ void CreateCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra X IN RDB$COLLATIONS { X.RDB$CHARACTER_SET_ID = forCharSetId; - strcpy(X.RDB$COLLATION_NAME, name.c_str()); + + strcpy(X.RDB$SCHEMA_NAME, name.schema.c_str()); + strcpy(X.RDB$COLLATION_NAME, name.object.c_str()); X.RDB$SYSTEM_FLAG = 0; X.RDB$OWNER_NAME.NULL = FALSE; @@ -4008,7 +4162,7 @@ void CreateCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra CharSet* cs = INTL_charset_lookup(tdbb, forCharSetId); SubtypeInfo info; - if (fromName.hasData()) + if (fromName.object.hasData()) { if (MET_get_char_coll_subtype_info(tdbb, INTL_CS_COLL_TO_TTYPE(forCharSetId, fromCollationId), &info) && @@ -4046,20 +4200,24 @@ void CreateCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra specificAttributes = temp; } - info.charsetName = forCharSet.c_str(); + info.charsetName = forCharSet; info.collationName = name; + if (X.RDB$BASE_COLLATION_NAME.NULL) - info.baseCollationName = info.collationName; + info.baseCollationName = info.collationName.object.c_str(); else + { info.baseCollationName = X.RDB$BASE_COLLATION_NAME; + info.baseCollationName.rtrim(); + } + info.ignoreAttributes = false; - if (!IntlManager::collationInstalled(info.baseCollationName.c_str(), - info.charsetName.c_str())) + if (!IntlManager::collationInstalled(info.baseCollationName, info.charsetName)) { // msg: 223: "Collation @1 not installed for character set @2" status_exception::raise( - Arg::PrivateDyn(223) << info.baseCollationName << info.charsetName); + Arg::PrivateDyn(223) << info.baseCollationName << info.charsetName.toQuotedString()); } IntlUtil::SpecificAttributesMap map; @@ -4077,7 +4235,7 @@ void CreateCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra string newSpecificAttributes; if (!IntlManager::setupCollationAttributes( - info.baseCollationName.c_str(), info.charsetName.c_str(), s, + info.baseCollationName, info.charsetName, s, newSpecificAttributes)) { // msg: 222: "Invalid collation attributes" @@ -4117,7 +4275,7 @@ void CreateCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra FOR(REQUEST_HANDLE request2) Y IN RDB$COLLATIONS WITH Y.RDB$CHARACTER_SET_ID = forCharSetId AND - Y.RDB$COLLATION_ID NOT MISSING + Y.RDB$COLLATION_ID NOT MISSING SORTED BY DESCENDING Y.RDB$COLLATION_ID { if (Y.RDB$COLLATION_ID + 1 <= X.RDB$COLLATION_ID) @@ -4137,8 +4295,7 @@ void CreateCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra storePrivileges(tdbb, transaction, name, obj_collation, USAGE_PRIVILEGES); - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, - DDL_TRIGGER_CREATE_COLLATION, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_COLLATION, name, {}); savePoint.release(); // everything is ok @@ -4149,19 +4306,27 @@ void CreateCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra DdlNode* CreateCollationNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { - const dsql_intlsym* resolvedCharSet = METD_get_charset( - dsqlScratch->getTransaction(), forCharSet.length(), forCharSet.c_str()); + dsqlScratch->qualifyNewName(name); + protectSystemSchema(name.schema, obj_collation); + dsqlScratch->ddlSchema = name.schema; + + dsqlScratch->qualifyExistingName(forCharSet, obj_charset); + + if (fromName.object.hasData()) + dsqlScratch->qualifyExistingName(fromName, obj_collation); + + const dsql_intlsym* resolvedCharSet = METD_get_charset(dsqlScratch->getTransaction(), forCharSet); if (!resolvedCharSet) { // specified character set not found ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-504) << - Arg::Gds(isc_charset_not_found) << forCharSet); + Arg::Gds(isc_charset_not_found) << forCharSet.toQuotedString()); } forCharSetId = resolvedCharSet->intlsym_charset_id; - if (fromName.hasData()) + if (fromName.object.hasData()) { const dsql_intlsym* resolvedCollation = METD_get_collation( dsqlScratch->getTransaction(), fromName, forCharSetId); @@ -4170,7 +4335,7 @@ DdlNode* CreateCollationNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { // Specified collation not found ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) << - Arg::Gds(isc_collation_not_found) << fromName << forCharSet); + Arg::Gds(isc_collation_not_found) << fromName.toQuotedString() << forCharSet.toQuotedString()); } fromCollationId = resolvedCollation->intlsym_collate_id; @@ -4197,8 +4362,7 @@ void DropCollationNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) SCL_check_collation(tdbb, name, SCL_drop); } -void DropCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - jrd_tra* transaction) +void DropCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); @@ -4209,24 +4373,22 @@ void DropCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) COLL IN RDB$COLLATIONS CROSS CS IN RDB$CHARACTER_SETS - WITH COLL.RDB$COLLATION_NAME EQ name.c_str() AND + WITH COLL.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + COLL.RDB$COLLATION_NAME EQ name.object.c_str() AND CS.RDB$CHARACTER_SET_ID EQ COLL.RDB$CHARACTER_SET_ID { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_DROP_COLLATION, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_COLLATION, name, {}); if (COLL.RDB$SYSTEM_FLAG) status_exception::raise(Arg::Gds(isc_dyn_cannot_del_syscoll)); if (COLL.RDB$COLLATION_ID == 0 || (!CS.RDB$DEFAULT_COLLATE_NAME.NULL && - MetaName(COLL.RDB$COLLATION_NAME) == MetaName(CS.RDB$DEFAULT_COLLATE_NAME))) + name == QualifiedName(CS.RDB$DEFAULT_COLLATE_NAME, CS.RDB$DEFAULT_COLLATE_SCHEMA_NAME))) { - fb_utils::exact_name_limit(CS.RDB$CHARACTER_SET_NAME, - sizeof(CS.RDB$CHARACTER_SET_NAME)); - status_exception::raise( - Arg::Gds(isc_dyn_cannot_del_def_coll) << CS.RDB$CHARACTER_SET_NAME); + Arg::Gds(isc_dyn_cannot_del_def_coll) << + QualifiedName(CS.RDB$CHARACTER_SET_NAME, CS.RDB$SCHEMA_NAME).toQuotedString()); } found = true; @@ -4237,34 +4399,40 @@ void DropCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) RF IN RDB$RELATION_FIELDS CROSS F IN RDB$FIELDS - WITH RF.RDB$FIELD_SOURCE EQ F.RDB$FIELD_NAME AND - F.RDB$CHARACTER_SET_ID EQ COLL.RDB$CHARACTER_SET_ID AND - RF.RDB$COLLATION_ID EQ COLL.RDB$COLLATION_ID + WITH RF.RDB$COLLATION_ID EQ COLL.RDB$COLLATION_ID AND + F.RDB$SCHEMA_NAME EQUIV RF.RDB$FIELD_SOURCE_SCHEMA_NAME AND + F.RDB$FIELD_NAME EQ RF.RDB$FIELD_SOURCE AND + F.RDB$CHARACTER_SET_ID EQ COLL.RDB$CHARACTER_SET_ID + { - fb_utils::exact_name_limit(RF.RDB$RELATION_NAME, sizeof(RF.RDB$RELATION_NAME)); fb_utils::exact_name_limit(RF.RDB$FIELD_NAME, sizeof(RF.RDB$FIELD_NAME)); status_exception::raise( - Arg::Gds(isc_dyn_coll_used_table) << COLL.RDB$COLLATION_NAME << - RF.RDB$RELATION_NAME << RF.RDB$FIELD_NAME); + Arg::Gds(isc_dyn_coll_used_table) << + name.toQuotedString() << + QualifiedName(RF.RDB$RELATION_NAME, RF.RDB$SCHEMA_NAME).toQuotedString() << + RF.RDB$FIELD_NAME); } END_FOR request2.reset(tdbb, drq_l_prm_coll, DYN_REQUESTS); FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) - PRM IN RDB$PROCEDURE_PARAMETERS CROSS F IN RDB$FIELDS - WITH PRM.RDB$FIELD_SOURCE EQ F.RDB$FIELD_NAME AND - F.RDB$CHARACTER_SET_ID EQ COLL.RDB$CHARACTER_SET_ID AND - PRM.RDB$COLLATION_ID EQ COLL.RDB$COLLATION_ID + PRM IN RDB$PROCEDURE_PARAMETERS + CROSS F IN RDB$FIELDS + WITH PRM.RDB$COLLATION_ID EQ COLL.RDB$COLLATION_ID AND + F.RDB$SCHEMA_NAME EQUIV PRM.RDB$FIELD_SOURCE_SCHEMA_NAME AND + F.RDB$FIELD_NAME EQ PRM.RDB$FIELD_SOURCE AND + F.RDB$CHARACTER_SET_ID EQ COLL.RDB$CHARACTER_SET_ID + { fb_utils::exact_name_limit(PRM.RDB$PARAMETER_NAME, sizeof(PRM.RDB$PARAMETER_NAME)); status_exception::raise( Arg::Gds(isc_dyn_coll_used_procedure) << - COLL.RDB$COLLATION_NAME << - QualifiedName(PRM.RDB$PROCEDURE_NAME, - (PRM.RDB$PACKAGE_NAME.NULL ? NULL : PRM.RDB$PACKAGE_NAME)).toString().c_str() << + name.toQuotedString() << + QualifiedName(PRM.RDB$PROCEDURE_NAME, PRM.RDB$SCHEMA_NAME, + (PRM.RDB$PACKAGE_NAME.NULL ? NULL : PRM.RDB$PACKAGE_NAME)).toQuotedString() << PRM.RDB$PARAMETER_NAME); } END_FOR @@ -4272,18 +4440,21 @@ void DropCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc request2.reset(tdbb, drq_l_arg_coll, DYN_REQUESTS); FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) - ARG IN RDB$FUNCTION_ARGUMENTS CROSS F IN RDB$FIELDS - WITH ARG.RDB$FIELD_SOURCE EQ F.RDB$FIELD_NAME AND - F.RDB$CHARACTER_SET_ID EQ COLL.RDB$CHARACTER_SET_ID AND - ARG.RDB$COLLATION_ID EQ COLL.RDB$COLLATION_ID + ARG IN RDB$FUNCTION_ARGUMENTS + CROSS F IN RDB$FIELDS + WITH ARG.RDB$COLLATION_ID EQ COLL.RDB$COLLATION_ID AND + F.RDB$SCHEMA_NAME EQUIV ARG.RDB$FIELD_SOURCE_SCHEMA_NAME AND + F.RDB$FIELD_NAME EQ ARG.RDB$FIELD_SOURCE AND + F.RDB$CHARACTER_SET_ID EQ COLL.RDB$CHARACTER_SET_ID + { fb_utils::exact_name_limit(ARG.RDB$ARGUMENT_NAME, sizeof(ARG.RDB$ARGUMENT_NAME)); status_exception::raise( Arg::Gds(isc_dyn_coll_used_function) << - COLL.RDB$COLLATION_NAME << - QualifiedName(ARG.RDB$FUNCTION_NAME, - (ARG.RDB$PACKAGE_NAME.NULL ? NULL : ARG.RDB$PACKAGE_NAME)).toString().c_str() << + name.toQuotedString() << + QualifiedName(ARG.RDB$FUNCTION_NAME, ARG.RDB$SCHEMA_NAME, + (ARG.RDB$PACKAGE_NAME.NULL ? NULL : ARG.RDB$PACKAGE_NAME)).toQuotedString() << ARG.RDB$ARGUMENT_NAME); } END_FOR @@ -4298,7 +4469,9 @@ void DropCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc fb_utils::exact_name_limit(F.RDB$FIELD_NAME, sizeof(F.RDB$FIELD_NAME)); status_exception::raise( - Arg::Gds(isc_dyn_coll_used_domain) << COLL.RDB$COLLATION_NAME << F.RDB$FIELD_NAME); + Arg::Gds(isc_dyn_coll_used_domain) << + name.toQuotedString() << + F.RDB$FIELD_NAME); } END_FOR @@ -4312,12 +4485,9 @@ void DropCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc deletePrivilegesByRelName(tdbb, transaction, name, obj_collation); if (found) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_COLLATION, - name, NULL); - } + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_COLLATION, name, {}); else if (!silent) - status_exception::raise(Arg::Gds(isc_dyn_collation_not_found) << Arg::Str(name)); + status_exception::raise(Arg::Gds(isc_dyn_collation_not_found) << name.toQuotedString()); savePoint.release(); // everything is ok @@ -4334,7 +4504,9 @@ string CreateDomainNode::internalPrint(NodePrinter& printer) const { DdlNode::internalPrint(printer); - NODE_PRINT(printer, nameType); + NODE_PRINT(printer, name); + NODE_PRINT(printer, type); + NODE_PRINT(printer, defaultClause); NODE_PRINT(printer, notNull); NODE_PRINT(printer, check); @@ -4343,31 +4515,29 @@ string CreateDomainNode::internalPrint(NodePrinter& printer) const void CreateDomainNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - SCL_check_create_access(tdbb, obj_domains); + SCL_check_create_access(tdbb, obj_domains, name.schema); } -void CreateDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - jrd_tra* transaction) +void CreateDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { Attachment* const attachment = transaction->tra_attachment; - dsql_fld* type = nameType->type; // The commented line should be restored when implicit domains get their own sys flag. - //if (fb_utils::implicit_domain(nameType->name.c_str())) - if (strncmp(nameType->name.c_str(), IMPLICIT_DOMAIN_PREFIX, IMPLICIT_DOMAIN_PREFIX_LEN) == 0) + //if (fb_utils::implicit_domain(name.c_str())) + if (strncmp(name.object.c_str(), IMPLICIT_DOMAIN_PREFIX, IMPLICIT_DOMAIN_PREFIX_LEN) == 0) { status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-637) << - Arg::Gds(isc_dsql_implicit_domain_name) << nameType->name); + Arg::Gds(isc_dsql_implicit_domain_name) << name.toQuotedString()); } const ValueListNode* elements = type->ranges; const USHORT dims = elements ? elements->items.getCount() / 2 : 0; - if (nameType->defaultClause && dims != 0) + if (defaultClause && dims != 0) { // Default value is not allowed for array type in domain %s - status_exception::raise(Arg::PrivateDyn(226) << nameType->name); + status_exception::raise(Arg::PrivateDyn(226) << name.toQuotedString()); } type->resolve(dsqlScratch); @@ -4377,35 +4547,35 @@ void CreateDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); - if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, nameType->name, obj_field)) + if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_field)) return; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_CREATE_DOMAIN, nameType->name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_DOMAIN, name, {}); - DYN_UTIL_check_unique_name(tdbb, transaction, nameType->name, obj_field); + DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_field); - storeGlobalField(tdbb, transaction, nameType->name, type); + storeGlobalField(tdbb, transaction, name, type); - if (nameType->defaultClause || check || notNull) + if (defaultClause || check || notNull) { AutoCacheRequest request(tdbb, drq_m_fld, DYN_REQUESTS); FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) FLD IN RDB$FIELDS - WITH FLD.RDB$FIELD_NAME EQ nameType->name.c_str() + WITH FLD.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + FLD.RDB$FIELD_NAME EQ name.object.c_str() { MODIFY FLD - if (nameType->defaultClause) + if (defaultClause) { FLD.RDB$DEFAULT_SOURCE.NULL = FALSE; attachment->storeMetaDataBlob(tdbb, transaction, &FLD.RDB$DEFAULT_SOURCE, - nameType->defaultClause->source); + defaultClause->source); dsqlScratch->getBlrData().clear(); dsqlScratch->appendUChar(dsqlScratch->isVersion4() ? blr_version4 : blr_version5); - ValueExprNode* node = doDsqlPass(dsqlScratch, nameType->defaultClause->value); + ValueExprNode* node = doDsqlPass(dsqlScratch, defaultClause->value); GEN_expr(dsqlScratch, node); @@ -4454,8 +4624,7 @@ void CreateDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch END_FOR } - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, - DDL_TRIGGER_CREATE_DOMAIN, nameType->name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_DOMAIN, name, {}); savePoint.release(); // everything is ok } @@ -4850,18 +5019,18 @@ void AlterDomainNode::checkUpdate(const dyn_fld& origFld, const dyn_fld& newFld) { case isc_dyn_dtype_invalid: // Cannot change datatype for column %s.The operation cannot be performed on DATE, BLOB, or ARRAY columns. - status_exception::raise(Arg::Gds(errorCode) << origFld.dyn_fld_name.c_str()); + status_exception::raise(Arg::Gds(errorCode) << origFld.dyn_fld_name.toQuotedString()); break; case isc_dyn_dtype_conv_invalid: // Cannot convert column %s from character to non-character data. - status_exception::raise(Arg::Gds(errorCode) << origFld.dyn_fld_name.c_str()); + status_exception::raise(Arg::Gds(errorCode) << origFld.dyn_fld_name.toQuotedString()); break; case isc_dyn_char_fld_too_small: // msg 208: New size specified for column %s must be at least %d characters. status_exception::raise( - Arg::Gds(errorCode) << origFld.dyn_fld_name.c_str() << Arg::Num(origLen)); + Arg::Gds(errorCode) << origFld.dyn_fld_name.toQuotedString() << Arg::Num(origLen)); break; case isc_dyn_scale_too_big: @@ -4881,7 +5050,7 @@ void AlterDomainNode::checkUpdate(const dyn_fld& origFld, const dyn_fld& newFld) // scale_too_big: New scale specified for column @1 must be at most @2. // precision_too_small: New precision specified for column @1 must be at least @2. status_exception::raise( - Arg::Gds(code) << origFld.dyn_fld_name.c_str() << Arg::Num(diff)); + Arg::Gds(code) << origFld.dyn_fld_name.toQuotedString() << Arg::Num(diff)); } break; @@ -4894,7 +5063,7 @@ void AlterDomainNode::checkUpdate(const dyn_fld& origFld, const dyn_fld& newFld) // Cannot change datatype for @1. Conversion from base type @2 to @3 is not supported. status_exception::raise( - Arg::Gds(errorCode) << origFld.dyn_fld_name.c_str() << orig_type << new_type); + Arg::Gds(errorCode) << origFld.dyn_fld_name.toQuotedString() << orig_type << new_type); } break; @@ -4934,7 +5103,8 @@ void AlterDomainNode::getDomainType(thread_db* tdbb, jrd_tra* transaction, dyn_f FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) FLD IN RDB$FIELDS - WITH FLD.RDB$FIELD_NAME EQ dynFld.dyn_fld_source.c_str(); + WITH FLD.RDB$SCHEMA_NAME EQ dynFld.dyn_fld_source.schema.c_str() AND + FLD.RDB$FIELD_NAME EQ dynFld.dyn_fld_source.object.c_str() { DSC_make_descriptor(&dynFld.dyn_dsc, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE, FLD.RDB$FIELD_LENGTH, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$CHARACTER_SET_ID, @@ -4956,15 +5126,18 @@ void AlterDomainNode::getDomainType(thread_db* tdbb, jrd_tra* transaction, dyn_f // Updates the field names in an index and forces the index to be rebuilt with the new field names. void AlterDomainNode::modifyLocalFieldIndex(thread_db* tdbb, jrd_tra* transaction, - const MetaName& relationName, const MetaName& fieldName, const MetaName& newFieldName) + const QualifiedName& relationName, const MetaName& fieldName, const MetaName& newFieldName) { AutoRequest request; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - IDX IN RDB$INDICES CROSS IDXS IN RDB$INDEX_SEGMENTS WITH - IDX.RDB$INDEX_NAME EQ IDXS.RDB$INDEX_NAME AND - IDX.RDB$RELATION_NAME EQ relationName.c_str() AND - IDXS.RDB$FIELD_NAME EQ fieldName.c_str() + IDX IN RDB$INDICES + CROSS IDXS IN RDB$INDEX_SEGMENTS + WITH IDXS.RDB$SCHEMA_NAME EQ IDX.RDB$SCHEMA_NAME AND + IDXS.RDB$INDEX_NAME EQ IDX.RDB$INDEX_NAME AND + IDX.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + IDX.RDB$RELATION_NAME EQ relationName.object.c_str() AND + IDXS.RDB$FIELD_NAME EQ fieldName.c_str() { // Change the name of the field in the index MODIFY IDXS USING @@ -5002,11 +5175,13 @@ void AlterDomainNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) SCL_check_domain(tdbb, name, SCL_alter); } -void AlterDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - jrd_tra* transaction) +void AlterDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { Attachment* const attachment = transaction->tra_attachment; + QualifiedName qualifiedRenameTo = renameTo.hasData() ? + QualifiedName(renameTo, name.schema) : QualifiedName(); + // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); @@ -5015,17 +5190,18 @@ void AlterDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) FLD IN RDB$FIELDS - WITH FLD.RDB$FIELD_NAME EQ name.c_str() + WITH FLD.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + FLD.RDB$FIELD_NAME EQ name.object.c_str() { found = true; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_ALTER_DOMAIN, name, renameTo); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_DOMAIN, + name, qualifiedRenameTo); if (FLD.RDB$SYSTEM_FLAG == fb_sysflag_system) { status_exception::raise(Arg::Gds(isc_dyn_cant_modify_sysobj) << - "domain" << Arg::Str(name)); + "domain" << name.toQuotedString()); } MODIFY FLD @@ -5059,7 +5235,7 @@ void AlterDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-607) << Arg::Gds(isc_dsql_command_err) << - Arg::Gds(isc_dsql_domain_not_found) << name); + Arg::Gds(isc_dsql_domain_not_found) << name.toQuotedString()); } DsqlDescMaker::fromField(&dsqlScratch->domainValue, &localField); @@ -5095,7 +5271,7 @@ void AlterDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, if (FLD.RDB$DIMENSIONS) { // msg 226: "Default value is not allowed for array type in domain %s" - status_exception::raise(Arg::PrivateDyn(226) << name); + status_exception::raise(Arg::PrivateDyn(226) << name.toQuotedString()); } FLD.RDB$DEFAULT_SOURCE.NULL = FALSE; @@ -5130,17 +5306,21 @@ void AlterDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, IND IN RDB$INDICES CROSS INDSEG IN RDB$INDEX_SEGMENTS CROSS RELCON IN RDB$RELATION_CONSTRAINTS - WITH RFL.RDB$FIELD_SOURCE EQ name.c_str() AND + WITH RFL.RDB$FIELD_SOURCE_SCHEMA_NAME EQ name.schema.c_str() AND + RFL.RDB$FIELD_SOURCE EQ name.object.c_str() AND (RFL.RDB$NULL_FLAG MISSING OR RFL.RDB$NULL_FLAG EQ 0) AND + IND.RDB$SCHEMA_NAME EQ RFL.RDB$SCHEMA_NAME AND IND.RDB$RELATION_NAME EQ RFL.RDB$RELATION_NAME AND + INDSEG.RDB$SCHEMA_NAME EQ IND.RDB$SCHEMA_NAME AND INDSEG.RDB$INDEX_NAME EQ IND.RDB$INDEX_NAME AND INDSEG.RDB$FIELD_NAME EQ RFL.RDB$FIELD_NAME AND + RELCON.RDB$SCHEMA_NAME EQ INDSEG.RDB$SCHEMA_NAME AND RELCON.RDB$INDEX_NAME EQ INDSEG.RDB$INDEX_NAME AND RELCON.RDB$CONSTRAINT_TYPE EQ PRIMARY_KEY { status_exception::raise( Arg::Gds(isc_domain_primary_key_notnull) << - MetaName(RFL.RDB$RELATION_NAME)); + QualifiedName(RFL.RDB$RELATION_NAME, RFL.RDB$SCHEMA_NAME).toQuotedString()); } END_FOR } @@ -5208,12 +5388,13 @@ void AlterDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) RFR IN RDB$RELATION_FIELDS - WITH RFR.RDB$FIELD_SOURCE = FLD.RDB$FIELD_NAME AND + WITH RFR.RDB$FIELD_SOURCE_SCHEMA_NAME = FLD.RDB$SCHEMA_NAME AND + RFR.RDB$FIELD_SOURCE = FLD.RDB$FIELD_NAME AND RFR.RDB$GENERATOR_NAME NOT MISSING { // Domain @1 must be of exact number type with zero scale because it's used // in an identity column. - status_exception::raise(Arg::PrivateDyn(276) << name); + status_exception::raise(Arg::PrivateDyn(276) << name.toQuotedString()); } END_FOR } @@ -5224,9 +5405,11 @@ void AlterDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) DOM IN RDB$RELATION_FIELDS - WITH DOM.RDB$FIELD_SOURCE EQ name.c_str() + WITH DOM.RDB$FIELD_SOURCE_SCHEMA_NAME = name.schema.c_str() AND + DOM.RDB$FIELD_SOURCE EQ name.object.c_str() { - modifyLocalFieldIndex(tdbb, transaction, DOM.RDB$RELATION_NAME, + modifyLocalFieldIndex(tdbb, transaction, + QualifiedName(DOM.RDB$RELATION_NAME, DOM.RDB$SCHEMA_NAME), DOM.RDB$FIELD_NAME, DOM.RDB$FIELD_NAME); } END_FOR @@ -5269,8 +5452,8 @@ void AlterDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, } executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_DOMAIN, - (renameTo.hasData() ? renameTo : name), - (renameTo.hasData() ? name : NULL)); + (renameTo.hasData() ? qualifiedRenameTo : name), + (renameTo.hasData() ? name : QualifiedName())); savePoint.release(); // everything is ok } @@ -5282,10 +5465,12 @@ void AlterDomainNode::rename(thread_db* tdbb, jrd_tra* transaction, SSHORT dimen AutoRequest request; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - FLD IN RDB$FIELDS WITH FLD.RDB$FIELD_NAME EQ renameTo.c_str() + FLD IN RDB$FIELDS + WITH FLD.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + FLD.RDB$FIELD_NAME EQ renameTo.c_str() { // msg 204: Cannot rename domain %s to %s. A domain with that name already exists. - status_exception::raise(Arg::PrivateDyn(204) << name << renameTo); + status_exception::raise(Arg::PrivateDyn(204) << name.toQuotedString() << renameTo); } END_FOR @@ -5296,7 +5481,8 @@ void AlterDomainNode::rename(thread_db* tdbb, jrd_tra* transaction, SSHORT dimen FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) FDIM IN RDB$FIELD_DIMENSIONS - WITH FDIM.RDB$FIELD_NAME EQ name.c_str() + WITH FDIM.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + FDIM.RDB$FIELD_NAME EQ name.object.c_str() { MODIFY FDIM USING strcpy(FDIM.RDB$FIELD_NAME, renameTo.c_str()); @@ -5309,13 +5495,15 @@ void AlterDomainNode::rename(thread_db* tdbb, jrd_tra* transaction, SSHORT dimen FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RFLD IN RDB$RELATION_FIELDS - WITH RFLD.RDB$FIELD_SOURCE EQ name.c_str() + WITH RFLD.RDB$FIELD_SOURCE_SCHEMA_NAME EQ name.schema.c_str() AND + RFLD.RDB$FIELD_SOURCE EQ name.object.c_str() { MODIFY RFLD USING strcpy(RFLD.RDB$FIELD_SOURCE, renameTo.c_str()); END_MODIFY - modifyLocalFieldIndex(tdbb, transaction, RFLD.RDB$RELATION_NAME, + modifyLocalFieldIndex(tdbb, transaction, + QualifiedName(RFLD.RDB$RELATION_NAME, RFLD.RDB$SCHEMA_NAME), RFLD.RDB$FIELD_NAME, RFLD.RDB$FIELD_NAME); } END_FOR @@ -5326,14 +5514,15 @@ void AlterDomainNode::rename(thread_db* tdbb, jrd_tra* transaction, SSHORT dimen // Delete the records in RDB$FIELD_DIMENSIONS pertaining to a field. -bool DropDomainNode::deleteDimensionRecords(thread_db* tdbb, jrd_tra* transaction, const MetaName& name) +bool DropDomainNode::deleteDimensionRecords(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& name) { AutoCacheRequest request(tdbb, drq_e_dims, DYN_REQUESTS); bool found = false; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$FIELD_DIMENSIONS - WITH X.RDB$FIELD_NAME EQ name.c_str() + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$FIELD_NAME EQ name.object.c_str() { found = true; ERASE X; @@ -5357,8 +5546,7 @@ void DropDomainNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) SCL_check_domain(tdbb, name, SCL_drop); } -void DropDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - jrd_tra* transaction) +void DropDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); @@ -5368,10 +5556,10 @@ void DropDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$FIELDS - WITH X.RDB$FIELD_NAME EQ name.c_str() + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$FIELD_NAME EQ name.object.c_str() { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_DROP_DOMAIN, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_DOMAIN, name, {}); check(tdbb, transaction); deleteDimensionRecords(tdbb, transaction, name); @@ -5388,10 +5576,7 @@ void DropDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, deletePrivilegesByRelName(tdbb, transaction, name, obj_field); if (found) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_DOMAIN, - name, NULL); - } + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_DOMAIN, name, {}); else if (!silent) { // msg 89: "Domain not found" @@ -5407,15 +5592,16 @@ void DropDomainNode::check(thread_db* tdbb, jrd_tra* transaction) FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) Y IN RDB$RELATION_FIELDS - WITH Y.RDB$FIELD_SOURCE EQ name.c_str() + WITH Y.RDB$FIELD_SOURCE_SCHEMA_NAME EQ name.schema.c_str() AND + Y.RDB$FIELD_SOURCE EQ name.object.c_str() { - fb_utils::exact_name_limit(Y.RDB$FIELD_SOURCE, sizeof(Y.RDB$FIELD_SOURCE)); - fb_utils::exact_name_limit(Y.RDB$RELATION_NAME, sizeof(Y.RDB$RELATION_NAME)); fb_utils::exact_name_limit(Y.RDB$FIELD_NAME, sizeof(Y.RDB$FIELD_NAME)); // msg 43: "Domain %s is used in table %s (local name %s) and can not be dropped" status_exception::raise( - Arg::PrivateDyn(43) << Y.RDB$FIELD_SOURCE << Y.RDB$RELATION_NAME << Y.RDB$FIELD_NAME); + Arg::PrivateDyn(43) << name.toQuotedString() << + QualifiedName(Y.RDB$RELATION_NAME, Y.RDB$SCHEMA_NAME).toQuotedString() << + MetaName(Y.RDB$FIELD_NAME).toQuotedString()); } END_FOR @@ -5423,18 +5609,17 @@ void DropDomainNode::check(thread_db* tdbb, jrd_tra* transaction) FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$PROCEDURE_PARAMETERS - WITH X.RDB$FIELD_SOURCE EQ name.c_str() + WITH X.RDB$FIELD_SOURCE_SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$FIELD_SOURCE EQ name.object.c_str() { - fb_utils::exact_name_limit(X.RDB$FIELD_SOURCE, sizeof(X.RDB$FIELD_SOURCE)); - fb_utils::exact_name_limit(X.RDB$PROCEDURE_NAME, sizeof(X.RDB$PROCEDURE_NAME)); fb_utils::exact_name_limit(X.RDB$PARAMETER_NAME, sizeof(X.RDB$PARAMETER_NAME)); // msg 239: "Domain %s is used in procedure %s (parameter name %s) and cannot be dropped" status_exception::raise( - Arg::PrivateDyn(239) << X.RDB$FIELD_SOURCE << - QualifiedName(X.RDB$PROCEDURE_NAME, - (X.RDB$PACKAGE_NAME.NULL ? NULL : X.RDB$PACKAGE_NAME)).toString().c_str() << - X.RDB$PARAMETER_NAME); + Arg::PrivateDyn(239) << name.toQuotedString() << + QualifiedName(X.RDB$PROCEDURE_NAME, X.RDB$SCHEMA_NAME, + (X.RDB$PACKAGE_NAME.NULL ? NULL : X.RDB$PACKAGE_NAME)).toQuotedString() << + MetaName(X.RDB$PARAMETER_NAME).toQuotedString()); } END_FOR @@ -5442,18 +5627,17 @@ void DropDomainNode::check(thread_db* tdbb, jrd_tra* transaction) FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$FUNCTION_ARGUMENTS - WITH X.RDB$FIELD_SOURCE EQ name.c_str() + WITH X.RDB$FIELD_SOURCE_SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$FIELD_SOURCE EQ name.object.c_str() { - fb_utils::exact_name_limit(X.RDB$FIELD_SOURCE, sizeof(X.RDB$FIELD_SOURCE)); - fb_utils::exact_name_limit(X.RDB$FUNCTION_NAME, sizeof(X.RDB$FUNCTION_NAME)); fb_utils::exact_name_limit(X.RDB$ARGUMENT_NAME, sizeof(X.RDB$ARGUMENT_NAME)); // msg 239: "Domain %s is used in function %s (parameter name %s) and cannot be dropped" status_exception::raise( - Arg::Gds(isc_dyn_domain_used_function) << X.RDB$FIELD_SOURCE << - QualifiedName(X.RDB$FUNCTION_NAME, - (X.RDB$PACKAGE_NAME.NULL ? NULL : X.RDB$PACKAGE_NAME)).toString().c_str() << - X.RDB$ARGUMENT_NAME); + Arg::Gds(isc_dyn_domain_used_function) << name.toQuotedString() << + QualifiedName(X.RDB$FUNCTION_NAME, X.RDB$SCHEMA_NAME, + (X.RDB$PACKAGE_NAME.NULL ? NULL : X.RDB$PACKAGE_NAME)).toQuotedString() << + MetaName(X.RDB$ARGUMENT_NAME).toQuotedString()); } END_FOR } @@ -5482,11 +5666,10 @@ void CreateAlterExceptionNode::checkPermission(thread_db* tdbb, jrd_tra* transac return; } - SCL_check_create_access(tdbb, obj_exceptions); + SCL_check_create_access(tdbb, obj_exceptions, name.schema); } -void CreateAlterExceptionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - jrd_tra* transaction) +void CreateAlterExceptionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { fb_assert(create || alter); @@ -5515,8 +5698,7 @@ void CreateAlterExceptionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsq savePoint.release(); // everything is ok } -void CreateAlterExceptionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - jrd_tra* transaction) +void CreateAlterExceptionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { Attachment* const attachment = transaction->getAttachment(); const MetaString& ownerName = attachment->getEffectiveUserName(); @@ -5524,8 +5706,7 @@ void CreateAlterExceptionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_exception)) return; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_CREATE_EXCEPTION, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_EXCEPTION, name, {}); DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_exception); @@ -5547,7 +5728,9 @@ void CreateAlterExceptionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc { X.RDB$EXCEPTION_NUMBER = id; X.RDB$SYSTEM_FLAG = 0; - strcpy(X.RDB$EXCEPTION_NAME, name.c_str()); + + strcpy(X.RDB$SCHEMA_NAME, name.schema.c_str()); + strcpy(X.RDB$EXCEPTION_NAME, name.object.c_str()); X.RDB$OWNER_NAME.NULL = FALSE; strcpy(X.RDB$OWNER_NAME, ownerName.c_str()); @@ -5572,8 +5755,7 @@ void CreateAlterExceptionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc storePrivileges(tdbb, transaction, name, obj_exception, USAGE_PRIVILEGES); - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_EXCEPTION, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_EXCEPTION, name, {}); } bool CreateAlterExceptionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, @@ -5584,10 +5766,10 @@ bool CreateAlterExceptionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$EXCEPTIONS - WITH X.RDB$EXCEPTION_NAME EQ name.c_str() + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$EXCEPTION_NAME EQ name.object.c_str() { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_ALTER_EXCEPTION, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_EXCEPTION, name, {}); MODIFY X strcpy(X.RDB$MESSAGE, message.c_str()); @@ -5598,10 +5780,7 @@ bool CreateAlterExceptionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch END_FOR if (modified) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_EXCEPTION, - name, NULL); - } + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_EXCEPTION, name, {}); return modified; } @@ -5636,10 +5815,10 @@ void DropExceptionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$EXCEPTIONS - WITH X.RDB$EXCEPTION_NAME EQ name.c_str() + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$EXCEPTION_NAME EQ name.object.c_str() { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_DROP_EXCEPTION, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_EXCEPTION, name, {}); ERASE X; if (!X.RDB$SECURITY_CLASS.NULL) @@ -5652,10 +5831,7 @@ void DropExceptionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc deletePrivilegesByRelName(tdbb, transaction, name, obj_exception); if (found) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_EXCEPTION, - name, NULL); - } + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_EXCEPTION, name, {}); else if (!silent) { // msg 144: "Exception not found" @@ -5692,7 +5868,7 @@ void CreateAlterSequenceNode::checkPermission(thread_db* tdbb, jrd_tra* transact return; } - SCL_check_create_access(tdbb, obj_generators); + SCL_check_create_access(tdbb, obj_generators, name.schema); } void CreateAlterSequenceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, @@ -5712,7 +5888,7 @@ void CreateAlterSequenceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsql else { // msg 214: "Sequence not found" - status_exception::raise(Arg::PrivateDyn(214) << name); + status_exception::raise(Arg::PrivateDyn(214) << name.toQuotedString()); } } } @@ -5745,7 +5921,7 @@ void CreateAlterSequenceNode::putErrorPrefix(Firebird::Arg::StatusVector& status else rc = isc_dsql_create_sequence_failed; } - statusVector << Firebird::Arg::Gds(rc) << name; + statusVector << Firebird::Arg::Gds(rc) << name.toQuotedString(); } void CreateAlterSequenceNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, @@ -5754,8 +5930,7 @@ void CreateAlterSequenceNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_generator)) return; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_SEQUENCE, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_SEQUENCE, name, {}); DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_generator); @@ -5765,13 +5940,12 @@ void CreateAlterSequenceNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch { initialStep = step.value(); if (initialStep == 0) - status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_increment) << Arg::Str(name)); + status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_increment) << name.toQuotedString()); } store(tdbb, transaction, name, fb_sysflag_user, val, initialStep); - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_SEQUENCE, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_SEQUENCE, name, {}); } bool CreateAlterSequenceNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, @@ -5793,10 +5967,9 @@ bool CreateAlterSequenceNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* return false; if (forbidden && !tdbb->getAttachment()->isRWGbak()) - status_exception::raise(Arg::Gds(isc_dyn_cant_modify_sysobj) << "generator" << Arg::Str(name)); + status_exception::raise(Arg::Gds(isc_dyn_cant_modify_sysobj) << "generator" << name.toQuotedString()); - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_SEQUENCE, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_SEQUENCE, name, {}); fb_assert(restartSpecified && value.has_value()); const SINT64 val = value.value_or(0); @@ -5804,7 +5977,7 @@ bool CreateAlterSequenceNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* { const SLONG newStep = step.value(); if (newStep == 0) - status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_increment) << Arg::Str(name)); + status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_increment) << name.toQuotedString()); // Perhaps it's better to move this to DFW? if (newStep != oldStep) @@ -5812,12 +5985,13 @@ bool CreateAlterSequenceNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* } transaction->getGenIdCache()->put(id, val); - dsc desc; - desc.makeText((USHORT) name.length(), ttype_metadata, (UCHAR*) name.c_str()); - DFW_post_work(transaction, dfw_set_generator, &desc, id); - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_SEQUENCE, - name, NULL); + dsc schemaDesc, nameDesc; + schemaDesc.makeText((USHORT) name.schema.length(), ttype_metadata, (UCHAR*) name.schema.c_str()); + nameDesc.makeText((USHORT) name.object.length(), ttype_metadata, (UCHAR*) name.object.c_str()); + DFW_post_work(transaction, dfw_set_generator, &nameDesc, &schemaDesc, id); + + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_SEQUENCE, name, {}); return true; } @@ -5828,10 +6002,10 @@ bool CreateAlterSequenceNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$GENERATORS - WITH X.RDB$GENERATOR_NAME EQ name.c_str() + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$GENERATOR_NAME EQ name.object.c_str() { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_SEQUENCE, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_SEQUENCE, name, {}); if (X.RDB$SYSTEM_FLAG == fb_sysflag_system) { @@ -5845,7 +6019,7 @@ bool CreateAlterSequenceNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* { const SLONG newStep = step.value(); if (newStep == 0) - status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_increment) << Arg::Str(name)); + status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_increment) << name.toQuotedString()); if (newStep != X.RDB$GENERATOR_INCREMENT) { @@ -5864,24 +6038,24 @@ bool CreateAlterSequenceNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* newValue - (!X.RDB$GENERATOR_INCREMENT.NULL ? X.RDB$GENERATOR_INCREMENT : 1)); } - dsc desc; - desc.makeText((USHORT) name.length(), ttype_metadata, (UCHAR*) name.c_str()); - DFW_post_work(transaction, dfw_set_generator, &desc, id); + dsc schemaDesc, nameDesc; + schemaDesc.makeText((USHORT) name.schema.length(), ttype_metadata, (UCHAR*) name.schema.c_str()); + nameDesc.makeText((USHORT) name.object.length(), ttype_metadata, (UCHAR*) name.object.c_str()); + DFW_post_work(transaction, dfw_set_generator, &nameDesc, &schemaDesc, id); - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_SEQUENCE, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_SEQUENCE, name, {}); found = true; } END_FOR if (forbidden) - status_exception::raise(Arg::Gds(isc_dyn_cant_modify_sysobj) << "generator" << Arg::Str(name)); + status_exception::raise(Arg::Gds(isc_dyn_cant_modify_sysobj) << "generator" << name.toQuotedString()); return found; } -SSHORT CreateAlterSequenceNode::store(thread_db* tdbb, jrd_tra* transaction, const MetaName& name, +SSHORT CreateAlterSequenceNode::store(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& name, fb_sysflag sysFlag, SINT64 val, SLONG step) { Attachment* const attachment = transaction->tra_attachment; @@ -5908,7 +6082,9 @@ SSHORT CreateAlterSequenceNode::store(thread_db* tdbb, jrd_tra* transaction, con { X.RDB$GENERATOR_ID = id; X.RDB$SYSTEM_FLAG = (SSHORT) sysFlag; - strcpy(X.RDB$GENERATOR_NAME, name.c_str()); + + strcpy(X.RDB$SCHEMA_NAME, name.schema.c_str()); + strcpy(X.RDB$GENERATOR_NAME, name.object.c_str()); X.RDB$OWNER_NAME.NULL = FALSE; strcpy(X.RDB$OWNER_NAME, ownerName.c_str()); @@ -5973,16 +6149,16 @@ void DropSequenceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) GEN IN RDB$GENERATORS - WITH GEN.RDB$GENERATOR_NAME EQ name.c_str() + WITH GEN.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + GEN.RDB$GENERATOR_NAME EQ name.object.c_str() { if (GEN.RDB$SYSTEM_FLAG != 0) { // msg 272: "Cannot delete system generator @1" - status_exception::raise(Arg::PrivateDyn(272) << name); + status_exception::raise(Arg::PrivateDyn(272) << name.toQuotedString()); } - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_DROP_SEQUENCE, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_SEQUENCE, name, {}); ERASE GEN; @@ -5996,25 +6172,23 @@ void DropSequenceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch deletePrivilegesByRelName(tdbb, transaction, name, obj_generator); if (found) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_SEQUENCE, - name, NULL); - } + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_SEQUENCE, name, {}); else if (!silent) - status_exception::raise(Arg::Gds(isc_gennotdef) << Arg::Str(name)); + status_exception::raise(Arg::Gds(isc_gennotdef) << name.toQuotedString()); savePoint.release(); // everything is ok } // Delete a record from RDB$GENERATORS, without verifying RDB$SYSTEM_FLAG. -void DropSequenceNode::deleteIdentity(thread_db* tdbb, jrd_tra* transaction, const MetaName& name) +void DropSequenceNode::deleteIdentity(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& name) { AutoCacheRequest request(tdbb, drq_e_ident_gens, DYN_REQUESTS); FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) GEN IN RDB$GENERATORS - WITH GEN.RDB$GENERATOR_NAME EQ name.c_str() + WITH GEN.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + GEN.RDB$GENERATOR_NAME EQ name.object.c_str() { ERASE GEN; @@ -6044,13 +6218,15 @@ void RelationNode::FieldDefinition::modify(thread_db* tdbb, jrd_tra* transaction FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RFR IN RDB$RELATION_FIELDS - WITH RFR.RDB$RELATION_NAME EQ relationName.c_str() AND + WITH RFR.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + RFR.RDB$RELATION_NAME EQ relationName.object.c_str() AND RFR.RDB$FIELD_NAME EQ name.c_str() { // ASF: This is prepared only to modify view fields! MODIFY RFR - strcpy(RFR.RDB$FIELD_SOURCE, fieldSource.c_str()); + strcpy(RFR.RDB$FIELD_SOURCE_SCHEMA_NAME, fieldSource.schema.c_str()); + strcpy(RFR.RDB$FIELD_SOURCE, fieldSource.object.c_str()); RFR.RDB$COLLATION_ID.NULL = TRUE; RFR.RDB$GENERATOR_NAME.NULL = TRUE; @@ -6101,7 +6277,7 @@ void RelationNode::FieldDefinition::modify(thread_db* tdbb, jrd_tra* transaction RFR.RDB$VIEW_CONTEXT = viewContext.value(); DYN_UTIL_find_field_source(tdbb, transaction, relationName, viewContext.value(), - baseField.c_str(), RFR.RDB$FIELD_SOURCE); + baseField.c_str(), RFR.RDB$FIELD_SOURCE_SCHEMA_NAME, RFR.RDB$FIELD_SOURCE); } END_MODIFY } @@ -6118,8 +6294,10 @@ void RelationNode::FieldDefinition::store(thread_db* tdbb, jrd_tra* transaction) RFR IN RDB$RELATION_FIELDS { strcpy(RFR.RDB$FIELD_NAME, name.c_str()); - strcpy(RFR.RDB$RELATION_NAME, relationName.c_str()); - strcpy(RFR.RDB$FIELD_SOURCE, fieldSource.c_str()); + strcpy(RFR.RDB$SCHEMA_NAME, relationName.schema.c_str()); + strcpy(RFR.RDB$RELATION_NAME, relationName.object.c_str()); + strcpy(RFR.RDB$FIELD_SOURCE_SCHEMA_NAME, fieldSource.schema.c_str()); + strcpy(RFR.RDB$FIELD_SOURCE, fieldSource.object.c_str()); RFR.RDB$SYSTEM_FLAG = 0; RFR.RDB$COLLATION_ID.NULL = TRUE; @@ -6140,10 +6318,10 @@ void RelationNode::FieldDefinition::store(thread_db* tdbb, jrd_tra* transaction) RFR.RDB$COLLATION_ID = collationId.value(); } - if (identitySequence.hasData()) + if (identitySequence.object.hasData()) { RFR.RDB$GENERATOR_NAME.NULL = FALSE; - strcpy(RFR.RDB$GENERATOR_NAME, identitySequence.c_str()); + strcpy(RFR.RDB$GENERATOR_NAME, identitySequence.object.c_str()); RFR.RDB$IDENTITY_TYPE.NULL = FALSE; RFR.RDB$IDENTITY_TYPE = identityType.value(); @@ -6199,12 +6377,73 @@ void RelationNode::FieldDefinition::store(thread_db* tdbb, jrd_tra* transaction) RFR.RDB$VIEW_CONTEXT = viewContext.value(); DYN_UTIL_find_field_source(tdbb, transaction, relationName, viewContext.value(), - baseField.c_str(), RFR.RDB$FIELD_SOURCE); + baseField.c_str(), RFR.RDB$FIELD_SOURCE_SCHEMA_NAME, RFR.RDB$FIELD_SOURCE); } } END_STORE } +DdlNode* RelationNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) +{ + const auto processAddConstraint = [&dsqlScratch](AddConstraintClause* const constraintClause) + { + if (constraintClause->refRelation.object.hasData()) + dsqlScratch->qualifyExistingName(constraintClause->refRelation, obj_relation); + }; + + for (auto clause : clauses) + { + switch (clause->type) + { + case Clause::TYPE_ADD_CONSTRAINT: + { + const auto constraintClause = static_cast(clause.getObject()); + processAddConstraint(constraintClause); + break; + } + + case Clause::TYPE_ADD_COLUMN: + { + const auto addColumnClause = static_cast(clause.getObject()); + + dsqlScratch->qualifyExistingName(addColumnClause->field->typeOfTable, obj_relation); + dsqlScratch->qualifyExistingName(addColumnClause->field->typeOfName, obj_field); + dsqlScratch->qualifyExistingName(addColumnClause->field->charSet, obj_charset); + dsqlScratch->qualifyExistingName(addColumnClause->field->collate, obj_collation); + + for (auto& constraintClause : addColumnClause->constraints) + processAddConstraint(&constraintClause); + + break; + } + + case Clause::TYPE_ALTER_COL_TYPE: + { + const auto alterColTypeClause = static_cast(clause.getObject()); + dsqlScratch->qualifyExistingName(alterColTypeClause->field->typeOfName, obj_field); + dsqlScratch->qualifyExistingName(alterColTypeClause->field->charSet, obj_field); + dsqlScratch->qualifyExistingName(alterColTypeClause->field->collate, obj_field); + break; + } + + case Clause::TYPE_ALTER_COL_NAME: + case Clause::TYPE_ALTER_COL_NULL: + case Clause::TYPE_ALTER_COL_POS: + case Clause::TYPE_DROP_COLUMN: + case Clause::TYPE_DROP_CONSTRAINT: + case Clause::TYPE_ALTER_SQL_SECURITY: + case Clause::TYPE_ALTER_PUBLICATION: + break; + + default: + fb_assert(false); + break; + } + } + + return DdlNode::dsqlPass(dsqlScratch); +} + // Delete local field. // // The rules for dropping a regular column: @@ -6231,7 +6470,8 @@ void RelationNode::FieldDefinition::store(thread_db* tdbb, jrd_tra* transaction) // done by code and system triggers. See the functional description of // deleteKeyConstraint function for detail. bool RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction, - const MetaName& relationName, const MetaName& fieldName, bool silent, std::function preChangeHandler) + const QualifiedName& relationName, const MetaName& fieldName, bool silent, + std::function preChangeHandler) { bool preChangeHandlerWasExecuted = false; @@ -6253,11 +6493,15 @@ bool RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction, X IN RDB$RELATION_FIELDS CROSS Y IN RDB$RELATION_FIELDS CROSS Z IN RDB$VIEW_RELATIONS - WITH X.RDB$RELATION_NAME EQ relationName.c_str() AND + WITH X.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + X.RDB$RELATION_NAME EQ relationName.object.c_str() AND X.RDB$FIELD_NAME EQ fieldName.c_str() AND X.RDB$FIELD_NAME EQ Y.RDB$BASE_FIELD AND + X.RDB$FIELD_SOURCE_SCHEMA_NAME EQ Y.RDB$FIELD_SOURCE_SCHEMA_NAME AND X.RDB$FIELD_SOURCE EQ Y.RDB$FIELD_SOURCE AND + Y.RDB$SCHEMA_NAME EQ Z.RDB$SCHEMA_NAME AND Y.RDB$RELATION_NAME EQ Z.RDB$VIEW_NAME AND + X.RDB$SCHEMA_NAME EQ Z.RDB$RELATION_SCHEMA_NAME AND X.RDB$RELATION_NAME EQ Z.RDB$RELATION_NAME AND Y.RDB$VIEW_CONTEXT EQ Z.RDB$VIEW_CONTEXT { @@ -6265,7 +6509,10 @@ bool RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction, // msg 52: "field %s from relation %s is referenced in view %s" status_exception::raise( - Arg::PrivateDyn(52) << fieldName << relationName << Y.RDB$RELATION_NAME); + Arg::PrivateDyn(52) << + fieldName << + relationName.toQuotedString() << + QualifiedName(Y.RDB$RELATION_NAME, Y.RDB$SCHEMA_NAME).toQuotedString()); } END_FOR @@ -6280,25 +6527,26 @@ bool RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction, IDX IN RDB$INDICES CROSS IDX_SEG IN RDB$INDEX_SEGMENTS CROSS REL_CONST IN RDB$RELATION_CONSTRAINTS - WITH IDX.RDB$RELATION_NAME EQ relationName.c_str() AND - REL_CONST.RDB$RELATION_NAME EQ relationName.c_str() AND + WITH IDX.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + IDX.RDB$RELATION_NAME EQ relationName.object.c_str() AND + REL_CONST.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + REL_CONST.RDB$RELATION_NAME EQ relationName.object.c_str() AND IDX_SEG.RDB$FIELD_NAME EQ fieldName.c_str() AND + IDX.RDB$SCHEMA_NAME EQ IDX_SEG.RDB$SCHEMA_NAME AND IDX.RDB$INDEX_NAME EQ IDX_SEG.RDB$INDEX_NAME AND + IDX.RDB$SCHEMA_NAME EQ REL_CONST.RDB$SCHEMA_NAME AND IDX.RDB$INDEX_NAME EQ REL_CONST.RDB$INDEX_NAME AND REL_CONST.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY { executePreChangeHandler(); if (IDX.RDB$SEGMENT_COUNT == 1) - { - deleteKeyConstraint(tdbb, transaction, relationName, - REL_CONST.RDB$CONSTRAINT_NAME, IDX.RDB$INDEX_NAME); - } + deleteKeyConstraint(tdbb, transaction, relationName, REL_CONST.RDB$CONSTRAINT_NAME, IDX.RDB$INDEX_NAME); else { // msg 187: "field %s from relation %s is referenced in index %s" status_exception::raise( - Arg::PrivateDyn(187) << fieldName << relationName << IDX.RDB$INDEX_NAME); + Arg::PrivateDyn(187) << fieldName << relationName.toQuotedString() << IDX.RDB$INDEX_NAME); } } END_FOR @@ -6314,11 +6562,14 @@ bool RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction, FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) IDX IN RDB$INDICES CROSS IDX_SEG IN RDB$INDEX_SEGMENTS - WITH IDX.RDB$INDEX_NAME EQ IDX_SEG.RDB$INDEX_NAME AND - IDX.RDB$RELATION_NAME EQ relationName.c_str() AND + WITH IDX.RDB$SCHEMA_NAME EQ IDX_SEG.RDB$SCHEMA_NAME AND + IDX.RDB$INDEX_NAME EQ IDX_SEG.RDB$INDEX_NAME AND + IDX.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + IDX.RDB$RELATION_NAME EQ relationName.object.c_str() AND IDX_SEG.RDB$FIELD_NAME EQ fieldName.c_str() AND NOT ANY REL_CONST IN RDB$RELATION_CONSTRAINTS - WITH REL_CONST.RDB$RELATION_NAME EQ IDX.RDB$RELATION_NAME AND + WITH REL_CONST.RDB$SCHEMA_NAME EQ IDX.RDB$SCHEMA_NAME AND + REL_CONST.RDB$RELATION_NAME EQ IDX.RDB$RELATION_NAME AND REL_CONST.RDB$INDEX_NAME EQ IDX.RDB$INDEX_NAME { executePreChangeHandler(); @@ -6326,7 +6577,7 @@ bool RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction, // msg 187: "field %s from relation %s is referenced in index %s" status_exception::raise( Arg::PrivateDyn(187) << - fieldName << relationName << + fieldName << relationName.toQuotedString() << fb_utils::exact_name_limit(IDX.RDB$INDEX_NAME, sizeof(IDX.RDB$INDEX_NAME))); } END_FOR @@ -6340,12 +6591,16 @@ bool RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction, FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RFR IN RDB$RELATION_FIELDS WITH RFR.RDB$FIELD_NAME EQ fieldName.c_str() AND - RFR.RDB$RELATION_NAME EQ relationName.c_str() + RFR.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + RFR.RDB$RELATION_NAME EQ relationName.object.c_str() { executePreChangeHandler(); if (!RFR.RDB$GENERATOR_NAME.NULL) - DropSequenceNode::deleteIdentity(tdbb, transaction, RFR.RDB$GENERATOR_NAME); + { + DropSequenceNode::deleteIdentity(tdbb, transaction, + QualifiedName(RFR.RDB$GENERATOR_NAME, RFR.RDB$SCHEMA_NAME)); + } ERASE RFR; @@ -6356,7 +6611,8 @@ bool RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction, } found = true; - DropRelationNode::deleteGlobalField(tdbb, transaction, RFR.RDB$FIELD_SOURCE); + DropRelationNode::deleteGlobalField(tdbb, transaction, + QualifiedName(RFR.RDB$FIELD_SOURCE, RFR.RDB$SCHEMA_NAME)); } END_FOR @@ -6364,7 +6620,8 @@ bool RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction, FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) PRIV IN RDB$USER_PRIVILEGES - WITH PRIV.RDB$RELATION_NAME EQ relationName.c_str() AND + WITH PRIV.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(relationName.schema.c_str(), '') AND + PRIV.RDB$RELATION_NAME EQ relationName.object.c_str() AND PRIV.RDB$FIELD_NAME EQ fieldName.c_str() AND PRIV.RDB$OBJECT_TYPE = obj_relation AND PRIV.RDB$GRANTOR NOT MISSING @@ -6378,7 +6635,7 @@ bool RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction, if (!found && !silent) { // msg 176: "column %s does not exist in table/view %s" - status_exception::raise(Arg::PrivateDyn(176) << fieldName << relationName); + status_exception::raise(Arg::PrivateDyn(176) << fieldName << relationName.toQuotedString()); } return found; @@ -6414,7 +6671,7 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch { FieldDefinition fieldDefinition(*tdbb->getDefaultPool()); - if (field->typeOfName.hasData()) + if (field->typeOfName.object.hasData()) { // Get the domain information. if (!METD_get_domain(transaction, field, field->typeOfName)) @@ -6423,7 +6680,7 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-607) << Arg::Gds(isc_dsql_command_err) << - Arg::Gds(isc_dsql_domain_not_found) << field->typeOfName); + Arg::Gds(isc_dsql_domain_not_found) << field->typeOfName.toQuotedString()); } fieldDefinition.fieldSource = field->typeOfName; @@ -6447,7 +6704,7 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch // Let's see if the field appears in a "primary_key (a, b, c)" relation constraint. for (FB_SIZE_T i = 0; !notNullFlag && i < pkCols->getCount(); ++i) { - if (field->fld_name == (*pkCols)[i].c_str()) + if (field->fld_name == (*pkCols)[i]) notNullFlag = true; } } @@ -6461,7 +6718,7 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch if (position >= 0) fieldDefinition.position = position; - if (field->typeOfName.isEmpty()) + if (field->typeOfName.object.isEmpty()) { string computedSource; BlrDebugWriter::BlrData computedValue; @@ -6477,13 +6734,17 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch field->resolve(dsqlScratch); // Generate a domain. + + if (fieldDefinition.fieldSource.schema.isEmpty()) + fieldDefinition.fieldSource.schema = name.schema; + storeGlobalField(tdbb, transaction, fieldDefinition.fieldSource, field, computedSource, computedValue); } else { // Resolve possible additional collation for domains. For plain types it is already resolved above. - if (field->collate.hasData()) + if (field->collate.object.hasData()) DDL_resolve_intl_type(dsqlScratch, field, field->collate); } @@ -6495,7 +6756,8 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-607) << Arg::Gds(isc_dsql_command_err) << - Arg::Gds(isc_dsql_type_not_supp_ext_tab) << typeName << name << field->fld_name); + Arg::Gds(isc_dsql_type_not_supp_ext_tab) << typeName << + name.toQuotedString() << field->fld_name.toQuotedString()); } if (clause->identityOptions) @@ -6504,7 +6766,7 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch { status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_inc_ident) << Arg::Str(field->fld_name) << - Arg::Str(name)); + name.toQuotedString()); } dsc desc; @@ -6513,9 +6775,10 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch if (!desc.isExact() || desc.dsc_scale != 0) { // Identity column @1 of table @2 must be exact numeric with zero scale. - status_exception::raise(Arg::PrivateDyn(273) << field->fld_name << name); + status_exception::raise(Arg::PrivateDyn(273) << field->fld_name << name.toQuotedString()); } + fieldDefinition.identitySequence.schema = fieldDefinition.relationName.schema; DYN_UTIL_generate_generator_name(tdbb, fieldDefinition.identitySequence); fieldDefinition.identityType = clause->identityOptions->type; @@ -6620,8 +6883,10 @@ void RelationNode::makeConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlScra Constraint::TYPE_PK : Constraint::TYPE_UNIQUE; constraint.name = clause->name; constraint.create->index = clause->index; + if (constraint.create->index && constraint.create->index->name.isEmpty()) constraint.create->index->name = constraint.name; + constraint.create->columns = clause->columns; break; } @@ -6677,6 +6942,7 @@ void RelationNode::makeConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlScra // Define the foreign key index and the triggers that may be needed // for referential integrity action. constraint.create->index = clause->index; + if (constraint.create->index && constraint.create->index->name.isEmpty()) constraint.create->index->name = constraint.name; @@ -6761,10 +7027,14 @@ void RelationNode::defineConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlSc jrd_tra* transaction, MetaName& constraintName, Constraint& constraint) { if (constraintName.isEmpty()) - DYN_UTIL_generate_constraint_name(tdbb, constraintName); + { + QualifiedName qualifiedConstraintName(constraintName, name.schema); + DYN_UTIL_generate_constraint_name(tdbb, qualifiedConstraintName); + constraintName = qualifiedConstraintName.object; + } AutoCacheRequest request(tdbb, drq_s_rel_con, DYN_REQUESTS); - MetaName referredIndexName; + QualifiedName referredIndexName; STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) CRT IN RDB$RELATION_CONSTRAINTS @@ -6772,7 +7042,8 @@ void RelationNode::defineConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlSc CRT.RDB$INDEX_NAME.NULL = TRUE; strcpy(CRT.RDB$CONSTRAINT_NAME, constraintName.c_str()); - strcpy(CRT.RDB$RELATION_NAME, name.c_str()); + strcpy(CRT.RDB$SCHEMA_NAME, name.schema.c_str()); + strcpy(CRT.RDB$RELATION_NAME, name.object.c_str()); switch (constraint.type) { @@ -6820,16 +7091,18 @@ void RelationNode::defineConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlSc definition.refRelation = constraint.refRelation; definition.refColumns = constraint.refColumns; - CreateIndexNode::store(tdbb, transaction, constraint.index->name, - definition, &referredIndexName); + QualifiedName qualifiedIndexName(constraint.index->name, name.schema); + CreateIndexNode::store(tdbb, transaction, qualifiedIndexName, definition, &referredIndexName); + constraint.index->name = qualifiedIndexName.object; CRT.RDB$INDEX_NAME.NULL = FALSE; strcpy(CRT.RDB$INDEX_NAME, constraint.index->name.c_str()); checkForeignKeyTempScope(tdbb, transaction, name, referredIndexName); - // Check that we have references permissions on the table and + // Check that we have references permissions on the schema, table and // fields that the index:referredIndexName is on. + SCL_check_schema(tdbb, referredIndexName.schema, SCL_usage); SCL_check_index(tdbb, referredIndexName, 0, SCL_references); break; @@ -6841,7 +7114,7 @@ void RelationNode::defineConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlSc if (constraint.type == Constraint::TYPE_NOT_NULL) { fb_assert(constraint.columns.getCount() == 1); - DYN_UTIL_store_check_constraints(tdbb, transaction, constraintName, + DYN_UTIL_store_check_constraints(tdbb, transaction, QualifiedName(constraintName, name.schema), *constraint.columns.begin()); } @@ -6852,7 +7125,8 @@ void RelationNode::defineConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlSc ++trigger) { trigger->store(tdbb, dsqlScratch, transaction); - DYN_UTIL_store_check_constraints(tdbb, transaction, constraintName, trigger->name); + DYN_UTIL_store_check_constraints(tdbb, transaction, QualifiedName(constraintName, name.schema), + trigger->name.object); } if (constraint.type == Constraint::TYPE_NOT_NULL || constraint.type == Constraint::TYPE_CHECK) @@ -6871,12 +7145,15 @@ void RelationNode::defineConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlSc IDS IN RDB$INDEX_SEGMENTS CROSS RFR IN RDB$RELATION_FIELDS CROSS FLX IN RDB$FIELDS - WITH IDS.RDB$INDEX_NAME EQ constraint.index->name.c_str() AND - RFR.RDB$RELATION_NAME EQ name.c_str() AND + WITH IDS.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + IDS.RDB$INDEX_NAME EQ constraint.index->name.c_str() AND + RFR.RDB$SCHEMA_NAME EQ IDS.RDB$SCHEMA_NAME AND + RFR.RDB$RELATION_NAME EQ name.object.c_str() AND RFR.RDB$FIELD_NAME EQ IDS.RDB$FIELD_NAME AND + FLX.RDB$SCHEMA_NAME EQUIV RFR.RDB$FIELD_SOURCE_SCHEMA_NAME AND FLX.RDB$FIELD_NAME EQ RFR.RDB$FIELD_SOURCE - REDUCED TO IDS.RDB$FIELD_NAME, IDS.RDB$INDEX_NAME, FLX.RDB$NULL_FLAG - SORTED BY ASCENDING IDS.RDB$FIELD_NAME + REDUCED TO RFR.RDB$SCHEMA_NAME, RFR.RDB$FIELD_NAME, IDS.RDB$INDEX_NAME, FLX.RDB$NULL_FLAG, RFR.RDB$NULL_FLAG + SORTED BY ASCENDING RFR.RDB$SCHEMA_NAME, RFR.RDB$FIELD_NAME { if ((FLX.RDB$NULL_FLAG.NULL || !FLX.RDB$NULL_FLAG) && (RFR.RDB$NULL_FLAG.NULL || !RFR.RDB$NULL_FLAG) && @@ -6884,11 +7161,12 @@ void RelationNode::defineConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlSc { // msg 123: "Field: %s not defined as NOT NULL - can't be used in PRIMARY KEY // constraint definition" - status_exception::raise(Arg::PrivateDyn(123) << MetaName(RFR.RDB$FIELD_NAME)); + status_exception::raise(Arg::PrivateDyn(123) << + QualifiedName(RFR.RDB$FIELD_NAME, RFR.RDB$SCHEMA_NAME).toQuotedString()); } ++uniqueCount; - fieldList.add() = IDS.RDB$FIELD_NAME; + fieldList.add() = RFR.RDB$FIELD_NAME; } END_FOR @@ -6896,7 +7174,8 @@ void RelationNode::defineConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlSc FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) IDS IN RDB$INDEX_SEGMENTS - WITH IDS.RDB$INDEX_NAME EQ constraint.index->name.c_str() + WITH IDS.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + IDS.RDB$INDEX_NAME EQ constraint.index->name.c_str() { ++allCount; } @@ -6919,12 +7198,16 @@ void RelationNode::defineConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlSc FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) CRT IN RDB$RELATION_CONSTRAINTS - WITH CRT.RDB$INDEX_NAME EQ referredIndexName.c_str() AND + WITH CRT.RDB$SCHEMA_NAME EQ referredIndexName.schema.c_str() AND + CRT.RDB$INDEX_NAME EQ referredIndexName.object.c_str() AND (CRT.RDB$CONSTRAINT_TYPE = PRIMARY_KEY OR CRT.RDB$CONSTRAINT_TYPE = UNIQUE_CNSTRT) { + fb_utils::exact_name_limit(CRT.RDB$SCHEMA_NAME, sizeof(CRT.RDB$SCHEMA_NAME)); + strcpy(REF.RDB$CONST_SCHEMA_NAME_UQ, CRT.RDB$SCHEMA_NAME); fb_utils::exact_name_limit(CRT.RDB$CONSTRAINT_NAME, sizeof(CRT.RDB$CONSTRAINT_NAME)); strcpy(REF.RDB$CONST_NAME_UQ, CRT.RDB$CONSTRAINT_NAME); + strcpy(REF.RDB$SCHEMA_NAME, name.schema.c_str()); strcpy(REF.RDB$CONSTRAINT_NAME, constraintName.c_str()); REF.RDB$UPDATE_RULE.NULL = FALSE; @@ -6944,20 +7227,21 @@ void RelationNode::defineConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlSc request.reset(tdbb, drq_c_dup_con, DYN_REQUESTS); - MetaName indexName; + QualifiedName indexName; int listIndex = -1; bool found = false; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) CRT IN RDB$RELATION_CONSTRAINTS CROSS - IDS IN RDB$INDEX_SEGMENTS OVER RDB$INDEX_NAME - WITH CRT.RDB$RELATION_NAME EQ name.c_str() AND + IDS IN RDB$INDEX_SEGMENTS OVER RDB$SCHEMA_NAME, RDB$INDEX_NAME + WITH CRT.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + CRT.RDB$RELATION_NAME EQ name.object.c_str() AND CRT.RDB$CONSTRAINT_NAME NE constraintName.c_str() AND (CRT.RDB$CONSTRAINT_TYPE EQ PRIMARY_KEY OR CRT.RDB$CONSTRAINT_TYPE EQ UNIQUE_CNSTRT) SORTED BY CRT.RDB$INDEX_NAME, DESCENDING IDS.RDB$FIELD_NAME { - if (indexName != CRT.RDB$INDEX_NAME) + if (indexName != QualifiedName(CRT.RDB$INDEX_NAME, CRT.RDB$SCHEMA_NAME)) { if (listIndex >= 0) found = false; @@ -6966,7 +7250,7 @@ void RelationNode::defineConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlSc break; listIndex = fieldList.getCount() - 1; - indexName = CRT.RDB$INDEX_NAME; + indexName = QualifiedName(CRT.RDB$INDEX_NAME, CRT.RDB$SCHEMA_NAME); found = true; } @@ -7018,7 +7302,7 @@ void RelationNode::defineCheckConstraintTrigger(DsqlCompilerScratch* dsqlScratch // Specify that the trigger should abort if the condition is not met. NestConst actionNode = FB_NEW_POOL(pool) CompoundStmtNode(pool); - ExceptionNode* exceptionNode = FB_NEW_POOL(pool) ExceptionNode(pool, CHECK_CONSTRAINT_EXCEPTION); + ExceptionNode* exceptionNode = FB_NEW_POOL(pool) ExceptionNode(pool, QualifiedName(CHECK_CONSTRAINT_EXCEPTION)); exceptionNode->exception->type = ExceptionItem::GDS_CODE; actionNode->statements.add(exceptionNode); @@ -7073,6 +7357,7 @@ void RelationNode::defineCheckConstraintTrigger(DsqlCompilerScratch* dsqlScratch TriggerDefinition& trigger = constraint.triggers.add(); trigger.systemFlag = fb_sysflag_check_constraint; trigger.relationName = name; + trigger.name.schema = name.schema; trigger.type = triggerType; trigger.source = clause->source; trigger.blrData = blrWriter.getBlrData(); @@ -7106,18 +7391,42 @@ void RelationNode::defineSetDefaultTrigger(DsqlCompilerScratch* dsqlScratch, blrWriter.appendUChar(blr_dcl_variable); blrWriter.appendUShort(index); - blrWriter.appendUChar(blr_column_name); - blrWriter.appendUChar(blr_domain_type_of); - blrWriter.appendNullString(0, name.c_str()); - blrWriter.appendNullString(0, column->c_str()); + if (constraint.refRelation.schema != name.schema) + { + blrWriter.appendUChar(blr_column_name3); + blrWriter.appendUChar(blr_domain_type_of); + blrWriter.appendMetaString(name.schema.c_str()); + blrWriter.appendMetaString(name.object.c_str()); + blrWriter.appendMetaString(column->c_str()); + blrWriter.appendUChar(0); + } + else + { + blrWriter.appendUChar(blr_column_name); + blrWriter.appendUChar(blr_domain_type_of); + blrWriter.appendMetaString(name.object.c_str()); + blrWriter.appendMetaString(column->c_str()); + } blrWriter.appendUChar(blr_dcl_variable); blrWriter.appendUShort(index + 1); - blrWriter.appendUChar(blr_column_name); - blrWriter.appendUChar(blr_domain_full); - blrWriter.appendNullString(0, name.c_str()); - blrWriter.appendNullString(0, column->c_str()); + if (constraint.refRelation.schema != name.schema) + { + blrWriter.appendUChar(blr_column_name3); + blrWriter.appendUChar(blr_domain_full); + blrWriter.appendMetaString(name.schema.c_str()); + blrWriter.appendMetaString(name.object.c_str()); + blrWriter.appendMetaString(column->c_str()); + blrWriter.appendUChar(0); + } + else + { + blrWriter.appendUChar(blr_column_name); + blrWriter.appendUChar(blr_domain_full); + blrWriter.appendMetaString(name.object.c_str()); + blrWriter.appendMetaString(column->c_str()); + } blrWriter.appendUChar(blr_assignment); blrWriter.appendUChar(blr_null); @@ -7164,7 +7473,7 @@ void RelationNode::defineSetDefaultTrigger(DsqlCompilerScratch* dsqlScratch, // The context for the foreign key relation. blrWriter.appendUChar(blr_field); blrWriter.appendUChar(2); - blrWriter.appendNullString(0, column->c_str()); + blrWriter.appendMetaString(column->c_str()); } blrWriter.appendUChar(blr_end); @@ -7180,6 +7489,7 @@ void RelationNode::defineSetDefaultTrigger(DsqlCompilerScratch* dsqlScratch, trigger.systemFlag = fb_sysflag_referential_constraint; trigger.fkTrigger = true; trigger.relationName = constraint.refRelation; + trigger.name.schema = constraint.refRelation.schema; trigger.type = (onUpdate ? POST_MODIFY_TRIGGER : POST_ERASE_TRIGGER); trigger.blrData = blrWriter.getBlrData(); } @@ -7221,6 +7531,7 @@ void RelationNode::defineSetNullTrigger(DsqlCompilerScratch* dsqlScratch, Constr trigger.systemFlag = fb_sysflag_referential_constraint; trigger.fkTrigger = true; trigger.relationName = constraint.refRelation; + trigger.name.schema = constraint.refRelation.schema; trigger.type = (onUpdate ? POST_MODIFY_TRIGGER : POST_ERASE_TRIGGER); trigger.blrData = blrWriter.getBlrData(); } @@ -7237,11 +7548,21 @@ void RelationNode::defineDeleteCascadeTrigger(DsqlCompilerScratch* dsqlScratch, blrWriter.appendUChar(blr_for); blrWriter.appendUChar(blr_rse); - - // The context for the prim. key relation. blrWriter.appendUChar(1); - blrWriter.appendUChar(blr_relation); - blrWriter.appendNullString(0, name.c_str()); + + if (constraint.refRelation.schema != name.schema) + { + blrWriter.appendUChar(blr_relation3); + blrWriter.appendMetaString(name.schema.c_str()); + blrWriter.appendMetaString(name.object.c_str()); + blrWriter.appendMetaString(""); + } + else + { + blrWriter.appendUChar(blr_relation); + blrWriter.appendMetaString(name.object.c_str()); + } + // The context for the foreign key relation. blrWriter.appendUChar(2); @@ -7257,6 +7578,7 @@ void RelationNode::defineDeleteCascadeTrigger(DsqlCompilerScratch* dsqlScratch, trigger.systemFlag = fb_sysflag_referential_constraint; trigger.fkTrigger = true; trigger.relationName = constraint.refRelation; + trigger.name.schema = constraint.refRelation.schema; trigger.type = POST_ERASE_TRIGGER; trigger.blrData = blrWriter.getBlrData(); } @@ -7296,6 +7618,7 @@ void RelationNode::defineUpdateCascadeTrigger(DsqlCompilerScratch* dsqlScratch, trigger.systemFlag = fb_sysflag_referential_constraint; trigger.fkTrigger = true; trigger.relationName = constraint.refRelation; + trigger.name.schema = constraint.refRelation.schema; trigger.type = POST_MODIFY_TRIGGER; trigger.blrData = blrWriter.getBlrData(); } @@ -7316,11 +7639,21 @@ void RelationNode::generateUnnamedTriggerBeginning(Constraint& constraint, bool blrWriter.appendUChar(blr_for); blrWriter.appendUChar(blr_rse); - - // The context for the prim. key relation. blrWriter.appendUChar(1); - blrWriter.appendUChar(blr_relation); - blrWriter.appendNullString(0, name.c_str()); + + if (constraint.refRelation.schema != name.schema) + { + blrWriter.appendUChar(blr_relation3); + blrWriter.appendMetaString(name.schema.c_str()); + blrWriter.appendMetaString(name.object.c_str()); + blrWriter.appendMetaString(""); + } + else + { + blrWriter.appendUChar(blr_relation); + blrWriter.appendMetaString(name.object.c_str()); + } + // The context for the foreign key relation. blrWriter.appendUChar(2); @@ -7408,7 +7741,7 @@ void RelationNode::stuffTriggerFiringCondition(const Constraint& constraint, Blr void RelationNode::addToPublication(thread_db* tdbb, jrd_tra* transaction, - const MetaName& tableName, + const QualifiedName& tableName, const MetaName& pubName) { AutoCacheRequest request(tdbb, drq_s_pub_tab, DYN_REQUESTS); @@ -7417,10 +7750,8 @@ void RelationNode::addToPublication(thread_db* tdbb, PTAB IN RDB$PUBLICATION_TABLES { strcpy(PTAB.RDB$PUBLICATION_NAME, pubName.c_str()); - PTAB.RDB$PUBLICATION_NAME.NULL = FALSE; - - strcpy(PTAB.RDB$TABLE_NAME, tableName.c_str()); - PTAB.RDB$TABLE_NAME.NULL = FALSE; + strcpy(PTAB.RDB$TABLE_SCHEMA_NAME, tableName.schema.c_str()); + strcpy(PTAB.RDB$TABLE_NAME, tableName.object.c_str()); } END_STORE } @@ -7428,15 +7759,16 @@ void RelationNode::addToPublication(thread_db* tdbb, void RelationNode::dropFromPublication(thread_db* tdbb, jrd_tra* transaction, - const MetaName& tableName, + const QualifiedName& tableName, const MetaName& pubName) { AutoCacheRequest request(tdbb, drq_e_pub_tab, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) PTAB IN RDB$PUBLICATION_TABLES - WITH PTAB.RDB$PUBLICATION_NAME EQ pubName.c_str() - AND PTAB.RDB$TABLE_NAME EQ tableName.c_str() + WITH PTAB.RDB$PUBLICATION_NAME EQ pubName.c_str() AND + PTAB.RDB$TABLE_SCHEMA_NAME EQ tableName.schema.c_str() AND + PTAB.RDB$TABLE_NAME EQ tableName.object.c_str() { ERASE PTAB; } @@ -7459,7 +7791,7 @@ string CreateRelationNode::internalPrint(NodePrinter& printer) const void CreateRelationNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - SCL_check_create_access(tdbb, obj_relations); + SCL_check_create_access(tdbb, obj_relations, name.schema); } void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, @@ -7479,8 +7811,7 @@ void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_TABLE, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_TABLE, name, {}); DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_relation); @@ -7493,7 +7824,8 @@ void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) REL IN RDB$RELATIONS { - strcpy(REL.RDB$RELATION_NAME, name.c_str()); + strcpy(REL.RDB$SCHEMA_NAME, name.schema.c_str()); + strcpy(REL.RDB$RELATION_NAME, name.object.c_str()); REL.RDB$SYSTEM_FLAG = 0; REL.RDB$FLAGS = REL_sql; REL.RDB$RELATION_TYPE = relationType.value(); @@ -7586,8 +7918,7 @@ void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat dsqlScratch->relation->rel_flags &= ~REL_creating; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_TABLE, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_TABLE, name, {}); savePoint.release(); // everything is ok @@ -7626,9 +7957,7 @@ string AlterRelationNode::internalPrint(NodePrinter& printer) const void AlterRelationNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - dsc dscName; - dscName.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str()); - SCL_check_relation(tdbb, &dscName, SCL_alter); + SCL_check_relation(tdbb, name, SCL_alter); } void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, @@ -7644,7 +7973,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-607) << Arg::Gds(isc_dsql_command_err) << - Arg::Gds(isc_dsql_table_not_found) << name); + Arg::Gds(isc_dsql_table_not_found) << name.toQuotedString()); } if (!dsqlScratch->relation) @@ -7658,7 +7987,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-204) << Arg::Gds(isc_dsql_relation_err) << - Arg::Gds(isc_random) << name /***<< + Arg::Gds(isc_random) << name.toQuotedString() /***<< Arg::Gds(isc_random) << linecol***/); } @@ -7669,7 +7998,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc if (!beforeTriggerWasExecuted) { beforeTriggerWasExecuted = true; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_TABLE, name, nullptr); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_TABLE, name, {}); } }; @@ -7697,7 +8026,8 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RFL IN RDB$RELATION_FIELDS - WITH RFL.RDB$RELATION_NAME = relation->rel_name.c_str() AND + WITH RFL.RDB$SCHEMA_NAME = relation->rel_name.schema.c_str() AND + RFL.RDB$RELATION_NAME = relation->rel_name.object.c_str() AND RFL.RDB$FIELD_NAME = addColumnClause->field->fld_name.c_str() { createColumn = false; @@ -7732,7 +8062,8 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RFL IN RDB$RELATION_FIELDS WITH RFL.RDB$FIELD_NAME EQ clause->fromName.c_str() AND - RFL.RDB$RELATION_NAME EQ name.c_str() + RFL.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + RFL.RDB$RELATION_NAME EQ name.object.c_str() { found = true; @@ -7751,7 +8082,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc // msg 205: Cannot rename field %s to %s. A field with that name // already exists in table %s. status_exception::raise( - Arg::PrivateDyn(205) << clause->fromName << clause->toName << name); + Arg::PrivateDyn(205) << clause->fromName << clause->toName << name.toQuotedString()); } END_MODIFY } @@ -7760,7 +8091,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc if (!found) { // msg 176: "column %s does not exist in table/view %s" - status_exception::raise(Arg::PrivateDyn(176) << clause->fromName << name); + status_exception::raise(Arg::PrivateDyn(176) << clause->fromName << name.toQuotedString()); } AutoRequest request2; @@ -7768,7 +8099,8 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) RCL IN RDB$RELATION_CONSTRAINTS CROSS CHK IN RDB$CHECK_CONSTRAINTS - WITH RCL.RDB$RELATION_NAME EQ name.c_str() AND + WITH RCL.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + RCL.RDB$RELATION_NAME EQ name.object.c_str() AND RCL.RDB$CONSTRAINT_TYPE EQ NOT_NULL_CNSTRT AND CHK.RDB$CONSTRAINT_NAME EQ RCL.RDB$CONSTRAINT_NAME AND CHK.RDB$TRIGGER_NAME EQ clause->fromName.c_str() @@ -7795,7 +8127,8 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RFL IN RDB$RELATION_FIELDS WITH RFL.RDB$FIELD_NAME EQ clause->name.c_str() AND - RFL.RDB$RELATION_NAME EQ name.c_str() + RFL.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + RFL.RDB$RELATION_NAME EQ name.object.c_str() { found = true; @@ -7804,7 +8137,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc if (!clause->notNullFlag && !RFL.RDB$GENERATOR_NAME.NULL) { // msg 274: Identity column @1 of table @2 cannot be changed to NULLable - status_exception::raise(Arg::PrivateDyn(274) << clause->name << name); + status_exception::raise(Arg::PrivateDyn(274) << clause->name << name.toQuotedString()); } if (clause->notNullFlag) @@ -7828,8 +8161,10 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) RCL IN RDB$RELATION_CONSTRAINTS CROSS CHK IN RDB$CHECK_CONSTRAINTS - WITH RCL.RDB$RELATION_NAME EQ name.c_str() AND + WITH RCL.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + RCL.RDB$RELATION_NAME EQ name.object.c_str() AND RCL.RDB$CONSTRAINT_TYPE EQ NOT_NULL_CNSTRT AND + CHK.RDB$SCHEMA_NAME EQ RCL.RDB$SCHEMA_NAME AND CHK.RDB$CONSTRAINT_NAME EQ RCL.RDB$CONSTRAINT_NAME AND CHK.RDB$TRIGGER_NAME EQ clause->name.c_str() { @@ -7847,7 +8182,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc if (!found) { // msg 176: "column %s does not exist in table/view %s" - status_exception::raise(Arg::PrivateDyn(176) << clause->name << name); + status_exception::raise(Arg::PrivateDyn(176) << clause->name << name.toQuotedString()); } break; @@ -7911,7 +8246,8 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RC IN RDB$RELATION_CONSTRAINTS WITH RC.RDB$CONSTRAINT_NAME EQ constraintName.c_str() AND - RC.RDB$RELATION_NAME EQ name.c_str() + RC.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + RC.RDB$RELATION_NAME EQ name.object.c_str() { found = true; break; @@ -7944,7 +8280,8 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) REL IN RDB$RELATIONS - WITH REL.RDB$RELATION_NAME EQ name.c_str() + WITH REL.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + REL.RDB$RELATION_NAME EQ name.object.c_str() { MODIFY REL { @@ -8021,7 +8358,8 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RC IN RDB$RELATION_CONSTRAINTS WITH RC.RDB$CONSTRAINT_NAME EQ constraint->name.c_str() AND - RC.RDB$RELATION_NAME EQ name.c_str() + RC.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + RC.RDB$RELATION_NAME EQ name.object.c_str() { found = true; ERASE RC; @@ -8037,7 +8375,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc } if (beforeTriggerWasExecuted) - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_TABLE, name, nullptr); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_TABLE, name, {}); savePoint.release(); // everything is ok @@ -8116,10 +8454,13 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc RFR IN RDB$RELATION_FIELDS CROSS REL IN RDB$RELATIONS CROSS FLD IN RDB$FIELDS - WITH REL.RDB$RELATION_NAME = RFR.RDB$RELATION_NAME AND - FLD.RDB$FIELD_NAME = RFR.RDB$FIELD_SOURCE AND - RFR.RDB$RELATION_NAME = name.c_str() AND - RFR.RDB$FIELD_NAME = field->fld_name.c_str() + WITH RFR.RDB$SCHEMA_NAME = name.schema.c_str() AND + RFR.RDB$RELATION_NAME = name.object.c_str() AND + RFR.RDB$FIELD_NAME = field->fld_name.c_str() AND + REL.RDB$SCHEMA_NAME = RFR.RDB$SCHEMA_NAME AND + REL.RDB$RELATION_NAME = RFR.RDB$RELATION_NAME AND + FLD.RDB$SCHEMA_NAME EQUIV RFR.RDB$FIELD_SOURCE_SCHEMA_NAME AND + FLD.RDB$FIELD_NAME = RFR.RDB$FIELD_SOURCE { found = true; @@ -8137,7 +8478,7 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc FLD.RDB$FIELD_LENGTH, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$CHARACTER_SET_ID, FLD.RDB$COLLATION_ID); - origDom.dyn_fld_name = field->fld_name; + origDom.dyn_fld_name.object = field->fld_name; origDom.dyn_charbytelen = FLD.RDB$FIELD_LENGTH; origDom.dyn_dtype = FLD.RDB$FIELD_TYPE; origDom.dyn_precision = FLD.RDB$FIELD_PRECISION; @@ -8145,14 +8486,14 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc origDom.dyn_charlen = FLD.RDB$CHARACTER_LENGTH; origDom.dyn_collation = FLD.RDB$COLLATION_ID; origDom.dyn_null_flag = !FLD.RDB$NULL_FLAG.NULL && FLD.RDB$NULL_FLAG != 0; - origDom.dyn_fld_source = RFR.RDB$FIELD_SOURCE; + origDom.dyn_fld_source = QualifiedName(RFR.RDB$FIELD_SOURCE, RFR.RDB$FIELD_SOURCE_SCHEMA_NAME); // If the original field type is an array, force its blr type to blr_blob. const bool hasDimensions = FLD.RDB$DIMENSIONS != 0; if (hasDimensions) origDom.dyn_dtype = blr_blob; - const bool wasInternalDomain = fb_utils::implicit_domain(origDom.dyn_fld_source.c_str()) && + const bool wasInternalDomain = fb_utils::implicit_domain(origDom.dyn_fld_source.object.c_str()) && RFR.RDB$BASE_FIELD.NULL; string computedSource; BlrDebugWriter::BlrData computedValue; @@ -8171,7 +8512,7 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc if (!RFR.RDB$GENERATOR_NAME.NULL) { // msg 275: Identity column @1 of table @2 cannot have default value - status_exception::raise(Arg::PrivateDyn(275) << field->fld_name << name); + status_exception::raise(Arg::PrivateDyn(275) << field->fld_name << name.toQuotedString()); } if (hasDimensions) @@ -8216,7 +8557,8 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc // msg 230: "Local column %s default belongs to domain %s" status_exception::raise( Arg::PrivateDyn(230) << - field->fld_name << MetaName(FLD.RDB$FIELD_NAME)); + field->fld_name << + QualifiedName(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME).toQuotedString()); } } else @@ -8234,7 +8576,8 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc status_exception::raise(Arg::PrivateDyn(285) << field->fld_name); } - DropSequenceNode::deleteIdentity(tdbb, transaction, RFR.RDB$GENERATOR_NAME); + DropSequenceNode::deleteIdentity(tdbb, transaction, + QualifiedName(RFR.RDB$GENERATOR_NAME, name.schema)); MODIFY RFR RFR.RDB$GENERATOR_NAME.NULL = TRUE; @@ -8251,7 +8594,7 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc WITH GEN.RDB$GENERATOR_NAME EQ RFR.RDB$GENERATOR_NAME { const SLONG id = GEN.RDB$GENERATOR_ID; - const MetaName genName(RFR.RDB$GENERATOR_NAME); + const QualifiedName genName(RFR.RDB$GENERATOR_NAME, RFR.RDB$SCHEMA_NAME); if (clause->identityOptions->restart) { @@ -8277,17 +8620,17 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc { status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_inc_ident) << Arg::Str(field->fld_name) << - Arg::Str(name)); + name.toQuotedString()); } MET_update_generator_increment(tdbb, id, clause->identityOptions->increment.value()); } - dsc desc; - desc.makeText((USHORT) genName.length(), ttype_metadata, - (UCHAR*) genName.c_str()); - DFW_post_work(transaction, dfw_set_generator, &desc, id); + dsc schemaDesc, nameDesc; + schemaDesc.makeText((USHORT) genName.schema.length(), ttype_metadata, (UCHAR*) genName.schema.c_str()); + nameDesc.makeText((USHORT) genName.object.length(), ttype_metadata, (UCHAR*) genName.object.c_str()); + DFW_post_work(transaction, dfw_set_generator, &nameDesc, &schemaDesc, id); found = true; } @@ -8303,21 +8646,21 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc { // We have the type. Default and type/domain are exclusive for now. - MetaName newDomainName; + QualifiedName newDomainName; dyn_fld newDom; - if (field->typeOfName.hasData()) + if (field->typeOfName.object.hasData()) { // Case a1: Internal domain -> domain. // Case a2: Domain -> domain. newDomainName = field->typeOfName; - if (fb_utils::implicit_domain(newDomainName.c_str())) + if (fb_utils::implicit_domain(newDomainName.object.c_str())) { // msg 224: "Cannot use the internal domain %s as new type for field %s". status_exception::raise( - Arg::PrivateDyn(224) << newDomainName << field->fld_name); + Arg::PrivateDyn(224) << newDomainName.toQuotedString() << field->fld_name); } // Get the domain information. @@ -8327,10 +8670,11 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-607) << Arg::Gds(isc_dsql_command_err) << - Arg::Gds(isc_dsql_domain_not_found) << newDomainName); + Arg::Gds(isc_dsql_domain_not_found) << newDomainName.toQuotedString()); } - DDL_resolve_intl_type(dsqlScratch, field, NULL); + QualifiedName dummyCollationName; + DDL_resolve_intl_type(dsqlScratch, field, dummyCollationName); // If the original definition was a base field type, remove the // entries from RDB$FIELDS. @@ -8345,6 +8689,8 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc // Case b1: Internal domain -> internal domain. // Case b2: Domain -> internal domain. + newDomainName.schema = name.schema; + // If COMPUTED was specified but the type wasn't, we use the type of // the computed expression. if (clause->computed && field->dtype == dtype_unknown) @@ -8402,7 +8748,7 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc if (!clause->computed && !isView) { - if (newDomainName.hasData()) + if (newDomainName.object.hasData()) newDom.dyn_fld_source = newDomainName; AlterDomainNode::getDomainType(tdbb, transaction, newDom); @@ -8413,16 +8759,19 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc if (!newDom.dyn_dsc.isExact() || newDom.dyn_dsc.dsc_scale != 0) { // Identity column @1 of table @2 must be exact numeric with zero scale. - status_exception::raise(Arg::PrivateDyn(273) << field->fld_name << name); + status_exception::raise(Arg::PrivateDyn(273) << field->fld_name << name.toQuotedString()); } } } - if (newDomainName.hasData()) + if (newDomainName.object.hasData()) { MODIFY RFR USING + RFR.RDB$FIELD_SOURCE_SCHEMA_NAME.NULL = FALSE; + strcpy(RFR.RDB$FIELD_SOURCE_SCHEMA_NAME, newDomainName.schema.c_str()); + RFR.RDB$FIELD_SOURCE.NULL = FALSE; - strcpy(RFR.RDB$FIELD_SOURCE, newDomainName.c_str()); + strcpy(RFR.RDB$FIELD_SOURCE, newDomainName.object.c_str()); if (clause->computed) { @@ -8458,10 +8807,12 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) PRM IN RDB$PROCEDURE_PARAMETERS - WITH PRM.RDB$RELATION_NAME = name.c_str() AND + WITH PRM.RDB$SCHEMA_NAME = name.schema.c_str() AND + PRM.RDB$RELATION_NAME = name.object.c_str() AND PRM.RDB$FIELD_NAME = field->fld_name.c_str() { MODIFY PRM USING + strcpy(PRM.RDB$FIELD_SOURCE_SCHEMA_NAME, RFR.RDB$FIELD_SOURCE_SCHEMA_NAME); strcpy(PRM.RDB$FIELD_SOURCE, RFR.RDB$FIELD_SOURCE); END_MODIFY } @@ -8471,10 +8822,12 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) ARG IN RDB$FUNCTION_ARGUMENTS - WITH ARG.RDB$RELATION_NAME = name.c_str() AND + WITH ARG.RDB$SCHEMA_NAME = name.schema.c_str() AND + ARG.RDB$RELATION_NAME = name.object.c_str() AND ARG.RDB$FIELD_NAME = field->fld_name.c_str() { MODIFY ARG USING + strcpy(ARG.RDB$FIELD_SOURCE_SCHEMA_NAME, RFR.RDB$FIELD_SOURCE_SCHEMA_NAME); strcpy(ARG.RDB$FIELD_SOURCE, RFR.RDB$FIELD_SOURCE); END_MODIFY } @@ -8485,9 +8838,11 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) RFR2 IN RDB$RELATION_FIELDS CROSS VRL IN RDB$VIEW_RELATIONS - WITH VRL.RDB$RELATION_NAME EQ name.c_str() AND + WITH VRL.RDB$RELATION_SCHEMA_NAME EQ name.schema.c_str() AND + VRL.RDB$RELATION_NAME EQ name.object.c_str() AND VRL.RDB$PACKAGE_NAME MISSING AND VRL.RDB$CONTEXT_TYPE EQ VCT_TABLE AND + RFR2.RDB$SCHEMA_NAME EQ VRL.RDB$SCHEMA_NAME AND RFR2.RDB$RELATION_NAME EQ VRL.RDB$VIEW_NAME AND RFR2.RDB$VIEW_CONTEXT EQ VRL.RDB$VIEW_CONTEXT AND RFR2.RDB$BASE_FIELD = field->fld_name.c_str() @@ -8505,7 +8860,7 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc if (!found) { // msg 176: "column %s does not exist in table/view %s" - status_exception::raise(Arg::PrivateDyn(176) << field->fld_name << name); + status_exception::raise(Arg::PrivateDyn(176) << field->fld_name << name.toQuotedString()); } // Update any indices that exist. @@ -8527,22 +8882,26 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc // Delete a global field if it's not used in others objects. void DropRelationNode::deleteGlobalField(thread_db* tdbb, jrd_tra* transaction, - const MetaName& globalName) + const QualifiedName& globalName) { AutoCacheRequest request(tdbb, drq_e_l_gfld, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) FLD IN RDB$FIELDS - WITH FLD.RDB$FIELD_NAME EQ globalName.c_str() AND + WITH FLD.RDB$SCHEMA_NAME EQ globalName.schema.c_str() AND + FLD.RDB$FIELD_NAME EQ globalName.object.c_str() AND FLD.RDB$VALIDATION_SOURCE MISSING AND FLD.RDB$NULL_FLAG MISSING AND FLD.RDB$DEFAULT_SOURCE MISSING AND FLD.RDB$FIELD_NAME STARTING WITH IMPLICIT_DOMAIN_PREFIX AND (NOT ANY RFR IN RDB$RELATION_FIELDS WITH + RFR.RDB$FIELD_SOURCE_SCHEMA_NAME EQUIV FLD.RDB$SCHEMA_NAME AND RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME) AND (NOT ANY PRM IN RDB$PROCEDURE_PARAMETERS WITH + PRM.RDB$FIELD_SOURCE_SCHEMA_NAME EQUIV FLD.RDB$SCHEMA_NAME AND PRM.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME) AND (NOT ANY ARG IN RDB$FUNCTION_ARGUMENTS WITH + ARG.RDB$FIELD_SOURCE_SCHEMA_NAME EQUIV FLD.RDB$SCHEMA_NAME AND ARG.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME) { DropDomainNode::deleteDimensionRecords(tdbb, transaction, globalName); @@ -8564,12 +8923,10 @@ string DropRelationNode::internalPrint(NodePrinter& printer) const void DropRelationNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - dsc dscName; - dscName.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str()); if (view) - SCL_check_view(tdbb, &dscName, SCL_drop); + SCL_check_view(tdbb, name, SCL_drop); else - SCL_check_relation(tdbb, &dscName, SCL_drop); + SCL_check_relation(tdbb, name, SCL_drop); } void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, @@ -8592,7 +8949,7 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-607) << Arg::Gds(isc_dsql_command_err) << - Arg::Gds(isc_dsql_view_not_found) << name); + Arg::Gds(isc_dsql_view_not_found) << name.toQuotedString()); } } else @@ -8602,7 +8959,7 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-607) << Arg::Gds(isc_dsql_command_err) << - Arg::Gds(isc_dsql_table_not_found) << name); + Arg::Gds(isc_dsql_table_not_found) << name.toQuotedString()); } } @@ -8616,9 +8973,10 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) R IN RDB$RELATIONS - WITH R.RDB$RELATION_NAME EQ name.c_str() + WITH R.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + R.RDB$RELATION_NAME EQ name.object.c_str() { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, ddlTriggerAction, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, ddlTriggerAction, name, {}); found = true; } END_FOR @@ -8627,7 +8985,8 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) CRT IN RDB$RELATION_CONSTRAINTS - WITH CRT.RDB$RELATION_NAME EQ name.c_str() AND + WITH CRT.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + CRT.RDB$RELATION_NAME EQ name.object.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) @@ -8641,9 +9000,10 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) IDX IN RDB$INDICES - WITH IDX.RDB$RELATION_NAME EQ name.c_str() + WITH IDX.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + IDX.RDB$RELATION_NAME EQ name.object.c_str() { - DropIndexNode::deleteSegmentRecords(tdbb, transaction, IDX.RDB$INDEX_NAME); + DropIndexNode::deleteSegmentRecords(tdbb, transaction, QualifiedName(IDX.RDB$INDEX_NAME, name.schema)); ERASE IDX; } END_FOR @@ -8653,7 +9013,9 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch 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 + WITH T.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + T.RDB$RELATION_NAME EQ name.object.c_str() AND + TM.RDB$SCHEMA_NAME EQ T.RDB$SCHEMA_NAME AND TM.RDB$TRIGGER_NAME EQ T.RDB$TRIGGER_NAME { ERASE TM; @@ -8665,7 +9027,8 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) CRT IN RDB$RELATION_CONSTRAINTS - WITH CRT.RDB$RELATION_NAME EQ name.c_str() AND + WITH CRT.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + CRT.RDB$RELATION_NAME EQ name.object.c_str() AND (CRT.RDB$CONSTRAINT_TYPE EQ CHECK_CNSTRT OR CRT.RDB$CONSTRAINT_TYPE EQ NOT_NULL_CNSTRT) { @@ -8677,10 +9040,14 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RFR IN RDB$RELATION_FIELDS - WITH RFR.RDB$RELATION_NAME EQ name.c_str() + WITH RFR.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + RFR.RDB$RELATION_NAME EQ name.object.c_str() { if (!RFR.RDB$GENERATOR_NAME.NULL) - DropSequenceNode::deleteIdentity(tdbb, transaction, RFR.RDB$GENERATOR_NAME); + { + DropSequenceNode::deleteIdentity(tdbb, transaction, + QualifiedName(RFR.RDB$GENERATOR_NAME, name.schema)); + } ERASE RFR; @@ -8690,7 +9057,7 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch deleteSecurityClass(tdbb, transaction, RFR.RDB$SECURITY_CLASS); } - deleteGlobalField(tdbb, transaction, RFR.RDB$FIELD_SOURCE); + deleteGlobalField(tdbb, transaction, QualifiedName(RFR.RDB$FIELD_SOURCE, RFR.RDB$FIELD_SOURCE_SCHEMA_NAME)); } END_FOR @@ -8698,7 +9065,8 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) VR IN RDB$VIEW_RELATIONS - WITH VR.RDB$VIEW_NAME EQ name.c_str() + WITH VR.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + VR.RDB$VIEW_NAME EQ name.object.c_str() { ERASE VR; } @@ -8708,7 +9076,8 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) R IN RDB$RELATIONS - WITH R.RDB$RELATION_NAME EQ name.c_str() + WITH R.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + R.RDB$RELATION_NAME EQ name.object.c_str() { ERASE R; @@ -8728,24 +9097,26 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch // Triggers must be deleted after check constraints - MetaName triggerName; + QualifiedName 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() + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$RELATION_NAME EQ name.object.c_str() { - triggerName = X.RDB$TRIGGER_NAME; + triggerName = QualifiedName(X.RDB$TRIGGER_NAME, X.RDB$SCHEMA_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 + WITH PRIV.RDB$USER_SCHEMA_NAME EQ triggerName.schema.c_str() AND + PRIV.RDB$USER EQ triggerName.object.c_str() AND + PRIV.RDB$USER_TYPE = obj_trigger AND + PRIV.RDB$GRANTOR NOT MISSING { ERASE PRIV; } @@ -8759,7 +9130,8 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) PRIV IN RDB$USER_PRIVILEGES - WITH PRIV.RDB$USER EQ name.c_str() AND + WITH PRIV.RDB$USER_SCHEMA_NAME EQ name.schema.c_str() AND + PRIV.RDB$USER EQ name.object.c_str() AND PRIV.RDB$USER_TYPE = obj_view AND PRIV.RDB$GRANTOR NOT MISSING { @@ -8773,14 +9145,15 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) PTAB IN RDB$PUBLICATION_TABLES - WITH PTAB.RDB$TABLE_NAME EQ name.c_str() + WITH PTAB.RDB$TABLE_SCHEMA_NAME EQ name.schema.c_str() AND + PTAB.RDB$TABLE_NAME EQ name.object.c_str() { ERASE PTAB; } END_FOR if (found) - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, ddlTriggerAction, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, ddlTriggerAction, name, {}); else { // msg 61: "Relation not found" @@ -8789,7 +9162,7 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch savePoint.release(); // everything is ok - METD_drop_relation(transaction, name.c_str()); + METD_drop_relation(transaction, name); MET_dsql_cache_release(tdbb, SYM_relation, name); } @@ -8813,21 +9186,28 @@ string CreateAlterViewNode::internalPrint(NodePrinter& printer) const DdlNode* CreateAlterViewNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { + if (create) + dsqlScratch->qualifyNewName(name); + else + dsqlScratch->qualifyExistingName(name, obj_view); + + protectSystemSchema(name.schema, obj_view); + dsqlScratch->ddlSchema = name.schema; + source.ltrim("\n\r\t "); + return DdlNode::dsqlPass(dsqlScratch); } void CreateAlterViewNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - dsc dscName; - dscName.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str()); if (alter) { - if (SCL_check_view(tdbb, &dscName, SCL_alter) || !create) + if (SCL_check_view(tdbb, name, SCL_alter) || !create) return; } - SCL_check_create_access(tdbb, obj_views); + SCL_check_create_access(tdbb, obj_views, name.schema); } void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, @@ -8846,7 +9226,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra modifyingView = METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch, name); if (!modifyingView && !create) - status_exception::raise(Arg::Gds(isc_dyn_view_not_found) << name); + status_exception::raise(Arg::Gds(isc_dyn_view_not_found) << name.toQuotedString()); } saveRelation(tdbb, dsqlScratch, name, true, modifyingView == NULL); @@ -8856,7 +9236,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra const int ddlTriggerAction = (modifyingView ? DDL_TRIGGER_ALTER_VIEW : DDL_TRIGGER_CREATE_VIEW); - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, ddlTriggerAction, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, ddlTriggerAction, name, {}); if (!modifyingView) DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_relation); @@ -8884,7 +9264,8 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) REL IN RDB$RELATIONS - WITH REL.RDB$RELATION_NAME EQ name.c_str() AND + WITH REL.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + REL.RDB$RELATION_NAME EQ name.object.c_str() AND REL.RDB$VIEW_BLR NOT MISSING { found = true; @@ -8898,13 +9279,14 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra END_FOR if (!found) - status_exception::raise(Arg::Gds(isc_dyn_view_not_found) << name); + status_exception::raise(Arg::Gds(isc_dyn_view_not_found) << name.toQuotedString()); AutoRequest request2; FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) VR IN RDB$VIEW_RELATIONS - WITH VR.RDB$VIEW_NAME EQ name.c_str() + WITH VR.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + VR.RDB$VIEW_NAME EQ name.object.c_str() { ERASE VR; } @@ -8914,7 +9296,8 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) TRG IN RDB$TRIGGERS - WITH TRG.RDB$RELATION_NAME EQ name.c_str() AND + WITH TRG.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + TRG.RDB$RELATION_NAME EQ name.object.c_str() AND TRG.RDB$SYSTEM_FLAG EQ fb_sysflag_view_check { ERASE TRG; @@ -8928,7 +9311,8 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) REL IN RDB$RELATIONS { - strcpy(REL.RDB$RELATION_NAME, name.c_str()); + strcpy(REL.RDB$SCHEMA_NAME, name.schema.c_str()); + strcpy(REL.RDB$RELATION_NAME, name.object.c_str()); REL.RDB$SYSTEM_FLAG = 0; REL.RDB$FLAGS = REL_sql; REL.RDB$RELATION_TYPE = SSHORT(rel_view); @@ -8959,9 +9343,13 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra if (relation || procedure) { - const MetaName& refName = relation ? relation->rel_name : procedure->prc_name.identifier; - const char* contextName = context->ctx_alias.hasData() ? - context->ctx_alias.c_str() : refName.c_str(); + const auto& refName = relation ? relation->rel_name : procedure->prc_name; + string contextName; + + if (context->ctx_alias.hasData()) + contextName = context->getConcatenatedAlias(); + else + contextName = refName.toQuotedString(); ViewContextType ctxType; if (relation) @@ -8977,11 +9365,13 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) VRL IN RDB$VIEW_RELATIONS { - strcpy(VRL.RDB$VIEW_NAME, name.c_str()); - strcpy(VRL.RDB$RELATION_NAME, refName.c_str()); + strcpy(VRL.RDB$SCHEMA_NAME, name.schema.c_str()); + strcpy(VRL.RDB$VIEW_NAME, name.object.c_str()); + strcpy(VRL.RDB$RELATION_SCHEMA_NAME, refName.schema.c_str()); + strcpy(VRL.RDB$RELATION_NAME, refName.object.c_str()); VRL.RDB$CONTEXT_TYPE = SSHORT(ctxType); VRL.RDB$VIEW_CONTEXT = context->ctx_context; - strcpy(VRL.RDB$CONTEXT_NAME, contextName); + strcpy(VRL.RDB$CONTEXT_NAME, contextName.c_str()); if (procedure && procedure->prc_name.package.hasData()) { @@ -9000,10 +9390,13 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra request.reset(tdbb, drq_l_view_rels, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - VRL IN RDB$VIEW_RELATIONS CROSS - PREL IN RDB$RELATIONS OVER RDB$RELATION_NAME + VRL IN RDB$VIEW_RELATIONS + CROSS PREL IN RDB$RELATIONS WITH VRL.RDB$PACKAGE_NAME MISSING AND - VRL.RDB$VIEW_NAME EQ name.c_str() + VRL.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + VRL.RDB$VIEW_NAME EQ name.object.c_str() AND + PREL.RDB$SCHEMA_NAME EQ VRL.RDB$RELATION_SCHEMA_NAME AND + PREL.RDB$RELATION_NAME EQ VRL.RDB$RELATION_NAME { // CVC: This never matches so it causes unnecessary calls to verify, // so I included a call to strip trailing blanks. @@ -9011,13 +9404,13 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra if (ownerName != PREL.RDB$OWNER_NAME) { - SecurityClass::flags_t priv; + // I think this should be the responsability of DFW or the user will find ways to circumvent DYN. - // I think this should be the responsability of DFW or the user will find ways to - // circumvent DYN. - priv = SCL_get_mask(tdbb, PREL.RDB$RELATION_NAME, ""); + SCL_check_schema(tdbb, PREL.RDB$SCHEMA_NAME, SCL_usage); - if (!(priv & SCL_select)) + if (auto priv = SCL_get_mask(tdbb, QualifiedName(PREL.RDB$RELATION_NAME, PREL.RDB$SCHEMA_NAME), ""); + !(priv & SCL_select) + ) { // msg 32: no permission for %s access to %s %s status_exception::raise( @@ -9025,7 +9418,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra // Remember, a view may be based on a view. "TABLE/VIEW" << // Non-Translatable // We want to print the name of the base table or view. - MetaName(PREL.RDB$RELATION_NAME)); + QualifiedName(PREL.RDB$RELATION_NAME, PREL.RDB$SCHEMA_NAME).toQuotedString()); } } } @@ -9177,6 +9570,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra fieldDefinition.relationName = name; fieldDefinition.name = fieldStr; fieldDefinition.position = position; + fieldDefinition.fieldSource.schema = name.schema; // CVC: Not sure if something should be done now that isc_dyn_view_context is used here, // but if alter view is going to work, maybe we need here the context type and package, too. @@ -9201,8 +9595,10 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra RFL IN RDB$RELATION_FIELDS CROSS FLD IN RDB$FIELDS WITH RFL.RDB$FIELD_NAME EQ fieldStr AND - RFL.RDB$RELATION_NAME EQ name.c_str() AND + RFL.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + RFL.RDB$RELATION_NAME EQ name.object.c_str() AND RFL.RDB$BASE_FIELD MISSING AND + FLD.RDB$SCHEMA_NAME EQ RFL.RDB$FIELD_SOURCE_SCHEMA_NAME AND FLD.RDB$FIELD_NAME EQ RFL.RDB$FIELD_SOURCE { bool wasInternalDomain = fb_utils::implicit_domain(FLD.RDB$FIELD_NAME); @@ -9262,8 +9658,10 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra RFL IN RDB$RELATION_FIELDS CROSS FLD IN RDB$FIELDS WITH RFL.RDB$FIELD_NAME EQ fieldStr AND - RFL.RDB$RELATION_NAME EQ name.c_str() AND + RFL.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + RFL.RDB$RELATION_NAME EQ name.object.c_str() AND RFL.RDB$BASE_FIELD MISSING AND + FLD.RDB$SCHEMA_NAME EQ RFL.RDB$FIELD_SOURCE_SCHEMA_NAME AND FLD.RDB$FIELD_NAME EQ RFL.RDB$FIELD_SOURCE { bool wasInternalDomain = fb_utils::implicit_domain(FLD.RDB$FIELD_NAME); @@ -9271,7 +9669,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra if (wasInternalDomain) { - fieldDefinition.fieldSource = FLD.RDB$FIELD_NAME; + fieldDefinition.fieldSource = QualifiedName(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME); MODIFY FLD updateRdbFields(&newField, @@ -9293,7 +9691,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra } END_FOR - if (fieldDefinition.fieldSource.isEmpty()) + if (fieldDefinition.fieldSource.object.isEmpty()) { storeGlobalField(tdbb, transaction, fieldDefinition.fieldSource, &newField, "", dsqlScratch->getBlrData()); @@ -9388,7 +9786,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra dsqlScratch->resetContextStack(); - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, ddlTriggerAction, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, ddlTriggerAction, name, {}); savePoint.release(); // everything is ok @@ -9404,7 +9802,7 @@ void CreateAlterViewNode::createCheckTrigger(thread_db* tdbb, DsqlCompilerScratc MemoryPool& pool = *tdbb->getDefaultPool(); // Specify that the trigger should abort if the condition is not met. - ExceptionNode* exceptionNode = FB_NEW_POOL(pool) ExceptionNode(pool, CHECK_CONSTRAINT_EXCEPTION); + ExceptionNode* exceptionNode = FB_NEW_POOL(pool) ExceptionNode(pool, QualifiedName(CHECK_CONSTRAINT_EXCEPTION)); exceptionNode->exception->type = ExceptionItem::GDS_CODE; AutoSetRestore autoCheckConstraintTrigger(&dsqlScratch->checkConstraintTrigger, true); @@ -9430,8 +9828,7 @@ void CreateAlterViewNode::createCheckTrigger(thread_db* tdbb, DsqlCompilerScratc { dsqlScratch->contextNumber = 2; - RelationSourceNode* baseRelation = FB_NEW_POOL(pool) RelationSourceNode(pool, - sourceNode->dsqlName.identifier); + RelationSourceNode* baseRelation = FB_NEW_POOL(pool) RelationSourceNode(pool, sourceNode->dsqlName); baseRelation->alias = sourceNode->alias; dsqlScratch->appendUChar(blr_for); @@ -9508,7 +9905,7 @@ void CreateAlterViewNode::createCheckTrigger(thread_db* tdbb, DsqlCompilerScratc { FieldNode* oldValueNode = FB_NEW_POOL(pool) FieldNode(pool); oldValueNode->dsqlName = (aliasNode ? aliasNode->name : valueNode->dsqlName); - oldValueNode->dsqlQualifier = OLD_CONTEXT_NAME; + oldValueNode->dsqlQualifier.object = OLD_CONTEXT_NAME; valueNod = oldValueNode->dsqlPass(dsqlScratch); fieldNod = fieldNode->dsqlPass(dsqlScratch); @@ -9534,7 +9931,7 @@ void CreateAlterViewNode::createCheckTrigger(thread_db* tdbb, DsqlCompilerScratc AutoSetRestore autoAlias(&relationNode->alias, sourceNode->alias); if (relationNode->alias.isEmpty()) - relationNode->alias = sourceNode->dsqlName.identifier.c_str(); + relationNode->alias = sourceNode->dsqlName.object.c_str(); newContext = PASS1_make_context(dsqlScratch, relationNode); newContext->ctx_flags |= CTX_system; @@ -9619,12 +10016,14 @@ void CreateAlterViewNode::createCheckTrigger(thread_db* tdbb, DsqlCompilerScratc // Store an index. -void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& name, - const Definition& definition, MetaName* referredIndexName) +void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, QualifiedName& name, + const Definition& definition, QualifiedName* referredIndexName) { - if (name.isEmpty()) + if (name.object.isEmpty()) DYN_UTIL_generate_index_name(tdbb, transaction, name, definition.type); + fb_assert(name.schema == definition.relation.schema); + DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_index); AutoCacheRequest request(tdbb, drq_s_indices, DYN_REQUESTS); @@ -9637,14 +10036,14 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam IDX.RDB$UNIQUE_FLAG.NULL = TRUE; IDX.RDB$INDEX_INACTIVE.NULL = TRUE; IDX.RDB$INDEX_TYPE.NULL = TRUE; + IDX.RDB$FOREIGN_KEY_SCHEMA_NAME.NULL = TRUE; IDX.RDB$FOREIGN_KEY.NULL = TRUE; IDX.RDB$EXPRESSION_SOURCE.NULL = TRUE; IDX.RDB$EXPRESSION_BLR.NULL = TRUE; - strcpy(IDX.RDB$INDEX_NAME, name.c_str()); - strcpy(IDX.RDB$RELATION_NAME, definition.relation.c_str()); - IDX.RDB$RELATION_NAME.NULL = FALSE; + strcpy(IDX.RDB$SCHEMA_NAME, name.schema.c_str()); + strcpy(IDX.RDB$INDEX_NAME, name.object.c_str()); + strcpy(IDX.RDB$RELATION_NAME, definition.relation.object.c_str()); IDX.RDB$SYSTEM_FLAG = 0; - IDX.RDB$SYSTEM_FLAG.NULL = FALSE; // Probably redundant. // Check if the table is actually a view. @@ -9652,7 +10051,8 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) VREL IN RDB$RELATIONS - WITH VREL.RDB$RELATION_NAME EQ IDX.RDB$RELATION_NAME + WITH VREL.RDB$SCHEMA_NAME EQ IDX.RDB$SCHEMA_NAME AND + VREL.RDB$RELATION_NAME EQ IDX.RDB$RELATION_NAME { if (!VREL.RDB$VIEW_BLR.NULL) { @@ -9699,8 +10099,10 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) F IN RDB$RELATION_FIELDS CROSS GF IN RDB$FIELDS - WITH GF.RDB$FIELD_NAME EQ F.RDB$FIELD_SOURCE AND - F.RDB$FIELD_NAME EQ definition.columns[i].c_str() AND + WITH F.RDB$FIELD_NAME EQ definition.columns[i].c_str() AND + GF.RDB$SCHEMA_NAME EQUIV F.RDB$FIELD_SOURCE_SCHEMA_NAME AND + GF.RDB$FIELD_NAME EQ F.RDB$FIELD_SOURCE AND + IDX.RDB$SCHEMA_NAME EQ F.RDB$SCHEMA_NAME AND IDX.RDB$RELATION_NAME EQ F.RDB$RELATION_NAME { ULONG length = 0; @@ -9708,17 +10110,17 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam if (GF.RDB$FIELD_TYPE == blr_blob) { // msg 116 "attempt to index blob field in index %s" - status_exception::raise(Arg::PrivateDyn(116) << IDX.RDB$INDEX_NAME); + status_exception::raise(Arg::PrivateDyn(116) << name.toQuotedString()); } else if (!GF.RDB$DIMENSIONS.NULL) { // msg 117 "attempt to index array field in index %s" - status_exception::raise(Arg::PrivateDyn(117) << IDX.RDB$INDEX_NAME); + status_exception::raise(Arg::PrivateDyn(117) << name.toQuotedString()); } else if (!GF.RDB$COMPUTED_BLR.NULL) { // msg 179 "attempt to index COMPUTED BY field in index %s" - status_exception::raise(Arg::PrivateDyn(179) << IDX.RDB$INDEX_NAME); + status_exception::raise(Arg::PrivateDyn(179) << name.toQuotedString()); } else if (GF.RDB$FIELD_TYPE == blr_varying || GF.RDB$FIELD_TYPE == blr_text) { @@ -9760,7 +10162,7 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam if (!found) { // msg 120 "Unknown columns in index %s" - status_exception::raise(Arg::PrivateDyn(120) << IDX.RDB$INDEX_NAME); + status_exception::raise(Arg::PrivateDyn(120) << name.toQuotedString()); } } @@ -9780,7 +10182,7 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam if (keyLength >= MAX_KEY) { // msg 118 "key size too big for index %s" - status_exception::raise(Arg::PrivateDyn(118) << IDX.RDB$INDEX_NAME); + status_exception::raise(Arg::PrivateDyn(118) << name.toQuotedString()); } if (definition.columns.hasData()) @@ -9796,6 +10198,7 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam STORE(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) X IN RDB$INDEX_SEGMENTS { + strcpy(X.RDB$SCHEMA_NAME, IDX.RDB$SCHEMA_NAME); strcpy(X.RDB$INDEX_NAME, IDX.RDB$INDEX_NAME); strcpy(X.RDB$FIELD_NAME, segment->c_str()); X.RDB$FIELD_POSITION = position++; @@ -9806,7 +10209,7 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam else if (IDX.RDB$EXPRESSION_BLR.NULL) { // msg 119 "no keys for index %s" - status_exception::raise(Arg::PrivateDyn(119) << IDX.RDB$INDEX_NAME); + status_exception::raise(Arg::PrivateDyn(119) << name.toQuotedString()); } if (definition.refColumns.hasData()) @@ -9825,29 +10228,30 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam request2.reset(tdbb, drq_l_unq_idx, DYN_REQUESTS); - MetaName indexName; + QualifiedName refIndexName; int listIndex = -1; bool found = false; FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) RC IN RDB$RELATION_CONSTRAINTS CROSS - IND IN RDB$INDICES OVER RDB$INDEX_NAME CROSS - ISEG IN RDB$INDEX_SEGMENTS OVER RDB$INDEX_NAME - WITH IND.RDB$RELATION_NAME EQ definition.refRelation.c_str() AND + IND IN RDB$INDICES OVER RDB$SCHEMA_NAME, RDB$INDEX_NAME CROSS + ISEG IN RDB$INDEX_SEGMENTS OVER RDB$SCHEMA_NAME, RDB$INDEX_NAME + WITH IND.RDB$SCHEMA_NAME EQ definition.refRelation.schema.c_str() AND + IND.RDB$RELATION_NAME EQ definition.refRelation.object.c_str() AND IND.RDB$UNIQUE_FLAG NOT MISSING AND (RC.RDB$CONSTRAINT_TYPE = PRIMARY_KEY OR RC.RDB$CONSTRAINT_TYPE = UNIQUE_CNSTRT) SORTED BY IND.RDB$INDEX_NAME, DESCENDING ISEG.RDB$FIELD_POSITION { - if (indexName != IND.RDB$INDEX_NAME) + if (refIndexName != QualifiedName(IND.RDB$INDEX_NAME, IND.RDB$SCHEMA_NAME)) { if (listIndex >= 0) found = false; if (found) break; listIndex = definition.refColumns.getCount() - 1; - indexName = IND.RDB$INDEX_NAME; + refIndexName = QualifiedName(IND.RDB$INDEX_NAME, IND.RDB$SCHEMA_NAME); found = true; } @@ -9870,11 +10274,14 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam if (found) { + IDX.RDB$FOREIGN_KEY_SCHEMA_NAME.NULL = FALSE; + strcpy(IDX.RDB$FOREIGN_KEY_SCHEMA_NAME, refIndexName.schema.c_str()); + IDX.RDB$FOREIGN_KEY.NULL = FALSE; - strcpy(IDX.RDB$FOREIGN_KEY, indexName.c_str()); + strcpy(IDX.RDB$FOREIGN_KEY, refIndexName.object.c_str()); if (referredIndexName) - *referredIndexName = indexName; + *referredIndexName = refIndexName; } else { @@ -9883,7 +10290,8 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam FOR(REQUEST_HANDLE request3 TRANSACTION_HANDLE transaction) X IN RDB$RELATIONS - WITH X.RDB$RELATION_NAME EQ definition.refRelation.c_str() + WITH X.RDB$SCHEMA_NAME EQ definition.refRelation.schema.c_str() AND + X.RDB$RELATION_NAME EQ definition.refRelation.object.c_str() { found = true; isView = !X.RDB$VIEW_BLR.NULL; @@ -9893,30 +10301,31 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam if (isView) { // msg 242: "attempt to reference a view (%s) in a foreign key" - status_exception::raise(Arg::PrivateDyn(242) << definition.refRelation); + status_exception::raise(Arg::PrivateDyn(242) << definition.refRelation.toQuotedString()); } if (found) { // msg 18: "could not find UNIQUE or PRIMARY KEY constraint in table %s with // specified columns" - status_exception::raise(Arg::PrivateDyn(18) << definition.refRelation); + status_exception::raise(Arg::PrivateDyn(18) << definition.refRelation.toQuotedString()); } else { // msg 241: "Table %s not found" - status_exception::raise(Arg::PrivateDyn(241) << definition.refRelation); + status_exception::raise(Arg::PrivateDyn(241) << definition.refRelation.toQuotedString()); } } } - else if (definition.refRelation.hasData()) + else if (definition.refRelation.object.hasData()) { request2.reset(tdbb, drq_l_primary, DYN_REQUESTS); FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) IND IN RDB$INDICES CROSS - RC IN RDB$RELATION_CONSTRAINTS OVER RDB$INDEX_NAME - WITH IND.RDB$RELATION_NAME EQ definition.refRelation.c_str() AND + RC IN RDB$RELATION_CONSTRAINTS OVER RDB$SCHEMA_NAME, RDB$INDEX_NAME + WITH IND.RDB$SCHEMA_NAME EQ definition.refRelation.schema.c_str() AND + IND.RDB$RELATION_NAME EQ definition.refRelation.object.c_str() AND RC.RDB$CONSTRAINT_TYPE EQ PRIMARY_KEY { // Number of columns in referred index should be same as number @@ -9930,20 +10339,24 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam status_exception::raise(Arg::PrivateDyn(133)); } + fb_utils::exact_name_limit(IND.RDB$SCHEMA_NAME, sizeof(IND.RDB$SCHEMA_NAME)); fb_utils::exact_name_limit(IND.RDB$INDEX_NAME, sizeof(IND.RDB$INDEX_NAME)); + IDX.RDB$FOREIGN_KEY_SCHEMA_NAME.NULL = FALSE; + strcpy(IDX.RDB$FOREIGN_KEY_SCHEMA_NAME, IND.RDB$SCHEMA_NAME); + IDX.RDB$FOREIGN_KEY.NULL = FALSE; strcpy(IDX.RDB$FOREIGN_KEY, IND.RDB$INDEX_NAME); if (referredIndexName) - *referredIndexName = IND.RDB$INDEX_NAME; + *referredIndexName = QualifiedName(IND.RDB$INDEX_NAME, IND.RDB$SCHEMA_NAME); } END_FOR if (IDX.RDB$FOREIGN_KEY.NULL) { // msg 20: "could not find PRIMARY KEY index in specified table %s" - status_exception::raise(Arg::PrivateDyn(20) << definition.refRelation); + status_exception::raise(Arg::PrivateDyn(20) << definition.refRelation.toQuotedString()); } } @@ -9957,7 +10370,8 @@ void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& nam FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) IDX IN RDB$INDICES - WITH IDX.RDB$INDEX_NAME EQ name.c_str() + WITH IDX.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + IDX.RDB$INDEX_NAME EQ name.object.c_str() { MODIFY IDX if (!definition.conditionBlr.isEmpty()) @@ -9994,10 +10408,7 @@ string CreateIndexNode::internalPrint(NodePrinter& printer) const void CreateIndexNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - dsc dscName; - const MetaName &relationName = relation->dsqlName; - dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) relationName.c_str()); - SCL_check_relation(tdbb, &dscName, SCL_alter, false); + SCL_check_relation(tdbb, relation->dsqlName, SCL_alter, false); } // Define an index. @@ -10011,8 +10422,7 @@ void CreateIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_index)) return; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_INDEX, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_INDEX, name, {}); CreateIndexNode::Definition definition; definition.type = isc_dyn_def_idx; @@ -10023,8 +10433,8 @@ void CreateIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, if (columns) { - const NestConst* ptr = columns->items.begin(); - const NestConst* const end = columns->items.end(); + const NestConst* ptr = columns->items.begin(); + const NestConst* const end = columns->items.end(); for (; ptr != end; ++ptr) { @@ -10061,12 +10471,31 @@ void CreateIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, store(tdbb, transaction, name, definition); - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_INDEX, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_INDEX, name, {}); savePoint.release(); // everything is ok } +DdlNode* CreateIndexNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) +{ + dsqlScratch->qualifyExistingName(relation->dsqlName, obj_relation); + + if (name.schema.isEmpty()) + name.schema = relation->dsqlName.schema; + + if (name.schema != relation->dsqlName.schema) + { + status_exception::raise( + Arg::Gds(isc_dyn_index_schema_must_match_table) << + name.schema.toQuotedString() << + relation->dsqlName.schema.toQuotedString()); + } + + dsqlScratch->ddlSchema = name.schema; + + return DdlNode::dsqlPass(dsqlScratch); +} + //---------------------- @@ -10084,12 +10513,9 @@ string AlterIndexNode::internalPrint(NodePrinter& printer) const void AlterIndexNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { bool systemIndex; - MetaName relationName = getIndexRelationName(tdbb, transaction, name, systemIndex); + const auto relationName = getIndexRelationName(tdbb, transaction, name, systemIndex); - dsc dscName; - dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) relationName.c_str()); - - SCL_check_relation(tdbb, &dscName, SCL_alter, systemIndex); + SCL_check_relation(tdbb, relationName, SCL_alter, systemIndex); } void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) @@ -10102,12 +10528,12 @@ void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) IDX IN RDB$INDICES - WITH IDX.RDB$INDEX_NAME EQ name.c_str() + WITH IDX.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + IDX.RDB$INDEX_NAME EQ name.object.c_str() { found = true; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_INDEX, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_INDEX, name, {}); MODIFY IDX IDX.RDB$INDEX_INACTIVE.NULL = FALSE; @@ -10117,10 +10543,7 @@ void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, END_FOR if (found) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_INDEX, - name, NULL); - } + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_INDEX, name, {}); else { // msg 48: "Index not found" @@ -10146,12 +10569,9 @@ string SetStatisticsNode::internalPrint(NodePrinter& printer) const void SetStatisticsNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { bool systemIndex; - MetaName relationName = getIndexRelationName(tdbb, transaction, name, systemIndex); + const auto relationName = getIndexRelationName(tdbb, transaction, name, systemIndex); - dsc dscName; - dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) relationName.c_str()); - - SCL_check_relation(tdbb, &dscName, SCL_alter, false); + SCL_check_relation(tdbb, relationName, SCL_alter, false); } void SetStatisticsNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) @@ -10164,12 +10584,12 @@ void SetStatisticsNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) IDX IN RDB$INDICES - WITH IDX.RDB$INDEX_NAME EQ name.c_str() + WITH IDX.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + IDX.RDB$INDEX_NAME EQ name.object.c_str() { found = true; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_INDEX, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_INDEX, name, {}); MODIFY IDX // For V4 index selectivity can be set only to -1. @@ -10180,10 +10600,7 @@ void SetStatisticsNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc END_FOR if (found) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_INDEX, - name, NULL); - } + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_INDEX, name, {}); else { // msg 48: "Index not found" @@ -10198,14 +10615,15 @@ void SetStatisticsNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc // Delete the records in RDB$INDEX_SEGMENTS pertaining to an index. -bool DropIndexNode::deleteSegmentRecords(thread_db* tdbb, jrd_tra* transaction, - const MetaName& name) +bool DropIndexNode::deleteSegmentRecords(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& name) { AutoCacheRequest request(tdbb, drq_e_idx_segs, DYN_REQUESTS); bool found = false; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - IDXSEG IN RDB$INDEX_SEGMENTS WITH IDXSEG.RDB$INDEX_NAME EQ name.c_str() + IDXSEG IN RDB$INDEX_SEGMENTS + WITH IDXSEG.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + IDXSEG.RDB$INDEX_NAME EQ name.object.c_str() { found = true; ERASE IDXSEG; @@ -10227,15 +10645,10 @@ string DropIndexNode::internalPrint(NodePrinter& printer) const void DropIndexNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { bool systemIndex; - MetaName relationName = getIndexRelationName(tdbb, transaction, name, systemIndex, silent); + const auto relationName = getIndexRelationName(tdbb, transaction, name, systemIndex, silent); - if (relationName.hasData()) - { - dsc dscName; - dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) relationName.c_str()); - - SCL_check_relation(tdbb, &dscName, SCL_alter, systemIndex); - } + if (relationName.object.hasData()) + SCL_check_relation(tdbb, relationName, SCL_alter, systemIndex); } void DropIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) @@ -10248,10 +10661,10 @@ void DropIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, j FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) IDX IN RDB$INDICES - WITH IDX.RDB$INDEX_NAME EQ name.c_str() + WITH IDX.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + IDX.RDB$INDEX_NAME EQ name.object.c_str() { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_DROP_INDEX, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_INDEX, name, {}); ERASE IDX; @@ -10266,10 +10679,7 @@ void DropIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, j END_FOR if (found) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_INDEX, - name, NULL); - } + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_INDEX, name, {}); else if (!silent) { // msg 48: "Index not found" @@ -10298,7 +10708,7 @@ string CreateFilterNode::internalPrint(NodePrinter& printer) const void CreateFilterNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - SCL_check_create_access(tdbb, obj_filters); + SCL_check_create_access(tdbb, obj_filters, {}); } // Define a blob filter. @@ -10310,10 +10720,7 @@ void CreateFilterNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScrat // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); - /*** - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DECLARE_FILTER, - name, NULL); - ***/ + /// executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DECLARE_FILTER, name, {}); AutoCacheRequest request(tdbb, drq_s_filters, DYN_REQUESTS); @@ -10356,10 +10763,7 @@ void CreateFilterNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScrat } END_STORE - /*** - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DECLARE_FILTER, - name, NULL); - ***/ + /// executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DECLARE_FILTER, name, {}); savePoint.release(); // everything is ok } @@ -10565,7 +10969,7 @@ string CreateAlterRoleNode::internalPrint(NodePrinter& printer) const void CreateAlterRoleNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { if (createFlag) - SCL_check_create_access(tdbb, obj_roles); + SCL_check_create_access(tdbb, obj_roles, {}); else SCL_check_role(tdbb, name, SCL_alter); } @@ -10589,7 +10993,7 @@ void CreateAlterRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra return; executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - createFlag ? DDL_TRIGGER_CREATE_ROLE : DDL_TRIGGER_ALTER_ROLE, name, NULL); + (createFlag ? DDL_TRIGGER_CREATE_ROLE : DDL_TRIGGER_ALTER_ROLE), QualifiedName(name), {}); if (name == ownerName) { @@ -10638,7 +11042,7 @@ void CreateAlterRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra if (createFlag) { PreparedStatement::Builder sql; - sql << "insert into rdb$roles(rdb$role_name, rdb$owner_name, rdb$system_privileges, rdb$system_flag)" + sql << "insert into system.rdb$roles(rdb$role_name, rdb$owner_name, rdb$system_privileges, rdb$system_flag)" << "values(" << name << "," << ownerName << "," << p << ", 0)"; AutoPreparedStatement ps(attachment->prepareStatement(tdbb, transaction, sql)); @@ -10647,7 +11051,7 @@ void CreateAlterRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra else if (privileges.hasData() || sysPrivDrop) { PreparedStatement::Builder sql; - sql << "update rdb$roles set rdb$system_privileges =" << p << "where rdb$role_name =" << name; + sql << "update system.rdb$roles set rdb$system_privileges =" << p << "where rdb$role_name =" << name; AutoPreparedStatement ps(attachment->prepareStatement(tdbb, transaction, sql)); if (ps->executeUpdate(tdbb, transaction) == 0) @@ -10658,7 +11062,7 @@ void CreateAlterRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra } executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, - createFlag ? DDL_TRIGGER_CREATE_ROLE : DDL_TRIGGER_ALTER_ROLE, name, NULL); + (createFlag ? DDL_TRIGGER_CREATE_ROLE : DDL_TRIGGER_ALTER_ROLE), QualifiedName(name), {}); savePoint.release(); // everything is ok } @@ -10871,7 +11275,7 @@ void MappingNode::runInSecurityDb(SecDbContext* secDbContext) Message result; Field cnt(result); - const char* checkSql = "select count(*) from RDB$AUTH_MAPPING where RDB$MAP_NAME = ?"; + const char* checkSql = "select count(*) from SYSTEM.RDB$AUTH_MAPPING where RDB$MAP_NAME = ?"; secDbContext->att->execute(&statusWrapper2, secDbContext->tra, 0, checkSql, SQL_DIALECT_V6, msgCheck.getMetadata(), msgCheck.getBuffer(), result.getMetadata(), result.getBuffer()); @@ -10936,20 +11340,20 @@ void MappingNode::runInSecurityDb(SecDbContext* secDbContext) switch(op) { case MAP_ADD: - sql = "insert into RDB$AUTH_MAPPING(RDB$MAP_TO_TYPE, RDB$MAP_TO, RDB$MAP_USING, " + sql = "insert into SYSTEM.RDB$AUTH_MAPPING(RDB$MAP_TO_TYPE, RDB$MAP_TO, RDB$MAP_USING, " "RDB$MAP_PLUGIN, RDB$MAP_DB, RDB$MAP_FROM_TYPE, RDB$MAP_FROM, RDB$MAP_NAME, RDB$SYSTEM_FLAG) " "values (?, ?, ?, ?, ?, ?, ?, ?, 0)"; msg = &full; break; case MAP_MOD: - sql = "update RDB$AUTH_MAPPING set RDB$MAP_TO_TYPE = ?, RDB$MAP_TO = ?, " + sql = "update SYSTEM.RDB$AUTH_MAPPING set RDB$MAP_TO_TYPE = ?, RDB$MAP_TO = ?, " "RDB$MAP_USING = ?, RDB$MAP_PLUGIN = ?, RDB$MAP_DB = ?, " "RDB$MAP_FROM_TYPE = ?, RDB$MAP_FROM = ? " "where RDB$MAP_NAME = ?"; msg = &full; break; case MAP_COMMENT: - sql = "update RDB$AUTH_MAPPING set RDB$DESCRIPTION = ? " + sql = "update SYSTEM.RDB$AUTH_MAPPING set RDB$DESCRIPTION = ? " "where RDB$MAP_NAME = ?"; msg = &cmnt; break; @@ -11024,8 +11428,7 @@ void MappingNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd case MAP_MOD: case MAP_RPL: ddlTriggerAction = DDL_TRIGGER_ALTER_MAPPING; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, ddlTriggerAction, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, ddlTriggerAction, QualifiedName(name), {}); MODIFY M if (to) @@ -11066,8 +11469,7 @@ void MappingNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd case MAP_DROP: ddlTriggerAction = DDL_TRIGGER_DROP_MAPPING; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, ddlTriggerAction, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, ddlTriggerAction, QualifiedName(name), {}); ERASE M; break; @@ -11092,7 +11494,7 @@ void MappingNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd break; ddlTriggerAction = DDL_TRIGGER_CREATE_MAPPING; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, ddlTriggerAction, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, ddlTriggerAction, QualifiedName(name), {}); STORE(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) M IN RDB$AUTH_MAPPING @@ -11141,10 +11543,10 @@ void MappingNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd fb_assert(ddlTriggerAction > 0 || op == MAP_COMMENT || (op == MAP_DROP && silentDrop)); if (ddlTriggerAction > 0) - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, ddlTriggerAction, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, ddlTriggerAction, QualifiedName(name), {}); if (op != MAP_COMMENT) - DFW_post_work(transaction, dfw_clear_cache, NULL, Mapping::MAPPING_CACHE); + DFW_post_work(transaction, dfw_clear_cache, {}, {}, Mapping::MAPPING_CACHE); savePoint.release(); // everything is ok } @@ -11179,8 +11581,8 @@ void DropRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jr ROL IN RDB$ROLES WITH ROL.RDB$ROLE_NAME EQ name.c_str() { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_DROP_ROLE, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_ROLE, + QualifiedName(name), {}); if (ROL.RDB$SYSTEM_FLAG != 0) { @@ -11222,10 +11624,7 @@ void DropRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jr END_FOR if (found) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_ROLE, - name, NULL); - } + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_ROLE, QualifiedName(name), {}); else if (!silent) { // msg 155: "Role %s not found" @@ -11399,13 +11798,13 @@ void CreateAlterUserNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra const int ddlAction = mode == USER_ADD ? DDL_TRIGGER_CREATE_USER : DDL_TRIGGER_ALTER_USER; executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, ddlAction, - userData->user.get(), NULL); + QualifiedName(userData->user.get()), {}); const USHORT id = transaction->getUserManagement()->put(userData); - DFW_post_work(transaction, dfw_user_management, NULL, id); + DFW_post_work(transaction, dfw_user_management, nullptr, nullptr, id); executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, ddlAction, - userData->user.get(), NULL); + QualifiedName(userData->user.get()), {}); savePoint.release(); // everything is ok } @@ -11450,13 +11849,13 @@ void DropUserNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jr check(&statusWrapper); executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_USER, - userData->user.get(), NULL); + QualifiedName(userData->user.get()), {}); const USHORT id = transaction->getUserManagement()->put(userData); - DFW_post_work(transaction, dfw_user_management, NULL, id); + DFW_post_work(transaction, dfw_user_management, nullptr, nullptr, id); executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_USER, - userData->user.get(), NULL); + QualifiedName(userData->user.get()), {}); savePoint.release(); // everything is ok } @@ -11532,7 +11931,7 @@ void GrantRevokeNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, } // Invalidate system privileges cache - DFW_post_work(transaction, dfw_clear_cache, NULL, Mapping::SYSTEM_PRIVILEGES_CACHE); + DFW_post_work(transaction, dfw_clear_cache, {}, {}, Mapping::SYSTEM_PRIVILEGES_CACHE); } } @@ -11559,7 +11958,7 @@ void GrantRevokeNode::runInSecurityDb(SecDbContext* secDbContext) Field u(isRole, MAX_SQL_IDENTIFIER_LEN); u = j.user.c_str(); - const char* isRoleSql = "select count(*) from RDB$ROLES where RDB$ROLE_NAME = ?"; + const char* isRoleSql = "select count(*) from SYSTEM.RDB$ROLES where RDB$ROLE_NAME = ?"; secDbContext->att->execute(&statusWrapper, secDbContext->tra, 0, isRoleSql, SQL_DIALECT_V6, isRole.getMetadata(), isRole.getBuffer(), result.getMetadata(), result.getBuffer()); check(&statusWrapper); @@ -11578,7 +11977,7 @@ void GrantRevokeNode::runInSecurityDb(SecDbContext* secDbContext) uType = j.userType; u = j.user.c_str(); - const char* checkSql = "select count(*) from RDB$DB_CREATORS where RDB$USER_TYPE = ? and RDB$USER = ?"; + const char* checkSql = "select count(*) from SYSTEM.RDB$DB_CREATORS where RDB$USER_TYPE = ? and RDB$USER = ?"; secDbContext->att->execute(&statusWrapper, secDbContext->tra, 0, checkSql, SQL_DIALECT_V6, gr.getMetadata(), gr.getBuffer(), result.getMetadata(), result.getBuffer()); check(&statusWrapper); @@ -11587,7 +11986,7 @@ void GrantRevokeNode::runInSecurityDb(SecDbContext* secDbContext) { if (!cnt) { - const char* insertSql = "insert into RDB$DB_CREATORS(RDB$USER_TYPE, RDB$USER) values(?, ?)"; + const char* insertSql = "insert into SYSTEM.RDB$DB_CREATORS(RDB$USER_TYPE, RDB$USER) values(?, ?)"; secDbContext->att->execute(&statusWrapper, secDbContext->tra, 0, insertSql, SQL_DIALECT_V6, gr.getMetadata(), gr.getBuffer(), NULL, NULL); check(&statusWrapper); @@ -11597,7 +11996,7 @@ void GrantRevokeNode::runInSecurityDb(SecDbContext* secDbContext) { if (cnt) { - const char* deleteSql = "delete from RDB$DB_CREATORS where RDB$USER_TYPE = ? and RDB$USER = ?"; + const char* deleteSql = "delete from SYSTEM.RDB$DB_CREATORS where RDB$USER_TYPE = ? and RDB$USER = ?"; secDbContext->att->execute(&statusWrapper, secDbContext->tra, 0, deleteSql, SQL_DIALECT_V6, gr.getMetadata(), gr.getBuffer(), NULL, NULL); @@ -11645,13 +12044,8 @@ void GrantRevokeNode::modifyPrivileges(thread_db* tdbb, jrd_tra* transaction, SS { char privs0[2] = {i->first, '\0'}; - ValueListNode* fields = i->second; - - for (NestConst* ptr = fields->items.begin(); ptr != fields->items.end(); ++ptr) - { - grantRevoke(tdbb, transaction, object, user, privs0, - nodeAs(*ptr)->dsqlName, option); - } + for (const auto& field : *i->second) + grantRevoke(tdbb, transaction, object, user, privs0, field, option); } else privs += i->first; @@ -11662,7 +12056,7 @@ void GrantRevokeNode::modifyPrivileges(thread_db* tdbb, jrd_tra* transaction, SS } -static bool checkObjectExist(thread_db* tdbb, jrd_tra* transaction, const MetaName& name, int type) +static bool checkObjectExist(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& name, int type) { bool rc = false; @@ -11673,7 +12067,9 @@ static bool checkObjectExist(thread_db* tdbb, jrd_tra* transaction, const MetaNa AutoCacheRequest request(tdbb, drq_proc_exist, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$PROCEDURES - WITH X.RDB$PROCEDURE_NAME EQ name.c_str() AND X.RDB$PACKAGE_NAME MISSING + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$PROCEDURE_NAME EQ name.object.c_str() AND + X.RDB$PACKAGE_NAME MISSING { rc = true; } @@ -11686,7 +12082,9 @@ static bool checkObjectExist(thread_db* tdbb, jrd_tra* transaction, const MetaNa AutoCacheRequest request(tdbb, drq_udf_exist, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$FUNCTIONS - WITH X.RDB$FUNCTION_NAME EQ name.c_str() AND X.RDB$PACKAGE_NAME MISSING + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$FUNCTION_NAME EQ name.object.c_str() AND + X.RDB$PACKAGE_NAME MISSING { rc = true; } @@ -11699,7 +12097,25 @@ static bool checkObjectExist(thread_db* tdbb, jrd_tra* transaction, const MetaNa AutoCacheRequest request(tdbb, drq_package_exist, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$PACKAGES - WITH X.RDB$PACKAGE_NAME EQ name.c_str() + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$PACKAGE_NAME EQ name.object.c_str() + { + rc = true; + } + END_FOR + break; + } + + case obj_schema: + { + fb_assert(name.object.hasData() && name.schema.isEmpty()); + + static const CachedRequestId requestId; + AutoCacheRequest request(tdbb, requestId); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + SCH IN RDB$SCHEMAS + WITH SCH.RDB$SCHEMA_NAME EQ name.object.c_str() { rc = true; } @@ -11712,7 +12128,8 @@ static bool checkObjectExist(thread_db* tdbb, jrd_tra* transaction, const MetaNa AutoCacheRequest request(tdbb, drq_trigger_exist, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$TRIGGERS - WITH X.RDB$TRIGGER_NAME EQ name.c_str() + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$TRIGGER_NAME EQ name.object.c_str() { rc = true; } @@ -11726,7 +12143,8 @@ static bool checkObjectExist(thread_db* tdbb, jrd_tra* transaction, const MetaNa AutoCacheRequest request(tdbb, drq_rel_exist, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$RELATIONS - WITH X.RDB$RELATION_NAME EQ name.c_str() + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$RELATION_NAME EQ name.object.c_str() { rc = (type != obj_view) || !X.RDB$VIEW_BLR.NULL; } @@ -11739,7 +12157,8 @@ static bool checkObjectExist(thread_db* tdbb, jrd_tra* transaction, const MetaNa AutoCacheRequest request(tdbb, drq_exception_exist, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$EXCEPTIONS - WITH X.RDB$EXCEPTION_NAME EQ name.c_str() + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$EXCEPTION_NAME EQ name.object.c_str() { rc = true; } @@ -11752,7 +12171,8 @@ static bool checkObjectExist(thread_db* tdbb, jrd_tra* transaction, const MetaNa AutoCacheRequest request(tdbb, drq_generator_exist, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$GENERATORS - WITH X.RDB$GENERATOR_NAME EQ name.c_str() + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$GENERATOR_NAME EQ name.object.c_str() { rc = true; } @@ -11764,14 +12184,16 @@ static bool checkObjectExist(thread_db* tdbb, jrd_tra* transaction, const MetaNa return rc; } -static bool checkFieldExist(thread_db* tdbb, jrd_tra* transaction, const MetaName& relation, const MetaName& field) +static bool checkFieldExist(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& relation, + const MetaName& field) { bool rc = false; AutoCacheRequest request(tdbb, drq_rel_field_exist, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$RELATION_FIELDS - WITH X.RDB$RELATION_NAME EQ relation.c_str() AND + WITH X.RDB$SCHEMA_NAME EQ relation.schema.c_str() AND + X.RDB$RELATION_NAME EQ relation.object.c_str() AND X.RDB$FIELD_NAME EQ field.c_str() { rc = true; @@ -11787,10 +12209,10 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G MetaName field, int options) { ObjectType userType = userNod->first; - MetaName user(userNod->second); + QualifiedName user(userNod->second); MetaName dummyName; const ObjectType objType = object ? object->first : obj_type_MAX; - const MetaName objName(object ? object->second : ""); + const auto objName(object ? object->second : QualifiedName()); bool crdb = false; AutoPtr privileges(FB_NEW char[MAX(strlen(ALL_PRIVILEGES), strlen(privs ? privs : "")) + 1]); @@ -11825,13 +12247,13 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G { case obj_user_or_role: // This test may become obsolete as we now allow explicit ROLE keyword. - if (isItSqlRole(tdbb, transaction, user, dummyName)) + if (isItSqlRole(tdbb, transaction, user.object, dummyName)) { userType = obj_sql_role; - if (user == NULL_ROLE) + if (user.object == NULL_ROLE) { // msg 195: keyword NONE could not be used as SQL role name. - status_exception::raise(Arg::PrivateDyn(195) << user.c_str()); + status_exception::raise(Arg::PrivateDyn(195) << user.toQuotedString()); } } else @@ -11844,49 +12266,53 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G case obj_udf: if (!checkObjectExist(tdbb, transaction, user, userType)) - status_exception::raise(Arg::PrivateDyn(301) << user.c_str()); // Function @1 does not exist + status_exception::raise(Arg::PrivateDyn(301) << user.toQuotedString()); // Function @1 does not exist break; case obj_procedure: if (!checkObjectExist(tdbb, transaction, user, userType)) - status_exception::raise(Arg::PrivateDyn(302) << user.c_str()); // Procedure @1 does not exist + status_exception::raise(Arg::PrivateDyn(302) << user.toQuotedString()); // Procedure @1 does not exist break; case obj_package_header: if (!checkObjectExist(tdbb, transaction, user, userType)) - status_exception::raise(Arg::PrivateDyn(303) << user.c_str()); // Package @1 does not exist + status_exception::raise(Arg::PrivateDyn(303) << user.toQuotedString()); // Package @1 does not exist + break; + + case obj_schema: + if (!checkObjectExist(tdbb, transaction, user, userType)) + status_exception::raise(Arg::Gds(isc_dyn_schema_not_found) << user.toQuotedString()); break; case obj_trigger: if (!checkObjectExist(tdbb, transaction, user, userType)) - status_exception::raise(Arg::PrivateDyn(304) << user.c_str()); // Trigger @1 does not exist + status_exception::raise(Arg::PrivateDyn(304) << user.toQuotedString()); // Trigger @1 does not exist break; case obj_view: if (!checkObjectExist(tdbb, transaction, user, userType)) - status_exception::raise(Arg::PrivateDyn(305) << user.c_str()); // View @1 does not exist + status_exception::raise(Arg::PrivateDyn(305) << user.toQuotedString()); // View @1 does not exist break; case obj_sql_role: - if (!crdb && (!isItSqlRole(tdbb, transaction, user, dummyName))) + if (!crdb && (!isItSqlRole(tdbb, transaction, user.object, dummyName))) { // msg 188: Role doesn't exist. - status_exception::raise(Arg::PrivateDyn(188) << user.c_str()); + status_exception::raise(Arg::PrivateDyn(188) << user.toQuotedString()); } - if (user == NULL_ROLE) + if (user.object == NULL_ROLE) { // msg 195: keyword NONE could not be used as SQL role name. - status_exception::raise(Arg::PrivateDyn(195) << user.c_str()); + status_exception::raise(Arg::PrivateDyn(195) << user.toQuotedString()); } break; case obj_privilege: // Should convert symbolic privilege name to bit number { - USHORT p = convertPrivilegeFromString(tdbb, transaction, user); - user.printf("%d", p); + USHORT p = convertPrivilegeFromString(tdbb, transaction, user.object); + user.object.printf("%d", p); } break; - } // Check if grant subject exists @@ -11894,52 +12320,70 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G { case obj_view: if (!checkObjectExist(tdbb, transaction, objName, objType)) - status_exception::raise(Arg::PrivateDyn(305) << objName.c_str()); // View @1 does not exist + status_exception::raise(Arg::PrivateDyn(305) << objName.toQuotedString()); // View @1 does not exist break; case obj_relation: if (!checkObjectExist(tdbb, transaction, objName, objType)) - status_exception::raise(Arg::PrivateDyn(306) << objName.c_str()); // Table @1 does not exist + status_exception::raise(Arg::PrivateDyn(306) << objName.toQuotedString()); // Table @1 does not exist if (field.hasData() && !checkFieldExist(tdbb, transaction, objName, field)) - status_exception::raise(Arg::PrivateDyn(309) << field.c_str() << objName.c_str()); // Field @1 of table @2 does not exist + status_exception::raise(Arg::PrivateDyn(309) << field.c_str() << objName.toQuotedString()); // Field @1 of table @2 does not exist + break; + + case obj_schema: + if (!checkObjectExist(tdbb, transaction, objName, objType)) + status_exception::raise(Arg::Gds(isc_dyn_schema_not_found) << objName.toQuotedString()); break; case obj_trigger: if (!checkObjectExist(tdbb, transaction, objName, objType)) - status_exception::raise(Arg::PrivateDyn(304) << objName.c_str()); // Trigger @1 does not exist + status_exception::raise(Arg::PrivateDyn(304) << objName.toQuotedString()); // Trigger @1 does not exist break; case obj_procedure: if (!checkObjectExist(tdbb, transaction, objName, objType)) - status_exception::raise(Arg::PrivateDyn(302) << objName.c_str()); // Procedure @1 does not exist + status_exception::raise(Arg::PrivateDyn(302) << objName.toQuotedString()); // Procedure @1 does not exist break; case obj_exception: if (!checkObjectExist(tdbb, transaction, objName, objType)) - status_exception::raise(Arg::PrivateDyn(307) << objName.c_str()); // Exception @1 does not exist + status_exception::raise(Arg::PrivateDyn(307) << objName.toQuotedString()); // Exception @1 does not exist break; case obj_generator: if (!checkObjectExist(tdbb, transaction, objName, objType)) - status_exception::raise(Arg::PrivateDyn(308) << objName.c_str()); // Generator/Sequence @1 does not exist + status_exception::raise(Arg::PrivateDyn(308) << objName.toQuotedString()); // Generator/Sequence @1 does not exist break; case obj_udf: if (!checkObjectExist(tdbb, transaction, objName, objType)) - status_exception::raise(Arg::PrivateDyn(301) << objName.c_str()); // Function @1 does not exist + status_exception::raise(Arg::PrivateDyn(301) << objName.toQuotedString()); // Function @1 does not exist break; case obj_package_header: if (!checkObjectExist(tdbb, transaction, objName, objType)) - status_exception::raise(Arg::PrivateDyn(303) << objName.c_str()); // Package @1 does not exist + status_exception::raise(Arg::PrivateDyn(303) << objName.toQuotedString()); // Package @1 does not exist break; case obj_sql_role: - if (!isItSqlRole(tdbb, transaction, objName, dummyName)) - status_exception::raise(Arg::PrivateDyn(188) << objName.c_str()); // Role doesn't exist. + if (!isItSqlRole(tdbb, transaction, objName.object, dummyName)) + status_exception::raise(Arg::PrivateDyn(188) << objName.toQuotedString()); // Role doesn't exist. break; + case obj_relations: + case obj_views: + case obj_procedures: + case obj_functions: + case obj_packages: + case obj_generators: + case obj_domains: + case obj_exceptions: + case obj_charsets: + case obj_collations: + if (!checkObjectExist(tdbb, transaction, QualifiedName(objName.schema), obj_schema)) + status_exception::raise(Arg::Gds(isc_dyn_schema_not_found) << objName.toQuotedString()); + default: fb_assert(object == NULL || isDdlObject(objType)); } @@ -11952,6 +12396,10 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G ERRD_post(Arg::Gds(isc_dsql_cant_grant_option) << Arg::Str("procedures")); break; + case obj_schema: + ERRD_post(Arg::Gds(isc_dsql_cant_grant_option) << Arg::Str("schemas")); + break; + case obj_trigger: ERRD_post(Arg::Gds(isc_dsql_cant_grant_option) << Arg::Str("triggers")); break; @@ -11995,13 +12443,14 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G if (!isGrant && !privs) // REVOKE ALL ON ALL { AutoCacheRequest request(tdbb, drq_e_grant3, DYN_REQUESTS); - CreateDbJob all(userType, user); + CreateDbJob all(userType, user.object); all.allOnAll = true; all.revoker = grantorRevoker; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) PRIV IN RDB$USER_PRIVILEGES - WITH PRIV.RDB$USER = user.c_str() AND + WITH PRIV.RDB$USER_SCHEMA_NAME EQUIV NULLIF(user.schema.c_str(), '') AND + PRIV.RDB$USER = user.object.c_str() AND PRIV.RDB$USER_TYPE = userType AND PRIV.RDB$GRANTOR NOT MISSING { @@ -12021,12 +12470,12 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G return; } - if (objType == obj_sql_role && objName == NULL_ROLE) + if (objType == obj_sql_role && objName.object == NULL_ROLE) { if (isGrant) { // msg 195: keyword NONE could not be used as SQL role name. - status_exception::raise(Arg::PrivateDyn(195) << objName.c_str()); + status_exception::raise(Arg::PrivateDyn(195) << objName.object.c_str()); } else { @@ -12037,7 +12486,7 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G if (crdb) { - CreateDbJob job(userType, user); + CreateDbJob job(userType, user.object); createDbJobs.push(job); if (!privileges[0]) @@ -12060,10 +12509,12 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) PRIV IN RDB$USER_PRIVILEGES - WITH PRIV.RDB$RELATION_NAME EQ objName.c_str() AND + WITH PRIV.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(objName.schema.c_str(), '') AND + PRIV.RDB$RELATION_NAME EQUIV NULLIF(objName.object.c_str(), '') AND PRIV.RDB$OBJECT_TYPE = objType AND PRIV.RDB$PRIVILEGE EQ priv AND - PRIV.RDB$USER = user.c_str() AND + PRIV.RDB$USER_SCHEMA_NAME EQUIV NULLIF(user.schema.c_str(), '') AND + PRIV.RDB$USER = user.object.c_str() AND PRIV.RDB$USER_TYPE = userType AND PRIV.RDB$GRANTOR EQ grantorRevoker.c_str() AND (PRIV.RDB$FIELD_NAME EQUIV NULLIF(field.c_str(), '') OR @@ -12079,10 +12530,10 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G const bool addDefaultRole = (objType == obj_sql_role && field == "D" && PRIV.RDB$FIELD_NAME.NULL); if (addGrantOption && !addDefaultRole) // Save DEFAULT option for re-grant - newField = PRIV.RDB$FIELD_NAME; + newField = PRIV.RDB$FIELD_NAME; if (addDefaultRole && !addGrantOption) // Add grant option was requested - newOptions = PRIV.RDB$GRANT_OPTION; + newOptions = PRIV.RDB$GRANT_OPTION; duplicate = !addGrantOption && !addDefaultRole; @@ -12096,18 +12547,18 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G if (objType == obj_sql_role) { - checkGrantorCanGrantRole(tdbb, transaction, grantorRevoker, objName); + checkGrantorCanGrantRole(tdbb, transaction, grantorRevoker, objName.object); if (userType == obj_sql_role) { // Check for blocking cycles of role grants. UserId grantedRoles; - grantedRoles.setSqlRole(objName); + grantedRoles.setSqlRole(objName.object); - if (grantedRoles.roleInUse(tdbb, user)) + if (grantedRoles.roleInUse(tdbb, user.object)) { // 292: role @1 can not be granted to role @2 - status_exception::raise(Arg::PrivateDyn(292) << objName.c_str() << user.c_str()); + status_exception::raise(Arg::PrivateDyn(292) << objName.toQuotedString() << user.toQuotedString()); } } } @@ -12139,6 +12590,7 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G case obj_exception: case obj_generator: case obj_package_header: + case obj_schema: { checkGrantorCanGrantObject(tdbb, transaction, currentUser.c_str(), priv, objName, objType); break; @@ -12161,24 +12613,25 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G const bool revokeDefaultRole = (objType == obj_sql_role) && field.hasData(); const bool revokeGrantOption = options; - // This var must be identical for request (1) and if below (2) const bool withField = field.hasData() && objType != obj_sql_role; - - AutoCacheRequest request(tdbb, (withField ? drq_e_grant1 : drq_e_grant2), DYN_REQUESTS); // (1) + static const CachedRequestId withFieldRequestHandleId, withoutFieldRequestHandleId; + AutoCacheRequest request(tdbb, (withField ? withFieldRequestHandleId : withoutFieldRequestHandleId)); for (const char* pr = privileges; (priv[0] = *pr); ++pr) { bool grantErased = false; bool badGrantor = false; - if (withField) // (2) + if (withField) { FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) PRIV IN RDB$USER_PRIVILEGES - WITH PRIV.RDB$RELATION_NAME EQ objName.c_str() AND + WITH PRIV.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(objName.schema.c_str(), '') AND + PRIV.RDB$RELATION_NAME EQUIV NULLIF(objName.object.c_str(), '') AND PRIV.RDB$OBJECT_TYPE = objType AND PRIV.RDB$PRIVILEGE EQ priv AND - PRIV.RDB$USER = user.c_str() AND + PRIV.RDB$USER_SCHEMA_NAME EQUIV NULLIF(user.schema.c_str(), '') AND + PRIV.RDB$USER = user.object.c_str() AND PRIV.RDB$USER_TYPE = userType AND PRIV.RDB$FIELD_NAME EQ field.c_str() AND PRIV.RDB$GRANTOR NOT MISSING @@ -12211,9 +12664,11 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) PRIV IN RDB$USER_PRIVILEGES WITH PRIV.RDB$PRIVILEGE EQ priv AND - PRIV.RDB$RELATION_NAME EQ objName.c_str() AND + PRIV.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(objName.schema.c_str(), '') AND + PRIV.RDB$RELATION_NAME EQUIV NULLIF(objName.object.c_str(), '') AND PRIV.RDB$OBJECT_TYPE = objType AND - PRIV.RDB$USER EQ user.c_str() AND + PRIV.RDB$USER_SCHEMA_NAME EQUIV NULLIF(user.schema.c_str(), '') AND + PRIV.RDB$USER EQ user.object.c_str() AND PRIV.RDB$USER_TYPE = userType AND PRIV.RDB$GRANTOR NOT MISSING { @@ -12224,11 +12679,11 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G MetaName owner; if ((grantorRevoker == PRIV.RDB$GRANTOR) || ((objType == obj_sql_role) && (PRIV.RDB$PRIVILEGE[0] == 'M') && // This is ROLE to USER grant - (currentUser != user) && // And current user does not revoke his own grant - ((isItSqlRole(tdbb, transaction, objName, owner) && // Pick up role owner name + (currentUser != user.object) && // And current user does not revoke his own grant + ((isItSqlRole(tdbb, transaction, objName.object, owner) && // Pick up role owner name (attachment->locksmith(tdbb, GRANT_REVOKE_ON_ANY_OBJECT) || // God-like check (owner == currentUser))) || // Current user is role owner - (getGrantorOption(tdbb, transaction, currentUser, obj_user, objName) == 2)))) // or has ADMIN option + (getGrantorOption(tdbb, transaction, currentUser, obj_user, objName.object) == 2)))) // or has ADMIN option { MetaName newField = NULL; int newOptions = 0; @@ -12258,14 +12713,16 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G { // msg 246: @1 is not grantor of @2 on @3 to @4. status_exception::raise(Arg::PrivateDyn(246) << - grantorRevoker.c_str() << privilegeName(priv[0]) << objName.c_str() << - user.c_str()); + grantorRevoker.c_str() << privilegeName(priv[0]) << objName.toQuotedString() << + user.toQuotedString()); } // msg 247: Warning: @1 on @2 is not granted to @3. ERR_post_warning( Arg::Warning(isc_dyn_miss_priv_warning) << - Arg::Str(privilegeName(priv[0])) << Arg::Str(objName) << Arg::Str(user)); + Arg::Str(privilegeName(priv[0])) << + objName.toQuotedString() << + user.toQuotedString()); } } } @@ -12273,7 +12730,7 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G // Check if the grantor has grant privilege on the relation/field. void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* transaction, - const char* grantor, const char* privilege, const MetaName& relationName, + const char* grantor, const char* privilege, const QualifiedName& relationName, const MetaName& fieldName, bool topLevel) { const Attachment* attachment = tdbb->getAttachment(); @@ -12286,8 +12743,9 @@ void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra bool relationExists = false; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - REL IN RDB$RELATIONS WITH - REL.RDB$RELATION_NAME = relationName.c_str() + REL IN RDB$RELATIONS + WITH REL.RDB$SCHEMA_NAME = relationName.schema.c_str() AND + REL.RDB$RELATION_NAME = relationName.object.c_str() { relationExists = true; if (!REL.RDB$FLAGS.NULL && (REL.RDB$FLAGS & REL_sql)) @@ -12298,7 +12756,7 @@ void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra if (!relationExists) { // table/view .. does not exist - status_exception::raise(Arg::PrivateDyn(175) << relationName.c_str()); + status_exception::raise(Arg::PrivateDyn(175) << relationName.toQuotedString()); } // Verify the the input field exists. @@ -12310,9 +12768,10 @@ void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra request.reset(tdbb, drq_gcg5, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - G_FLD IN RDB$RELATION_FIELDS WITH - G_FLD.RDB$RELATION_NAME = relationName.c_str() AND - G_FLD.RDB$FIELD_NAME = fieldName.c_str() + G_FLD IN RDB$RELATION_FIELDS + WITH G_FLD.RDB$SCHEMA_NAME = relationName.schema.c_str() AND + G_FLD.RDB$RELATION_NAME = relationName.object.c_str() AND + G_FLD.RDB$FIELD_NAME = fieldName.c_str() { fieldExists = true; } @@ -12322,7 +12781,8 @@ void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra { // column .. does not exist in table/view .. status_exception::raise(Arg::PrivateDyn(176) << - fieldName.c_str() << relationName.c_str()); + fieldName << + relationName.toQuotedString()); } } @@ -12339,9 +12799,10 @@ void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra request.reset(tdbb, drq_gcg2, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - REL IN RDB$RELATIONS WITH - REL.RDB$RELATION_NAME = relationName.c_str() AND - REL.RDB$OWNER_NAME = UPPERCASE(grantor) + REL IN RDB$RELATIONS + WITH REL.RDB$SCHEMA_NAME = relationName.schema.c_str() AND + REL.RDB$RELATION_NAME = relationName.object.c_str() AND + REL.RDB$OWNER_NAME = UPPERCASE(grantor) { grantorIsOwner = true; } @@ -12367,7 +12828,8 @@ void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra PRV IN RDB$USER_PRIVILEGES WITH ((PRV.RDB$USER = UPPERCASE(grantor) AND PRV.RDB$USER_TYPE = obj_user) OR (PRV.RDB$USER_TYPE = obj_sql_role)) AND - PRV.RDB$RELATION_NAME = relationName.c_str() AND + PRV.RDB$RELATION_SCHEMA_NAME EQ relationName.schema.c_str() AND + PRV.RDB$RELATION_NAME = relationName.object.c_str() AND PRV.RDB$OBJECT_TYPE = obj_relation AND PRV.RDB$PRIVILEGE = privilege { @@ -12403,7 +12865,7 @@ void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra { // no grant option for privilege .. on column .. of [base] table/view .. status_exception::raise(Arg::PrivateDyn(topLevel ? 167 : 168) << - privilegeName(*privilege) << fieldName.c_str() << relationName.c_str()); + privilegeName(*privilege) << fieldName.c_str() << relationName.toQuotedString()); } if (goFld == -1) @@ -12412,14 +12874,14 @@ void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra { // no grant option for privilege .. on [base] table/view .. (for column ..) status_exception::raise(Arg::PrivateDyn(topLevel ? 169 : 170) << - privilegeName(*privilege) << relationName.c_str() << fieldName.c_str()); + privilegeName(*privilege) << relationName.toQuotedString() << fieldName.c_str()); } if (goRel == -1) { // no .. privilege with grant option on [base] table/view .. (for column ..) status_exception::raise(Arg::PrivateDyn(topLevel ? 171 : 172) << - privilegeName(*privilege) << relationName.c_str() << fieldName.c_str()); + privilegeName(*privilege) << relationName.toQuotedString() << fieldName.c_str()); } } } @@ -12428,13 +12890,13 @@ void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra if (goRel == 0) { // no grant option for privilege .. on table/view .. - status_exception::raise(Arg::PrivateDyn(173) << privilegeName(*privilege) << relationName.c_str()); + status_exception::raise(Arg::PrivateDyn(173) << privilegeName(*privilege) << relationName.toQuotedString()); } if (goRel == -1) { // no .. privilege with grant option on table/view .. - status_exception::raise(Arg::PrivateDyn(174) << privilegeName(*privilege) << relationName.c_str()); + status_exception::raise(Arg::PrivateDyn(174) << privilegeName(*privilege) << relationName.toQuotedString()); } } @@ -12450,25 +12912,29 @@ void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra request.reset(tdbb, drq_gcg3, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - G_FLD IN RDB$RELATION_FIELDS CROSS - G_VIEW IN RDB$VIEW_RELATIONS WITH - G_FLD.RDB$RELATION_NAME = relationName.c_str() AND - G_FLD.RDB$BASE_FIELD NOT MISSING AND - G_VIEW.RDB$VIEW_NAME EQ G_FLD.RDB$RELATION_NAME AND - G_VIEW.RDB$VIEW_CONTEXT EQ G_FLD.RDB$VIEW_CONTEXT + G_FLD IN RDB$RELATION_FIELDS + CROSS G_VIEW IN RDB$VIEW_RELATIONS + WITH G_FLD.RDB$SCHEMA_NAME = relationName.schema.c_str() AND + G_FLD.RDB$RELATION_NAME = relationName.object.c_str() AND + G_FLD.RDB$BASE_FIELD NOT MISSING AND + G_VIEW.RDB$SCHEMA_NAME EQ G_FLD.RDB$SCHEMA_NAME AND + G_VIEW.RDB$VIEW_NAME EQ G_FLD.RDB$RELATION_NAME AND + G_VIEW.RDB$VIEW_CONTEXT EQ G_FLD.RDB$VIEW_CONTEXT { if (fieldName.hasData()) { if (fieldName == G_FLD.RDB$FIELD_NAME) { checkGrantorCanGrantRelation(tdbb, transaction, grantor, privilege, - G_VIEW.RDB$RELATION_NAME, G_FLD.RDB$BASE_FIELD, false); + QualifiedName(G_VIEW.RDB$RELATION_NAME, G_VIEW.RDB$RELATION_SCHEMA_NAME), + G_FLD.RDB$BASE_FIELD, false); } } else { checkGrantorCanGrantRelation(tdbb, transaction, grantor, privilege, - G_VIEW.RDB$RELATION_NAME, G_FLD.RDB$BASE_FIELD, false); + QualifiedName(G_VIEW.RDB$RELATION_NAME, G_VIEW.RDB$RELATION_SCHEMA_NAME), + G_FLD.RDB$BASE_FIELD, false); } } END_FOR @@ -12553,7 +13019,7 @@ void GrantRevokeNode::checkGrantorCanGrantRole(thread_db* tdbb, jrd_tra* transac // Check if the grantor has grant option on DDL privilege void GrantRevokeNode::checkGrantorCanGrantDdl(thread_db* tdbb, jrd_tra* transaction, - const MetaName& grantor, const char* privilege, const MetaName& objName) + const MetaName& grantor, const char* privilege, const QualifiedName& objName) { const Attachment* attachment = tdbb->getAttachment(); @@ -12567,7 +13033,8 @@ void GrantRevokeNode::checkGrantorCanGrantDdl(thread_db* tdbb, jrd_tra* transact PRV IN RDB$USER_PRIVILEGES WITH ((PRV.RDB$USER = UPPERCASE(grantor.c_str()) AND PRV.RDB$USER_TYPE = obj_user) OR (PRV.RDB$USER_TYPE = obj_sql_role)) AND - PRV.RDB$RELATION_NAME EQ objName.c_str() AND + PRV.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(objName.schema.c_str(), '') AND + PRV.RDB$RELATION_NAME EQ objName.object.c_str() AND PRV.RDB$OBJECT_TYPE >= obj_database AND // it might be deleted but I believe it's more efficient PRV.RDB$PRIVILEGE EQ privilege { @@ -12589,14 +13056,14 @@ void GrantRevokeNode::checkGrantorCanGrantDdl(thread_db* tdbb, jrd_tra* transact if (!grantable) { // no @1 privilege with grant option on DDL @2 - status_exception::raise(Arg::PrivateDyn(299) << privilegeName(*privilege) << objName.c_str()); + status_exception::raise(Arg::PrivateDyn(299) << privilegeName(*privilege) << objName.toQuotedString()); } } // Check if the grantor has grant option on generator privilege void GrantRevokeNode::checkGrantorCanGrantObject(thread_db* tdbb, jrd_tra* transaction, const char* grantor, - const char* privilege, const MetaName& objName, SSHORT objType) + const char* privilege, const QualifiedName& objName, SSHORT objType) { const Attachment* attachment = tdbb->getAttachment(); @@ -12610,7 +13077,8 @@ void GrantRevokeNode::checkGrantorCanGrantObject(thread_db* tdbb, jrd_tra* trans PRV IN RDB$USER_PRIVILEGES WITH ((PRV.RDB$USER = UPPERCASE(grantor) AND PRV.RDB$USER_TYPE = obj_user) OR (PRV.RDB$USER_TYPE = obj_sql_role)) AND - PRV.RDB$RELATION_NAME EQ objName.c_str() AND + PRV.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(objName.schema.c_str(), '') AND + PRV.RDB$RELATION_NAME EQ objName.object.c_str() AND PRV.RDB$OBJECT_TYPE = objType AND PRV.RDB$PRIVILEGE EQ privilege { @@ -12628,32 +13096,59 @@ void GrantRevokeNode::checkGrantorCanGrantObject(thread_db* tdbb, jrd_tra* trans if (!grantable) { // no @1 privilege with grant option on object @2 - status_exception::raise(Arg::PrivateDyn(300) << privilegeName(*privilege) << objName.c_str()); + status_exception::raise(Arg::PrivateDyn(300) << privilegeName(*privilege) << objName.toQuotedString()); } } -void GrantRevokeNode::storePrivilege(thread_db* tdbb, jrd_tra* transaction, const MetaName& object, - const MetaName& user, const MetaName& field, const TEXT* privilege, SSHORT userType, +void GrantRevokeNode::storePrivilege(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& object, + const QualifiedName& user, const MetaName& field, const TEXT* privilege, SSHORT userType, SSHORT objType, int option, const MetaName& grantor) { AutoCacheRequest request(tdbb, drq_s_grant, DYN_REQUESTS); STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) PRIV IN RDB$USER_PRIVILEGES + { + if (object.schema.hasData()) + { + strcpy(PRIV.RDB$RELATION_SCHEMA_NAME, object.schema.c_str()); + PRIV.RDB$RELATION_SCHEMA_NAME.NULL = FALSE; + } + else + PRIV.RDB$RELATION_SCHEMA_NAME.NULL = TRUE; + PRIV.RDB$FIELD_NAME.NULL = TRUE; - strcpy(PRIV.RDB$RELATION_NAME, object.c_str()); - strcpy(PRIV.RDB$USER, user.c_str()); + + if (object.object.hasData()) + { + strcpy(PRIV.RDB$RELATION_NAME, object.object.c_str()); + PRIV.RDB$RELATION_NAME.NULL = FALSE; + } + else + PRIV.RDB$RELATION_NAME.NULL = TRUE; + + if (user.schema.hasData()) + { + strcpy(PRIV.RDB$USER_SCHEMA_NAME, user.schema.c_str()); + PRIV.RDB$USER_SCHEMA_NAME.NULL = FALSE; + } + else + PRIV.RDB$USER_SCHEMA_NAME.NULL = TRUE; + + strcpy(PRIV.RDB$USER, user.object.c_str()); + strcpy(PRIV.RDB$GRANTOR, grantor.c_str()); PRIV.RDB$USER_TYPE = userType; PRIV.RDB$OBJECT_TYPE = objType; - { + if (field.hasData()) { strcpy(PRIV.RDB$FIELD_NAME, field.c_str()); PRIV.RDB$FIELD_NAME.NULL = FALSE; setFieldClassName(tdbb, transaction, object, field); } + PRIV.RDB$PRIVILEGE[0] = privilege[0]; PRIV.RDB$PRIVILEGE[1] = 0; PRIV.RDB$GRANT_OPTION = option; @@ -12663,7 +13158,7 @@ void GrantRevokeNode::storePrivilege(thread_db* tdbb, jrd_tra* transaction, cons // For field level grants, be sure the field has a unique class name. void GrantRevokeNode::setFieldClassName(thread_db* tdbb, jrd_tra* transaction, - const MetaName& relation, const MetaName& field) + const QualifiedName& relation, const MetaName& field) { AutoCacheRequest request(tdbb, drq_s_f_class, DYN_REQUESTS); @@ -12672,21 +13167,24 @@ void GrantRevokeNode::setFieldClassName(thread_db* tdbb, jrd_tra* transaction, FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RFR IN RDB$RELATION_FIELDS WITH RFR.RDB$FIELD_NAME = field.c_str() AND - RFR.RDB$RELATION_NAME = relation.c_str() AND + RFR.RDB$SCHEMA_NAME = relation.schema.c_str() AND + RFR.RDB$RELATION_NAME = relation.object.c_str() AND RFR.RDB$SECURITY_CLASS MISSING { MODIFY RFR while (!unique) { sprintf(RFR.RDB$SECURITY_CLASS, "%s%" SQUADFORMAT, SQL_FLD_SECCLASS_PREFIX, - DPM_gen_id(tdbb, MET_lookup_generator(tdbb, SQL_SECCLASS_GENERATOR), false, 1)); + DPM_gen_id(tdbb, + MET_lookup_generator(tdbb, QualifiedName(SQL_SECCLASS_GENERATOR, SYSTEM_SCHEMA)), false, 1)); unique = true; AutoCacheRequest request2(tdbb, drq_s_u_class, DYN_REQUESTS); FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) RFR1 IN RDB$RELATION_FIELDS - WITH RFR1.RDB$SECURITY_CLASS = RFR.RDB$SECURITY_CLASS + WITH RFR1.RDB$SCHEMA_NAME = RFR.RDB$SCHEMA_NAME AND + RFR1.RDB$SECURITY_CLASS = RFR.RDB$SECURITY_CLASS { unique = false; } @@ -12815,7 +13313,7 @@ void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc relationType(REL.RDB$RELATION_TYPE.NULL, REL.RDB$RELATION_TYPE); if (relType == rel_persistent) - pubTables.add(REL.RDB$RELATION_NAME); + pubTables.add(QualifiedName(REL.RDB$RELATION_NAME, REL.RDB$SCHEMA_NAME)); } END_FOR @@ -12836,16 +13334,16 @@ void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc { AutoCacheRequest request(tdbb, drq_l_pub_rel_name, DYN_REQUESTS); - for (const MetaName* iter = pubTables.begin(); iter != pubTables.end(); ++iter) + for (const auto& tableName : pubTables) { - const MetaName& tableName = *iter; bool found = false; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) REL IN RDB$RELATIONS - WITH REL.RDB$SYSTEM_FLAG EQ 0 - AND REL.RDB$VIEW_BLR MISSING - AND REL.RDB$RELATION_NAME EQ tableName.c_str() + WITH REL.RDB$SYSTEM_FLAG EQ 0 AND + REL.RDB$VIEW_BLR MISSING AND + REL.RDB$SCHEMA_NAME EQ tableName.schema.c_str() AND + REL.RDB$RELATION_NAME EQ tableName.object.c_str() { const rel_t relType = relationType(REL.RDB$RELATION_TYPE.NULL, REL.RDB$RELATION_TYPE); @@ -12856,14 +13354,12 @@ void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc END_FOR if (!found) - status_exception::raise(Arg::Gds(isc_dyn_table_not_found) << tableName); + status_exception::raise(Arg::Gds(isc_dyn_table_not_found) << tableName.toQuotedString()); } } - for (const MetaName* iter = pubTables.begin(); iter != pubTables.end(); ++iter) + for (const auto& tableName : pubTables) { - const MetaName& tableName = *iter; - if (clauses & CLAUSE_PUB_INCL_TABLE) { try @@ -12897,32 +13393,58 @@ void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc if (clauses & CLAUSE_END_BACKUP) changeBackupMode(tdbb, transaction, CLAUSE_END_BACKUP); - if (setDefaultCharSet.hasData() || setDefaultCollation.hasData() || linger >= 0 || + if (setDefaultCharSet.object.hasData() || setDefaultCollation.object.hasData() || linger >= 0 || ssDefiner.isAssigned()) { - AutoCacheRequest request(tdbb, drq_m_database, DYN_REQUESTS); - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + static const CachedRequestId databaseRequestHandleId; + AutoCacheRequest databaseRequestHandle(tdbb, databaseRequestHandleId); + + FOR(REQUEST_HANDLE databaseRequestHandle TRANSACTION_HANDLE transaction) DBB IN RDB$DATABASE { MODIFY DBB USING - if (setDefaultCharSet.hasData()) + if (setDefaultCharSet.object.hasData()) { - if (!METD_get_charset(transaction, setDefaultCharSet.length(), - setDefaultCharSet.c_str())) + if (!METD_get_charset(transaction, setDefaultCharSet)) { // specified character set not found - status_exception::raise(Arg::Gds(isc_charset_not_found) << setDefaultCharSet); + status_exception::raise(Arg::Gds(isc_charset_not_found) << setDefaultCharSet.toQuotedString()); } + DBB.RDB$CHARACTER_SET_SCHEMA_NAME.NULL = FALSE; + strcpy(DBB.RDB$CHARACTER_SET_SCHEMA_NAME, setDefaultCharSet.schema.c_str()); + DBB.RDB$CHARACTER_SET_NAME.NULL = FALSE; - strcpy(DBB.RDB$CHARACTER_SET_NAME, setDefaultCharSet.c_str()); + strcpy(DBB.RDB$CHARACTER_SET_NAME, setDefaultCharSet.object.c_str()); + + if (create) + { + static const CachedRequestId schemaRequestHandleId; + AutoCacheRequest schemaRequestHandle(tdbb, schemaRequestHandleId); + + FOR (REQUEST_HANDLE schemaRequestHandle TRANSACTION_HANDLE transaction) + SCH IN RDB$SCHEMAS + WITH SCH.RDB$SCHEMA_NAME EQ PUBLIC_SCHEMA + { + MODIFY SCH USING + { + SCH.RDB$CHARACTER_SET_SCHEMA_NAME.NULL = FALSE; + strcpy(SCH.RDB$CHARACTER_SET_SCHEMA_NAME, setDefaultCharSet.schema.c_str()); + + SCH.RDB$CHARACTER_SET_NAME.NULL = FALSE; + strcpy(SCH.RDB$CHARACTER_SET_NAME, setDefaultCharSet.object.c_str()); + } + END_MODIFY + } + END_FOR + } dsql_dbb* dbb = transaction->getDsqlAttachment(); - dbb->dbb_dfl_charset = ""; // reset in the cache + dbb->dbb_dfl_charset.clear(); // reset in the cache } - if (!DBB.RDB$CHARACTER_SET_NAME.NULL && setDefaultCollation.hasData()) + if (!DBB.RDB$CHARACTER_SET_NAME.NULL && setDefaultCollation.object.hasData()) { AlterCharSetNode alterCharSetNode(dsqlScratch->getPool(), setDefaultCharSet, setDefaultCollation); alterCharSetNode.execute(tdbb, dsqlScratch, transaction); @@ -12951,7 +13473,7 @@ void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc Database* const db = tdbb->getDatabase(); db->dbb_crypto_manager->prepareChangeCryptState(tdbb, cryptPlugin, keyName); - DFW_post_work(transaction, dfw_db_crypt, cryptPlugin.c_str(), 0); + DFW_post_work(transaction, dfw_db_crypt, cryptPlugin.c_str(), {}, 0); } savePoint.release(); // everything is ok @@ -13072,4 +13594,472 @@ void AlterDatabaseNode::defineDifference(thread_db* tdbb, jrd_tra* transaction, } +//---------------------- + + +string CreateAlterSchemaNode::internalPrint(NodePrinter& printer) const +{ + DdlNode::internalPrint(printer); + + NODE_PRINT(printer, name); + NODE_PRINT(printer, create); + NODE_PRINT(printer, alter); + NODE_PRINT(printer, createIfNotExistsOnly); + NODE_PRINT(printer, setDefaultCharSet); + + return "CreateAlterSchemaNode"; +} + +DdlNode* CreateAlterSchemaNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) +{ + if (create && (name == "INFORMATION_SCHEMA" || name == "DEFINITION_SCHEMA")) + status_exception::raise(Arg::Gds(isc_dyn_cannot_create_reserved_schema) << name.toQuotedString()); + + dsqlScratch->ddlSchema = name; + + if (setDefaultCharSet.object.hasData()) + { + dsqlScratch->qualifyExistingName(setDefaultCharSet, obj_charset); + + if (!METD_get_charset(dsqlScratch->getTransaction(), setDefaultCharSet)) + status_exception::raise(Arg::Gds(isc_charset_not_found) << setDefaultCharSet.toQuotedString()); + } + + return DdlNode::dsqlPass(dsqlScratch); +} + +void CreateAlterSchemaNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + if (alter) + { + if (SCL_check_schema(tdbb, name, SCL_alter) || !create) + return; + } + + SCL_check_create_access(tdbb, obj_schemas, {}); +} + +void CreateAlterSchemaNode::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_dyn_schema_not_found) << name.toQuotedString()); + } + } + else + executeCreate(tdbb, dsqlScratch, transaction); + + savePoint.release(); // everything is ok +} + +void CreateAlterSchemaNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) +{ + const auto dbb = transaction->getDsqlAttachment(); + const QualifiedName qualifiedName(name); + const auto attachment = transaction->getAttachment(); + const auto& ownerName = attachment->getEffectiveUserName(); + + if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, qualifiedName, obj_schema)) + return; + + auto defaultCharSet = setDefaultCharSet; + + if (defaultCharSet.object.isEmpty()) + defaultCharSet = METD_get_database_charset(transaction); + + fb_assert(defaultCharSet.object.hasData()); + + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_SCHEMA, qualifiedName, {}); + + DYN_UTIL_check_unique_name(tdbb, transaction, qualifiedName, obj_schema); + + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + + STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + SCH IN RDB$SCHEMAS USING + { + strcpy(SCH.RDB$SCHEMA_NAME, name.c_str()); + SCH.RDB$SYSTEM_FLAG = 0; + strcpy(SCH.RDB$OWNER_NAME, ownerName.c_str()); + strcpy(SCH.RDB$CHARACTER_SET_NAME, defaultCharSet.object.c_str()); + strcpy(SCH.RDB$CHARACTER_SET_SCHEMA_NAME, defaultCharSet.schema.c_str()); + } + END_STORE + + static const CachedRequestId userPrivRequestHandleId; + AutoCacheRequest userPrivRequestHandle(tdbb, userPrivRequestHandleId); + + for (int obj = obj_database + 1; obj < obj_type_MAX; obj++) + { + if (bool useSchema; isDdlObject(obj, &useSchema) && useSchema) + { + for (const char* privilege = ALL_DDL_PRIVILEGES; *privilege; ++privilege) + { + STORE(REQUEST_HANDLE userPrivRequestHandle TRANSACTION_HANDLE transaction) + X IN RDB$USER_PRIVILEGES + { + strcpy(X.RDB$RELATION_SCHEMA_NAME, name.c_str()); + strcpy(X.RDB$RELATION_NAME, getSecurityClassName(obj)); + + strcpy(X.RDB$USER, ownerName.c_str()); + X.RDB$USER_TYPE = obj_user; + X.RDB$OBJECT_TYPE = obj; + X.RDB$PRIVILEGE[0] = *privilege; + X.RDB$PRIVILEGE[1] = 0; + X.RDB$GRANT_OPTION = WITH_GRANT_OPTION; + } + END_STORE + } + } + } + + storePrivileges(tdbb, transaction, qualifiedName, obj_schema, USAGE_PRIVILEGES); + + dbb->dbb_schemas_dfl_charset.put(name, defaultCharSet); + + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_SCHEMA, qualifiedName, {}); +} + +bool CreateAlterSchemaNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) +{ + const auto dbb = transaction->getDsqlAttachment(); + const QualifiedName qualifiedName(name); + + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + bool modified = false; + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + SCH IN RDB$SCHEMAS + WITH SCH.RDB$SCHEMA_NAME = name.c_str() + { + if (SCH.RDB$SYSTEM_FLAG) + status_exception::raise(Arg::Gds(isc_dyn_cannot_mod_system_schema)); + + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_SCHEMA, qualifiedName, {}); + + MODIFY SCH + { + if (setDefaultCharSet.object.hasData()) + { + strcpy(SCH.RDB$CHARACTER_SET_NAME, setDefaultCharSet.object.c_str()); + strcpy(SCH.RDB$CHARACTER_SET_SCHEMA_NAME, setDefaultCharSet.schema.c_str()); + } + + modified = true; + } + END_MODIFY + } + END_FOR + + if (modified) + { + if (setDefaultCharSet.object.hasData()) + dbb->dbb_schemas_dfl_charset.put(name, setDefaultCharSet); + + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_SCHEMA, qualifiedName, {}); + } + + return modified; +} + + +//---------------------- + + +string DropSchemaNode::internalPrint(NodePrinter& printer) const +{ + DdlNode::internalPrint(printer); + + NODE_PRINT(printer, name); + NODE_PRINT(printer, silent); + + return "DropSchemaNode"; +} + +void DropSchemaNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_schema(tdbb, name, SCL_drop); +} + +void DropSchemaNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) +{ + const auto dbb = transaction->getDsqlAttachment(); + const QualifiedName qualifiedName(name); + + // run all statements under savepoint control + AutoSavePoint savePoint(tdbb, transaction); + + bool found = false; + + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + SCH IN RDB$SCHEMAS + WITH SCH.RDB$SCHEMA_NAME = name.c_str() + { + if (SCH.RDB$SYSTEM_FLAG) + status_exception::raise(Arg::Gds(isc_dyn_cannot_mod_system_schema)); + + found = true; + + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_SCHEMA, qualifiedName, {}); + + if (collectObjects(tdbb, transaction)) + status_exception::raise(Arg::Gds(isc_dyn_cannot_drop_non_emptyschema) << name.toQuotedString()); + + ERASE SCH; + + if (!SCH.RDB$SECURITY_CLASS.NULL) + deleteSecurityClass(tdbb, transaction, SCH.RDB$SECURITY_CLASS); + + static const CachedRequestId privRequestHandleId; + AutoCacheRequest privRequestHandle(tdbb, privRequestHandleId); + + FOR(REQUEST_HANDLE privRequestHandle TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + WITH PRIV.RDB$RELATION_SCHEMA_NAME = name.c_str() + { + ERASE PRIV; + } + END_FOR + + static const CachedRequestId secClsRequestHandleId; + AutoCacheRequest secClsRequestHandle(tdbb, secClsRequestHandleId); + + for (int obj = obj_database + 1; obj < obj_type_MAX; obj++) + { + if (bool useSchema; isDdlObject(obj, &useSchema) && useSchema) + { + const auto secClassName = string(getSecurityClassName(obj)) + "$" + name.c_str(); + + FOR(REQUEST_HANDLE secClsRequestHandle TRANSACTION_HANDLE transaction) + SC IN RDB$SECURITY_CLASSES + WITH SC.RDB$SECURITY_CLASS = secClassName.c_str() + { + ERASE SC; + } + END_FOR + } + } + + deletePrivilegesByRelName(tdbb, transaction, qualifiedName, obj_schema); + + dbb->dbb_schemas_dfl_charset.remove(name); + + /* FIXME: + dsc schemaDesc, nameDesc; + schemaDesc.makeText(name.schema.length(), ttype_metadata, (UCHAR*) const_cast(name.schema.c_str())); + nameDesc.makeText(name.object.length(), ttype_metadata, (UCHAR*) const_cast(name.object.c_str())); + DFW_post_work(transaction, dfw_drop_package_header, &nameDesc, &schemaDesc, 0); + */ + } + END_FOR + + if (!found && !silent) + { + status_exception::raise( + Arg::Gds(isc_no_meta_update) << + Arg::Gds(isc_dyn_schema_not_found) << name.toQuotedString()); + } + + if (found) + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_SCHEMA, qualifiedName, {}); + + savePoint.release(); // everything is ok +} + +bool DropSchemaNode::collectObjects(thread_db* tdbb, jrd_tra* transaction, + Array>* objects) +{ + if (objects) + objects->clear(); + + { // fields + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + FLD IN RDB$FIELDS + WITH FLD.RDB$SCHEMA_NAME EQ name.c_str() + SORTED BY FLD.RDB$FIELD_NAME + { + if (objects) + objects->add({obj_field, FLD.RDB$FIELD_NAME}); + else + return true; + } + END_FOR + } + + { // relations + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + REL IN RDB$RELATIONS + WITH REL.RDB$SCHEMA_NAME EQ name.c_str() + SORTED BY REL.RDB$RELATION_NAME + { + if (objects) + objects->add({obj_relation, REL.RDB$RELATION_NAME}); + } + END_FOR + } + + { // triggers + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + TRG IN RDB$TRIGGERS + WITH TRG.RDB$SCHEMA_NAME EQ name.c_str() AND + TRG.RDB$RELATION_NAME MISSING + SORTED BY TRG.RDB$TRIGGER_NAME + { + if (objects) + objects->add({obj_trigger, TRG.RDB$TRIGGER_NAME}); + else + return true; + } + END_FOR + } + + { // functions + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + FUN IN RDB$FUNCTIONS + WITH FUN.RDB$SCHEMA_NAME EQ name.c_str() AND + FUN.RDB$PACKAGE_NAME MISSING + SORTED BY FUN.RDB$FUNCTION_NAME + { + if (objects) + objects->add({obj_udf, FUN.RDB$FUNCTION_NAME}); + else + return true; + } + END_FOR + } + + { // generators + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + GEN IN RDB$GENERATORS + WITH GEN.RDB$SCHEMA_NAME EQ name.c_str() + SORTED BY GEN.RDB$GENERATOR_NAME + { + if (objects) + objects->add({obj_generator, GEN.RDB$GENERATOR_NAME}); + else + return true; + } + END_FOR + } + + { // procedures + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + PRC IN RDB$PROCEDURES + WITH PRC.RDB$SCHEMA_NAME EQ name.c_str() AND + PRC.RDB$PACKAGE_NAME MISSING + SORTED BY PRC.RDB$PROCEDURE_NAME + { + if (objects) + objects->add({obj_procedure, PRC.RDB$PROCEDURE_NAME}); + else + return true; + } + END_FOR + } + + { // character sets + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + CSC IN RDB$CHARACTER_SETS + WITH CSC.RDB$SCHEMA_NAME EQ name.c_str() + SORTED BY CSC.RDB$CHARACTER_SET_NAME + { + if (objects) + objects->add({obj_charset, CSC.RDB$CHARACTER_SET_NAME}); + else + return true; + } + END_FOR + } + + { // collations + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + COL IN RDB$COLLATIONS + WITH COL.RDB$SCHEMA_NAME EQ name.c_str() + SORTED BY COL.RDB$COLLATION_NAME + { + if (objects) + objects->add({obj_collation, COL.RDB$COLLATION_NAME}); + else + return true; + } + END_FOR + } + + { // exceptions + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + XCP IN RDB$EXCEPTIONS + WITH XCP.RDB$SCHEMA_NAME EQ name.c_str() + SORTED BY XCP.RDB$EXCEPTION_NAME + { + if (objects) + objects->add({obj_exception, XCP.RDB$EXCEPTION_NAME}); + else + return true; + } + END_FOR + } + + { // packages + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + PKG IN RDB$PACKAGES + WITH PKG.RDB$SCHEMA_NAME EQ name.c_str() + SORTED BY PKG.RDB$PACKAGE_NAME + { + if (objects) + objects->add({obj_package_header, PKG.RDB$PACKAGE_NAME}); + else + return true; + } + END_FOR + } + + return objects && objects->hasData(); +} + + } // namespace Jrd diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index 7f3f1b15df..c78de0d648 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -167,9 +167,7 @@ struct CollectedParameter bid defaultValue; }; -typedef Firebird::GenericMap< - Firebird::Pair > > - CollectedParameterMap; +typedef Firebird::LeftPooledMap CollectedParameterMap; class ExecInSecurityDb @@ -194,6 +192,7 @@ public: dropNode(p, createNode->name) { dropNode.silent = true; + dropNode.recreate = true; } public: @@ -234,7 +233,18 @@ public: protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(ERROR_CODE) << createNode->name; + statusVector << Firebird::Arg::Gds(ERROR_CODE) << nameToString(createNode->name); + } + +private: + Firebird::string nameToString(const QualifiedName& name) + { + return name.toQuotedString(); + } + + Firebird::string nameToString(const MetaName& name) + { + return name.toQuotedString(); } protected: @@ -246,8 +256,7 @@ protected: class AlterCharSetNode : public DdlNode { public: - AlterCharSetNode(MemoryPool& pool, const MetaName& aCharSet, - const MetaName& aDefaultCollation) + AlterCharSetNode(MemoryPool& pool, const QualifiedName& aCharSet, const QualifiedName& aDefaultCollation) : DdlNode(pool), charSet(pool, aCharSet), defaultCollation(pool, aDefaultCollation) @@ -259,15 +268,26 @@ public: virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + dsqlScratch->qualifyExistingName(charSet, obj_charset); + protectSystemSchema(charSet.schema, obj_charset); + dsqlScratch->ddlSchema = charSet.schema; + + dsqlScratch->qualifyExistingName(defaultCollation, obj_collation); + + return DdlNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_alter_charset_failed) << charSet; + statusVector << Firebird::Arg::Gds(isc_dsql_alter_charset_failed) << charSet.toQuotedString(); } private: - MetaName charSet; - MetaName defaultCollation; + QualifiedName charSet; + QualifiedName defaultCollation; }; @@ -344,11 +364,11 @@ class CommentOnNode : public DdlNode { public: CommentOnNode(MemoryPool& pool, int aObjType, - const QualifiedName& aObjName, const MetaName& aSubName, + const QualifiedName& aName, const MetaName& aSubName, const Firebird::string aText) : DdlNode(pool), objType(aObjType), - objName(pool, aObjName), + name(pool, aName), subName(pool, aSubName), text(pool, aText), str(pool) @@ -357,13 +377,14 @@ public: public: virtual Firebird::string internalPrint(NodePrinter& printer) const; + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); 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) { - str = objName.toString(); + str = name.toQuotedString(); if (subName.hasData()) str.append(".").append(subName.c_str()); @@ -373,7 +394,7 @@ protected: private: int objType; - QualifiedName objName; + QualifiedName name; MetaName subName; Firebird::string text, str; }; @@ -382,7 +403,7 @@ private: class CreateAlterFunctionNode : public DdlNode { public: - CreateAlterFunctionNode(MemoryPool& pool, const MetaName& aName) + CreateAlterFunctionNode(MemoryPool& pool, const QualifiedName& aName) : DdlNode(pool), name(pool, aName), create(true), @@ -395,7 +416,6 @@ public: body(NULL), compiled(false), invalid(false), - package(pool), packageOwner(pool), privateScope(false), preserveDefaults(false), @@ -416,7 +436,7 @@ protected: Firebird::Arg::Gds(createAlterCode(create, alter, isc_dsql_create_func_failed, isc_dsql_alter_func_failed, isc_dsql_create_alter_func_failed)) << - name; + name.toQuotedString(); } private: @@ -438,20 +458,19 @@ private: void collectParameters(thread_db* tdbb, jrd_tra* transaction, CollectedParameterMap& items); public: - MetaName name; + QualifiedName name; bool create; bool alter; bool createIfNotExistsOnly = false; NestConst external; Firebird::TriState deterministic; - Firebird::Array > parameters; + Firebird::Array> parameters; NestConst returnType; NestConst localDeclList; Firebird::string source; NestConst body; bool compiled; bool invalid; - MetaName package; MetaName packageOwner; bool privateScope; bool preserveDefaults; @@ -463,7 +482,7 @@ public: class AlterExternalFunctionNode : public DdlNode { public: - AlterExternalFunctionNode(MemoryPool& p, const MetaName& aName) + AlterExternalFunctionNode(MemoryPool& p, const QualifiedName& aName) : DdlNode(p), name(p, aName), clauses(p) @@ -475,14 +494,23 @@ public: virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + dsqlScratch->qualifyExistingName(name, obj_udf); + protectSystemSchema(name.schema, obj_udf); + dsqlScratch->ddlSchema = name.schema; + + return DdlNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_alter_func_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_alter_func_failed) << name.toQuotedString(); } public: - MetaName name; + QualifiedName name; ExternalClause clauses; }; @@ -490,17 +518,15 @@ public: class DropFunctionNode : public DdlNode { public: - DropFunctionNode(MemoryPool& pool, const MetaName& aName) + DropFunctionNode(MemoryPool& pool, const QualifiedName& aName) : DdlNode(pool), name(pool, aName), - silent(false), - package(pool) + silent(false) { } public: - static void dropArguments(thread_db* tdbb, jrd_tra* transaction, - const MetaName& functionName, const MetaName& packageName); + static void dropArguments(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& functionName); public: virtual Firebird::string internalPrint(NodePrinter& printer) const; @@ -511,13 +537,13 @@ public: protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_drop_func_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_drop_func_failed) << name.toQuotedString(); } public: - MetaName name; + QualifiedName name; bool silent; - MetaName package; + bool recreate = false; }; @@ -528,7 +554,7 @@ typedef RecreateNode body; bool compiled; bool invalid; - MetaName package; MetaName packageOwner; bool privateScope; bool preserveDefaults; @@ -601,17 +625,15 @@ public: class DropProcedureNode : public DdlNode { public: - DropProcedureNode(MemoryPool& pool, const MetaName& aName) + DropProcedureNode(MemoryPool& pool, const QualifiedName& aName) : DdlNode(pool), name(pool, aName), - silent(false), - package(pool) + silent(false) { } public: - static void dropParameters(thread_db* tdbb, jrd_tra* transaction, - const MetaName& procedureName, const MetaName& packageName); + static void dropParameters(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& procedureName); public: virtual Firebird::string internalPrint(NodePrinter& printer) const; @@ -622,13 +644,13 @@ public: protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_drop_proc_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_drop_proc_failed) << name.toQuotedString(); } public: - MetaName name; + QualifiedName name; bool silent; - MetaName package; + bool recreate = false; }; @@ -669,8 +691,8 @@ protected: } public: - MetaName name; - MetaName relationName; + QualifiedName name; + QualifiedName relationName; std::optional type; Firebird::TriState active; std::optional position; @@ -687,7 +709,7 @@ public: class CreateAlterTriggerNode : public DdlNode, public TriggerDefinition { public: - CreateAlterTriggerNode(MemoryPool& p, const MetaName& aName) + CreateAlterTriggerNode(MemoryPool& p, const QualifiedName& aName) : DdlNode(p), TriggerDefinition(p), create(true), @@ -713,7 +735,7 @@ protected: Firebird::Arg::Gds(createAlterCode(create, alter, isc_dsql_create_trigger_failed, isc_dsql_alter_trigger_failed, isc_dsql_create_alter_trigger_failed)) << - name; + name.toQuotedString(); } virtual void preModify(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) @@ -721,7 +743,7 @@ protected: if (alter) { executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_ALTER_TRIGGER, name, NULL); + DDL_TRIGGER_ALTER_TRIGGER, name, {}); } } @@ -730,7 +752,7 @@ protected: if (alter) { executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, - DDL_TRIGGER_ALTER_TRIGGER, name, NULL); + DDL_TRIGGER_ALTER_TRIGGER, name, {}); } } @@ -768,7 +790,7 @@ public: class DropTriggerNode : public DdlNode { public: - DropTriggerNode(MemoryPool& p, const MetaName& aName) + DropTriggerNode(MemoryPool& p, const QualifiedName& aName) : DdlNode(p), name(p, aName), silent(false) @@ -784,24 +806,41 @@ public: protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_drop_trigger_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_drop_trigger_failed) << name.toQuotedString(); } public: - MetaName name; + QualifiedName name; bool silent; + bool recreate = false; }; -typedef RecreateNode - RecreateTriggerNode; +class RecreateTriggerNode : + public RecreateNode +{ +public: + using RecreateNode::RecreateNode; + +public: + DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) override + { + createNode->dsqlPass(dsqlScratch); + + if (dropNode.name.schema.isEmpty()) + dropNode.name.schema = createNode->name.schema; + + dropNode.dsqlPass(dsqlScratch); + + return DdlNode::dsqlPass(dsqlScratch); + } +}; class CreateCollationNode : public DdlNode { public: - CreateCollationNode(MemoryPool& p, const MetaName& aName, - const MetaName& aForCharSet) + CreateCollationNode(MemoryPool& p, const QualifiedName& aName, const QualifiedName& aForCharSet) : DdlNode(p), name(p, aName), forCharSet(p, aForCharSet), @@ -848,13 +887,13 @@ public: protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_create_collation_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_create_collation_failed) << name.toQuotedString(); } public: - MetaName name; - MetaName forCharSet; - MetaName fromName; + QualifiedName name; + QualifiedName forCharSet; + QualifiedName fromName; Firebird::string fromExternal; Firebird::UCharBuffer specificAttributes; bool createIfNotExistsOnly = false; @@ -870,7 +909,7 @@ private: class DropCollationNode : public DdlNode { public: - DropCollationNode(MemoryPool& p, const MetaName& aName) + DropCollationNode(MemoryPool& p, const QualifiedName& aName) : DdlNode(p), name(p, aName) { @@ -881,14 +920,23 @@ public: virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + dsqlScratch->qualifyExistingName(name, obj_collation); + protectSystemSchema(name.schema, obj_collation); + dsqlScratch->ddlSchema = name.schema; + + return DdlNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_drop_collation_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_drop_collation_failed) << name.toQuotedString(); } public: - MetaName name; + QualifiedName name; bool silent = false; }; @@ -896,11 +944,11 @@ public: class CreateDomainNode : public DdlNode { public: - CreateDomainNode(MemoryPool& p, ParameterClause* aNameType) + CreateDomainNode(MemoryPool& p, const QualifiedName& aName, dsql_fld* aType, ValueSourceClause* aDefaultClause) : DdlNode(p), - nameType(aNameType), - notNull(false), - check(NULL) + name(aName), + type(aType), + defaultClause(aDefaultClause) { } @@ -909,16 +957,29 @@ public: virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + dsqlScratch->qualifyNewName(name); + protectSystemSchema(name.schema, obj_collation); + dsqlScratch->ddlSchema = name.schema; + + type->resolve(dsqlScratch); + + return DdlNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_create_domain_failed) << nameType->name; + statusVector << Firebird::Arg::Gds(isc_dsql_create_domain_failed) << name.toQuotedString(); } public: - NestConst nameType; - bool notNull; + QualifiedName name; + NestConst type; + NestConst defaultClause; NestConst check; + bool notNull = false; bool createIfNotExistsOnly = false; }; @@ -926,13 +987,9 @@ public: class AlterDomainNode : public DdlNode { public: - AlterDomainNode(MemoryPool& p, const MetaName& aName) + AlterDomainNode(MemoryPool& p, const QualifiedName& aName) : DdlNode(p), name(p, aName), - dropConstraint(false), - dropDefault(false), - setConstraint(NULL), - setDefault(NULL), renameTo(p) { } @@ -942,62 +999,83 @@ public: static ULONG checkUpdateNumericType(const dyn_fld& origFld, const dyn_fld& newFld); static void getDomainType(thread_db* tdbb, jrd_tra* transaction, dyn_fld& dynFld); static void modifyLocalFieldIndex(thread_db* tdbb, jrd_tra* transaction, - const MetaName& relationName, const MetaName& fieldName, + const QualifiedName& relationName, const MetaName& fieldName, const MetaName& newFieldName); 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); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + dsqlScratch->qualifyExistingName(name, obj_field); + protectSystemSchema(name.schema, obj_field); + dsqlScratch->ddlSchema = name.schema; + + if (type) + type->resolve(dsqlScratch); + + return DdlNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_alter_domain_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_alter_domain_failed) << name.toQuotedString(); } private: void rename(thread_db* tdbb, jrd_tra* transaction, SSHORT dimensions); public: - MetaName name; - bool dropConstraint; - bool dropDefault; + QualifiedName name; NestConst setConstraint; NestConst setDefault; MetaName renameTo; Firebird::AutoPtr type; Firebird::TriState notNullFlag; // true = NOT NULL / false = NULL + bool dropConstraint = false; + bool dropDefault = false; }; class DropDomainNode : public DdlNode { public: - DropDomainNode(MemoryPool& p, const MetaName& aName) + DropDomainNode(MemoryPool& p, const QualifiedName& aName) : DdlNode(p), name(p, aName) { } static bool deleteDimensionRecords(thread_db* tdbb, jrd_tra* transaction, - const MetaName& name); + const QualifiedName& name); 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); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + dsqlScratch->qualifyExistingName(name, obj_field); + protectSystemSchema(name.schema, obj_field); + dsqlScratch->ddlSchema = name.schema; + + return DdlNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_drop_domain_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_drop_domain_failed) << name.toQuotedString(); } private: void check(thread_db* tdbb, jrd_tra* transaction); public: - MetaName name; + QualifiedName name; bool silent = false; }; @@ -1005,7 +1083,7 @@ public: class CreateAlterExceptionNode : public DdlNode { public: - CreateAlterExceptionNode(MemoryPool& p, const MetaName& aName, + CreateAlterExceptionNode(MemoryPool& p, const QualifiedName& aName, const Firebird::string& aMessage) : DdlNode(p), name(p, aName), @@ -1020,6 +1098,19 @@ public: virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + if (create) + dsqlScratch->qualifyNewName(name); + else + dsqlScratch->qualifyExistingName(name, obj_exception); + + protectSystemSchema(name.schema, obj_exception); + dsqlScratch->ddlSchema = name.schema; + + return DdlNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { @@ -1027,7 +1118,7 @@ protected: Firebird::Arg::Gds(createAlterCode(create, alter, isc_dsql_create_except_failed, isc_dsql_alter_except_failed, isc_dsql_create_alter_except_failed)) << - name; + name.toQuotedString(); } private: @@ -1035,7 +1126,7 @@ private: bool executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); public: - MetaName name; + QualifiedName name; Firebird::string message; bool create; bool alter; @@ -1046,7 +1137,7 @@ public: class DropExceptionNode : public DdlNode { public: - DropExceptionNode(MemoryPool& p, const MetaName& aName) + DropExceptionNode(MemoryPool& p, const QualifiedName& aName) : DdlNode(p), name(p, aName), silent(false) @@ -1058,15 +1149,29 @@ public: virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + if (recreate) + dsqlScratch->qualifyNewName(name); + else + dsqlScratch->qualifyExistingName(name, obj_exception); + + protectSystemSchema(name.schema, obj_exception); + dsqlScratch->ddlSchema = name.schema; + + return DdlNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_drop_except_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_drop_except_failed) << name.toQuotedString(); } public: - MetaName name; + QualifiedName name; bool silent; + bool recreate = false; }; @@ -1077,7 +1182,7 @@ typedef RecreateNodegetDsqlStatement()->setType( - legacy ? DsqlStatement::TYPE_SET_GENERATOR : DsqlStatement::TYPE_DDL); + if (create) + dsqlScratch->qualifyNewName(name); + else + dsqlScratch->qualifyExistingName(name, obj_generator); + + if (!restartSpecified) + protectSystemSchema(name.schema, obj_generator); + + dsqlScratch->ddlSchema = name.schema; + + dsqlScratch->getDsqlStatement()->setType(legacy ? DsqlStatement::TYPE_SET_GENERATOR : DsqlStatement::TYPE_DDL); + return this; } @@ -1127,7 +1242,7 @@ public: bool createIfNotExistsOnly = false; bool legacy; bool restartSpecified; - const MetaName name; + QualifiedName name; std::optional value; std::optional step; }; @@ -1136,30 +1251,43 @@ public: class DropSequenceNode : public DdlNode { public: - DropSequenceNode(MemoryPool& pool, const MetaName& aName) + DropSequenceNode(MemoryPool& pool, const QualifiedName& aName) : DdlNode(pool), name(pool, aName), silent(false) { } - static void deleteIdentity(thread_db* tdbb, jrd_tra* transaction, - const MetaName& name); + static void deleteIdentity(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& name); 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); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + if (recreate) + dsqlScratch->qualifyNewName(name); + else + dsqlScratch->qualifyExistingName(name, obj_generator); + + protectSystemSchema(name.schema, obj_generator); + dsqlScratch->ddlSchema = name.schema; + + return DdlNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_drop_sequence_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_drop_sequence_failed) << name.toQuotedString(); } public: - MetaName name; + QualifiedName name; bool silent; + bool recreate = false; }; @@ -1188,9 +1316,9 @@ public: public: MetaName name; - MetaName relationName; - MetaName fieldSource; - MetaName identitySequence; + QualifiedName relationName; + QualifiedName fieldSource; + QualifiedName identitySequence; std::optional identityType; std::optional collationId; Firebird::TriState notNullFlag; // true = NOT NULL / false = NULL @@ -1260,7 +1388,7 @@ public: Constraint::Type type; Firebird::ObjectsArray columns; NestConst index; - MetaName refRelation; + QualifiedName refRelation; Firebird::ObjectsArray refColumns; const char* refUpdateAction; const char* refDeleteAction; @@ -1349,7 +1477,7 @@ public: ConstraintType constraintType; Firebird::ObjectsArray columns; NestConst index; - MetaName refRelation; + QualifiedName refRelation; Firebird::ObjectsArray refColumns; NestConst refAction; NestConst check; @@ -1392,7 +1520,7 @@ public: dsql_fld* field; NestConst defaultValue; Firebird::ObjectsArray constraints; - MetaName collate; + QualifiedName collate; NestConst computed; NestConst identityOptions; bool notNullSpecified; @@ -1487,13 +1615,16 @@ public: RelationNode(MemoryPool& p, RelationSourceNode* aDsqlNode); static bool deleteLocalField(thread_db* tdbb, jrd_tra* transaction, - const MetaName& relationName, const MetaName& fieldName, bool silent, + const QualifiedName& relationName, const MetaName& fieldName, bool silent, std::function preChangeHandler = {}); static void addToPublication(thread_db* tdbb, jrd_tra* transaction, - const MetaName& tableName, const MetaName& pubTame); + const QualifiedName& tableName, const MetaName& pubName); static void dropFromPublication(thread_db* tdbb, jrd_tra* transaction, - const MetaName& tableName, const MetaName& pubTame); + const QualifiedName& tableName, const MetaName& pubName); + +public: + DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); protected: virtual Firebird::string internalPrint(NodePrinter& printer) const @@ -1535,7 +1666,7 @@ protected: public: NestConst dsqlNode; - MetaName name; + QualifiedName name; Firebird::Array > clauses; Firebird::TriState ssDefiner; Firebird::TriState replicationState; @@ -1557,10 +1688,19 @@ public: virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + dsqlScratch->qualifyNewName(name); + protectSystemSchema(name.schema, obj_relation); + dsqlScratch->ddlSchema = name.schema; + + return RelationNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_create_table_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_create_table_failed) << name.toQuotedString(); } private: @@ -1583,6 +1723,15 @@ public: { } + DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + dsqlScratch->qualifyExistingName(name, obj_relation); + protectSystemSchema(name.schema, obj_relation); + dsqlScratch->ddlSchema = name.schema; + + return RelationNode::dsqlPass(dsqlScratch); + } + public: virtual Firebird::string internalPrint(NodePrinter& printer) const; virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction); @@ -1591,7 +1740,7 @@ public: protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_alter_table_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_alter_table_failed) << name.toQuotedString(); } private: @@ -1603,7 +1752,7 @@ private: class DropRelationNode : public DdlNode { public: - DropRelationNode(MemoryPool& p, const MetaName& aName, bool aView = false) + DropRelationNode(MemoryPool& p, const QualifiedName& aName, bool aView = false) : DdlNode(p), name(p, aName), view(aView), @@ -1611,25 +1760,38 @@ public: { } - static void deleteGlobalField(thread_db* tdbb, jrd_tra* transaction, - const MetaName& globalName); + static void deleteGlobalField(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& globalName); 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); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + if (recreate) + dsqlScratch->qualifyNewName(name); + else + dsqlScratch->qualifyExistingName(name, (view ? obj_view : obj_relation)); + + protectSystemSchema(name.schema, (view ? obj_view : obj_relation)); + dsqlScratch->ddlSchema = name.schema; + + return DdlNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(view ? isc_dsql_drop_view_failed : - isc_dsql_drop_table_failed) << name; + statusVector << Firebird::Arg::Gds(view ? isc_dsql_drop_view_failed : isc_dsql_drop_table_failed) << + name.toQuotedString(); } public: - MetaName name; + QualifiedName name; bool view; bool silent; + bool recreate = false; }; @@ -1665,7 +1827,7 @@ protected: Firebird::Arg::Gds(createAlterCode(create, alter, isc_dsql_create_view_failed, isc_dsql_alter_view_failed, isc_dsql_create_alter_view_failed)) << - name; + name.toQuotedString(); } private: @@ -1710,7 +1872,7 @@ public: conditionSource.clear(); } - MetaName relation; + QualifiedName relation; Firebird::ObjectsArray columns; Firebird::TriState unique; Firebird::TriState descending; @@ -1720,34 +1882,35 @@ public: bid expressionSource; bid conditionBlr; bid conditionSource; - MetaName refRelation; + QualifiedName refRelation; Firebird::ObjectsArray refColumns; }; public: - CreateIndexNode(MemoryPool& p, const MetaName& aName) + CreateIndexNode(MemoryPool& p, const QualifiedName& aName) : DdlNode(p), name(p, aName) { } public: - static void store(thread_db* tdbb, jrd_tra* transaction, MetaName& name, - const Definition& definition, MetaName* referredIndexName = nullptr); + static void store(thread_db* tdbb, jrd_tra* transaction, QualifiedName& name, + const Definition& definition, QualifiedName* referredIndexName = nullptr); 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); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_create_index_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_create_index_failed) << name.toQuotedString(); } public: - MetaName name; + QualifiedName name; bool unique = false; bool descending = false; bool active = true; @@ -1762,7 +1925,7 @@ public: class AlterIndexNode : public DdlNode { public: - AlterIndexNode(MemoryPool& p, const MetaName& aName, bool aActive) + AlterIndexNode(MemoryPool& p, const QualifiedName& aName, bool aActive) : DdlNode(p), name(p, aName), active(aActive) @@ -1774,14 +1937,22 @@ public: virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + dsqlScratch->qualifyExistingName(name, obj_index); + dsqlScratch->ddlSchema = name.schema; + + return DdlNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_alter_index_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_alter_index_failed) << name.toQuotedString(); } public: - MetaName name; + QualifiedName name; bool active; }; @@ -1789,7 +1960,7 @@ public: class SetStatisticsNode : public DdlNode { public: - SetStatisticsNode(MemoryPool& p, const MetaName& aName) + SetStatisticsNode(MemoryPool& p, const QualifiedName& aName) : DdlNode(p), name(p, aName) { @@ -1800,43 +1971,58 @@ public: virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + dsqlScratch->qualifyExistingName(name, obj_index); + dsqlScratch->ddlSchema = name.schema; + + return DdlNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { // ASF: using ALTER INDEX's code. - statusVector << Firebird::Arg::Gds(isc_dsql_alter_index_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_alter_index_failed) << name.toQuotedString(); } public: - MetaName name; + QualifiedName name; }; class DropIndexNode : public DdlNode { public: - DropIndexNode(MemoryPool& p, const MetaName& aName) + DropIndexNode(MemoryPool& p, const QualifiedName& aName) : DdlNode(p), name(p, aName) { } - static bool deleteSegmentRecords(thread_db* tdbb, jrd_tra* transaction, - const MetaName& name); + static bool deleteSegmentRecords(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& name); 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); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + dsqlScratch->qualifyExistingName(name, obj_index); + dsqlScratch->ddlSchema = name.schema; + + return DdlNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_drop_index_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_drop_index_failed) << name.toQuotedString(); } public: - MetaName name; + QualifiedName name; bool silent = false; }; @@ -1877,8 +2063,6 @@ public: CreateFilterNode(MemoryPool& p, const MetaName& aName) : DdlNode(p), name(p, aName), - inputFilter(NULL), - outputFilter(NULL), entryPoint(p), moduleName(p) { @@ -2253,6 +2437,7 @@ public: const MetaName name; MetaName plugin; bool silent; + bool recreate = false; }; @@ -2270,8 +2455,8 @@ typedef RecreateNode > PrivilegeClause; -typedef Firebird::Pair > GranteeClause; +typedef Firebird::NonPooledPair*> PrivilegeClause; +typedef Firebird::NonPooledPair GranteeClause; class GrantRevokeNode : public PrivilegesNode, private ExecInSecurityDb { @@ -2296,6 +2481,77 @@ public: virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + Firebird::Array grantees; + + if (object) + grantees.add(object); + + for (auto& user : users) + grantees.add(&user); + + for (auto grantee : grantees) + { + switch (grantee->first) + { + case obj_charset: + case obj_collation: + case obj_exception: + case obj_field: + case obj_generator: + case obj_index: + case obj_package_header: + case obj_procedure: + case obj_relation: + case obj_view: + case obj_trigger: + case obj_udf: + dsqlScratch->qualifyExistingName(grantee->second, grantee->first); + break; + + case obj_database: + case obj_schema: + case obj_user: + case obj_user_or_role: + case obj_sql_role: + case obj_privilege: + case obj_roles: + case obj_filters: + case obj_jobs: + case obj_tablespaces: + case obj_schemas: + break; + + case obj_relations: + case obj_views: + case obj_procedures: + case obj_functions: + case obj_packages: + case obj_generators: + case obj_domains: + case obj_exceptions: + case obj_charsets: + case obj_collations: + fb_assert(grantee->second.object.hasData()); + + if (grantee->second.schema.isEmpty()) + { + fb_assert(grantee->second.object.hasData()); + dsqlScratch->qualifyNewName(grantee->second); + } + + break; + + default: + fb_assert(false); + break; + } + } + + return PrivilegesNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { @@ -2309,20 +2565,20 @@ private: void grantRevoke(thread_db* tdbb, jrd_tra* transaction, const GranteeClause* object, const GranteeClause* userNod, const char* privs, MetaName field, int options); static void checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* transaction, const char* grantor, - const char* privilege, const MetaName& relationName, + const char* privilege, const QualifiedName& relationName, const MetaName& fieldName, bool topLevel); static void checkGrantorCanGrantRole(thread_db* tdbb, jrd_tra* transaction, const MetaName& grantor, const MetaName& roleName); static void checkGrantorCanGrantDdl(thread_db* tdbb, jrd_tra* transaction, - const MetaName& grantor, const char* privilege, const MetaName& objName); + const MetaName& grantor, const char* privilege, const QualifiedName& objName); static void checkGrantorCanGrantObject(thread_db* tdbb, jrd_tra* transaction, const char* grantor, - const char* privilege, const MetaName& objName, SSHORT objType); + const char* privilege, const QualifiedName& objName, SSHORT objType); static void storePrivilege(thread_db* tdbb, jrd_tra* transaction, - const MetaName& object, const MetaName& user, + const QualifiedName& object, const QualifiedName& user, const MetaName& field, const TEXT* privilege, SSHORT userType, SSHORT objType, int option, const MetaName& grantor); static void setFieldClassName(thread_db* tdbb, jrd_tra* transaction, - const MetaName& relation, const MetaName& field); + const QualifiedName& relation, const MetaName& field); // Diagnostics print helper. static const char* privilegeName(char symbol) @@ -2404,6 +2660,12 @@ public: public: virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) { + dsqlScratch->qualifyExistingName(setDefaultCharSet, obj_charset); + dsqlScratch->qualifyExistingName(setDefaultCollation, obj_collation); + + for (auto& pubTable : pubTables) + dsqlScratch->qualifyExistingName(pubTable, obj_relation); + dsqlScratch->getDsqlStatement()->setType( create ? DsqlStatement::TYPE_CREATE_DB : DsqlStatement::TYPE_DDL); return this; @@ -2434,15 +2696,92 @@ public: SLONG linger = -1; unsigned clauses = 0; Firebird::string differenceFile; - MetaName setDefaultCharSet; - MetaName setDefaultCollation; + QualifiedName setDefaultCharSet; + QualifiedName setDefaultCollation; MetaName cryptPlugin; MetaName keyName; Firebird::TriState ssDefiner; - Firebird::Array pubTables; + Firebird::Array pubTables; }; +class CreateAlterSchemaNode : public DdlNode +{ +public: + CreateAlterSchemaNode(MemoryPool& pool, const MetaName& aName) + : DdlNode(pool), + name(pool, aName), + setDefaultCharSet(pool), + owner(pool) + { + } + +public: + DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) override; + Firebird::string internalPrint(NodePrinter& printer) const override; + void checkPermission(thread_db* tdbb, jrd_tra* transaction) override; + void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) override; + +protected: + void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) override + { + statusVector << + Firebird::Arg::Gds(createAlterCode(create, alter, + isc_dsql_create_schema_failed, isc_dsql_alter_schema_failed, + isc_dsql_create_alter_schema_failed)) << + name.toQuotedString(); + } + +private: + void executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + bool executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + +public: + MetaName name; + bool create = true; + bool alter = false; + bool createIfNotExistsOnly = false; + QualifiedName setDefaultCharSet; + +private: + MetaName owner; +}; + + +class DropSchemaNode : public DdlNode +{ +public: + DropSchemaNode(MemoryPool& pool, const MetaName& aName) + : DdlNode(pool), + name(pool, aName) + { + } + +public: + Firebird::string internalPrint(NodePrinter& printer) const override; + void checkPermission(thread_db* tdbb, jrd_tra* transaction) override; + void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) override; + +protected: + void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) override + { + statusVector << Firebird::Arg::Gds(isc_dsql_drop_schema_failed) << name.toQuotedString(); + } + +private: + bool collectObjects(thread_db* tdbb, jrd_tra* transaction, + Firebird::Array>* objects = nullptr); + +public: + MetaName name; + bool silent = false; + bool recreate = false; +}; + + +using RecreateSchemaNode = RecreateNode; + + } // namespace #endif // DSQL_DDL_NODES_H diff --git a/src/dsql/DsqlCompilerScratch.cpp b/src/dsql/DsqlCompilerScratch.cpp index 586dfdb9ee..98242a8032 100644 --- a/src/dsql/DsqlCompilerScratch.cpp +++ b/src/dsql/DsqlCompilerScratch.cpp @@ -52,8 +52,8 @@ void DsqlCompilerScratch::dumpContextStack(const DsqlContextStack* stack) context->ctx_context, (context->ctx_flags & CTX_system) != 0, (context->ctx_flags & CTX_returning) != 0, - MAX_SQL_IDENTIFIER_SIZE, MAX_SQL_IDENTIFIER_SIZE, context->ctx_alias.c_str(), - MAX_SQL_IDENTIFIER_SIZE, MAX_SQL_IDENTIFIER_SIZE, context->ctx_internal_alias.c_str()); + MAX_SQL_IDENTIFIER_SIZE, MAX_SQL_IDENTIFIER_SIZE, context->ctx_alias[0].toQuotedString().c_str(), + MAX_SQL_IDENTIFIER_SIZE, MAX_SQL_IDENTIFIER_SIZE, context->ctx_internal_alias.toQuotedString().c_str()); } } #endif @@ -99,40 +99,88 @@ void DsqlCompilerScratch::putDtype(const TypeClause* field, bool useSubType) if (field->notNull) appendUChar(blr_not_nullable); - if (field->typeOfName.hasData()) + if (field->typeOfName.object.hasData()) { - if (field->typeOfTable.hasData()) + if (field->typeOfTable.object.hasData()) { if (field->explicitCollation) { - appendUChar(blr_column_name2); - appendUChar(field->fullDomain ? blr_domain_full : blr_domain_type_of); - appendMetaString(field->typeOfTable.c_str()); - appendMetaString(field->typeOfName.c_str()); - appendUShort(field->textType); + if (field->typeOfTable.schema != ddlSchema) + { + appendUChar(blr_column_name3); + appendUChar(field->fullDomain ? blr_domain_full : blr_domain_type_of); + appendMetaString(field->typeOfTable.schema.c_str()); + appendMetaString(field->typeOfTable.object.c_str()); + appendMetaString(field->typeOfName.object.c_str()); + appendUChar(1); + appendUShort(field->textType); + } + else + { + appendUChar(blr_column_name2); + appendUChar(field->fullDomain ? blr_domain_full : blr_domain_type_of); + appendMetaString(field->typeOfTable.object.c_str()); + appendMetaString(field->typeOfName.object.c_str()); + appendUShort(field->textType); + } } else { - appendUChar(blr_column_name); - appendUChar(field->fullDomain ? blr_domain_full : blr_domain_type_of); - appendMetaString(field->typeOfTable.c_str()); - appendMetaString(field->typeOfName.c_str()); + if (field->typeOfTable.schema != ddlSchema) + { + appendUChar(blr_column_name3); + appendUChar(field->fullDomain ? blr_domain_full : blr_domain_type_of); + appendMetaString(field->typeOfTable.schema.c_str()); + appendMetaString(field->typeOfTable.object.c_str()); + appendMetaString(field->typeOfName.object.c_str()); + appendUChar(0); + } + else + { + appendUChar(blr_column_name); + appendUChar(field->fullDomain ? blr_domain_full : blr_domain_type_of); + appendMetaString(field->typeOfTable.object.c_str()); + appendMetaString(field->typeOfName.object.c_str()); + } } } else { if (field->explicitCollation) { - appendUChar(blr_domain_name2); - appendUChar(field->fullDomain ? blr_domain_full : blr_domain_type_of); - appendMetaString(field->typeOfName.c_str()); - appendUShort(field->textType); + if (field->typeOfName.schema != ddlSchema) + { + appendUChar(blr_domain_name3); + appendUChar(field->fullDomain ? blr_domain_full : blr_domain_type_of); + appendMetaString(field->typeOfName.schema.c_str()); + appendMetaString(field->typeOfName.object.c_str()); + appendUChar(1); + appendUShort(field->textType); + } + else + { + appendUChar(blr_domain_name2); + appendUChar(field->fullDomain ? blr_domain_full : blr_domain_type_of); + appendMetaString(field->typeOfName.object.c_str()); + appendUShort(field->textType); + } } else { - appendUChar(blr_domain_name); - appendUChar(field->fullDomain ? blr_domain_full : blr_domain_type_of); - appendMetaString(field->typeOfName.c_str()); + if (field->typeOfName.schema != ddlSchema) + { + appendUChar(blr_domain_name3); + appendUChar(field->fullDomain ? blr_domain_full : blr_domain_type_of); + appendMetaString(field->typeOfName.schema.c_str()); + appendMetaString(field->typeOfName.object.c_str()); + appendUChar(0); + } + else + { + appendUChar(blr_domain_name); + appendUChar(field->fullDomain ? blr_domain_full : blr_domain_type_of); + appendMetaString(field->typeOfName.object.c_str()); + } } } @@ -199,40 +247,88 @@ void DsqlCompilerScratch::putType(const TypeClause* type, bool useSubType) if (type->notNull) appendUChar(blr_not_nullable); - if (type->typeOfName.hasData()) + if (type->typeOfName.object.hasData()) { - if (type->typeOfTable.hasData()) + if (type->typeOfTable.object.hasData()) { - if (type->collate.hasData()) + if (type->collate.object.hasData()) { - appendUChar(blr_column_name2); - appendUChar(type->fullDomain ? blr_domain_full : blr_domain_type_of); - appendMetaString(type->typeOfTable.c_str()); - appendMetaString(type->typeOfName.c_str()); - appendUShort(type->textType); + if (type->typeOfTable.schema != ddlSchema) + { + appendUChar(blr_column_name3); + appendUChar(type->fullDomain ? blr_domain_full : blr_domain_type_of); + appendMetaString(type->typeOfTable.schema.c_str()); + appendMetaString(type->typeOfTable.object.c_str()); + appendMetaString(type->typeOfName.object.c_str()); + appendUChar(1); + appendUShort(type->textType); + } + else + { + appendUChar(blr_column_name2); + appendUChar(type->fullDomain ? blr_domain_full : blr_domain_type_of); + appendMetaString(type->typeOfTable.object.c_str()); + appendMetaString(type->typeOfName.object.c_str()); + appendUShort(type->textType); + } } else { - appendUChar(blr_column_name); - appendUChar(type->fullDomain ? blr_domain_full : blr_domain_type_of); - appendMetaString(type->typeOfTable.c_str()); - appendMetaString(type->typeOfName.c_str()); + if (type->typeOfTable.schema != ddlSchema) + { + appendUChar(blr_column_name3); + appendUChar(type->fullDomain ? blr_domain_full : blr_domain_type_of); + appendMetaString(type->typeOfTable.schema.c_str()); + appendMetaString(type->typeOfTable.object.c_str()); + appendMetaString(type->typeOfName.object.c_str()); + appendUChar(0); + } + else + { + appendUChar(blr_column_name); + appendUChar(type->fullDomain ? blr_domain_full : blr_domain_type_of); + appendMetaString(type->typeOfTable.object.c_str()); + appendMetaString(type->typeOfName.object.c_str()); + } } } else { - if (type->collate.hasData()) + if (type->collate.object.hasData()) { - appendUChar(blr_domain_name2); - appendUChar(type->fullDomain ? blr_domain_full : blr_domain_type_of); - appendMetaString(type->typeOfName.c_str()); - appendUShort(type->textType); + if (type->typeOfName.schema != ddlSchema) + { + appendUChar(blr_domain_name3); + appendUChar(type->fullDomain ? blr_domain_full : blr_domain_type_of); + appendMetaString(type->typeOfName.schema.c_str()); + appendMetaString(type->typeOfName.object.c_str()); + appendUChar(1); + appendUShort(type->textType); + } + else + { + appendUChar(blr_domain_name2); + appendUChar(type->fullDomain ? blr_domain_full : blr_domain_type_of); + appendMetaString(type->typeOfName.object.c_str()); + appendUShort(type->textType); + } } else { - appendUChar(blr_domain_name); - appendUChar(type->fullDomain ? blr_domain_full : blr_domain_type_of); - appendMetaString(type->typeOfName.c_str()); + if (type->typeOfName.schema != ddlSchema) + { + appendUChar(blr_domain_name3); + appendUChar(type->fullDomain ? blr_domain_full : blr_domain_type_of); + appendMetaString(type->typeOfName.schema.c_str()); + appendMetaString(type->typeOfName.object.c_str()); + appendUChar(0); + } + else + { + appendUChar(blr_domain_name); + appendUChar(type->fullDomain ? blr_domain_full : blr_domain_type_of); + appendMetaString(type->typeOfName.object.c_str()); + } } } @@ -285,7 +381,7 @@ void DsqlCompilerScratch::putType(const TypeClause* type, bool useSubType) // Write out local variable field data type. void DsqlCompilerScratch::putLocalVariableDecl(dsql_var* variable, DeclareVariableNode* hostParam, - const MetaName& collationName) + QualifiedName& collationName) { const auto field = variable->field; @@ -476,14 +572,14 @@ void DsqlCompilerScratch::genParameters(Array >& para for (FB_SIZE_T i = 0; i < parameters.getCount(); ++i) { ParameterClause* parameter = parameters[i]; - putDebugArgument(fb_dbg_arg_input, i, parameter->name.c_str()); + putDebugArgument(fb_dbg_arg_input, i, parameter->name.c_str()); // TODO: ? putType(parameter->type, true); // Add slot for null flag (parameter2). appendUChar(blr_short); appendUChar(0); - makeVariable(parameter->type, parameter->name.c_str(), + makeVariable(parameter->type, parameter->name.c_str(), // TODO: ? dsql_var::TYPE_INPUT, 0, (USHORT) (2 * i), 0); } } @@ -498,14 +594,14 @@ void DsqlCompilerScratch::genParameters(Array >& para for (FB_SIZE_T i = 0; i < returns.getCount(); ++i) { ParameterClause* parameter = returns[i]; - putDebugArgument(fb_dbg_arg_output, i, parameter->name.c_str()); + putDebugArgument(fb_dbg_arg_output, i, parameter->name.c_str()); // TODO: ? putType(parameter->type, true); // Add slot for null flag (parameter2). appendUChar(blr_short); appendUChar(0); - makeVariable(parameter->type, parameter->name.c_str(), + makeVariable(parameter->type, parameter->name.c_str(), // TODO: ? dsql_var::TYPE_OUTPUT, 1, (USHORT) (2 * i), i); } } @@ -540,7 +636,7 @@ void DsqlCompilerScratch::addCTEs(WithClause* withClause) // Add CTE name into CTE aliases stack. It allows later to search for // aliases of given CTE. - addCTEAlias((*cte)->alias); + addCTEAlias((*cte)->alias.c_str()); } else ctes.add(*cte); @@ -932,12 +1028,12 @@ RseNode* DsqlCompilerScratch::pass1RseIsRecursive(RseNode* input) // Check if table reference is recursive i.e. its name is equal to the name of current processing CTE. bool DsqlCompilerScratch::pass1RelProcIsRecursive(RecordSourceNode* input) { - MetaName relName; + QualifiedName relName; string relAlias; if (auto procNode = nodeAs(input)) { - relName = procNode->dsqlName.identifier; + relName = procNode->dsqlName; relAlias = procNode->alias; } else if (auto relNode = nodeAs(input)) @@ -951,10 +1047,10 @@ bool DsqlCompilerScratch::pass1RelProcIsRecursive(RecordSourceNode* input) fb_assert(currCtes.hasData()); const SelectExprNode* currCte = currCtes.object(); - const bool recursive = currCte->alias == relName.c_str(); + const bool recursive = relName.schema.isEmpty() && currCte->alias == relName.object.c_str(); if (recursive) - addCTEAlias(relAlias.hasData() ? relAlias.c_str() : relName.c_str()); + addCTEAlias(relAlias.hasData() ? relAlias.c_str() : relName.object.c_str()); return recursive; } diff --git a/src/dsql/DsqlCompilerScratch.h b/src/dsql/DsqlCompilerScratch.h index 8755b7cb2d..a7e8ad81fc 100644 --- a/src/dsql/DsqlCompilerScratch.h +++ b/src/dsql/DsqlCompilerScratch.h @@ -96,6 +96,7 @@ public: mainScratch(aMainScratch), outerMessagesMap(p), outerVarsMap(p), + ddlSchema(p), ctes(p), cteAliases(p), subFunctions(p), @@ -151,16 +152,49 @@ public: dsqlStatement = aDsqlStatement; } + void qualifyNewName(QualifiedName& name) const + { + using namespace Firebird; + + const auto tdbb = JRD_get_thread_data(); + + if (!dbb->dbb_attachment->qualifyNewName(tdbb, name)) + { + if (name.schema.isEmpty()) + status_exception::raise(Arg::Gds(isc_dyn_cannot_infer_schema)); + else + status_exception::raise(Arg::Gds(isc_dyn_schema_not_found) << name.schema.toQuotedString()); + } + } + + void qualifyExistingName(QualifiedName& name, ObjectType objectType) const + { + if (!(name.schema.isEmpty() && name.object.hasData())) + return; + + const auto tdbb = JRD_get_thread_data(); + const auto attachment = tdbb->getAttachment(); + + if (ddlSchema.hasData()) + { + Firebird::ObjectsArray schemaSearchPath({ddlSchema, SYSTEM_SCHEMA}); + attachment->qualifyExistingName(tdbb, name, objectType, &schemaSearchPath); + } + else + attachment->qualifyExistingName(tdbb, name, objectType); + } + void putBlrMarkers(ULONG marks); void putDtype(const TypeClause* field, bool useSubType); void putType(const TypeClause* type, bool useSubType); - void putLocalVariableDecl(dsql_var* variable, DeclareVariableNode* hostParam, const MetaName& collationName); + void putLocalVariableDecl(dsql_var* variable, DeclareVariableNode* hostParam, QualifiedName& collationName); void putLocalVariableInit(dsql_var* variable, const DeclareVariableNode* hostParam); - void putLocalVariable(dsql_var* variable, DeclareVariableNode* hostParam, const MetaName& collationName) + void putLocalVariable(dsql_var* variable) { - putLocalVariableDecl(variable, hostParam, collationName); - putLocalVariableInit(variable, hostParam); + QualifiedName dummyCollationName; + putLocalVariableDecl(variable, nullptr, dummyCollationName); + putLocalVariableInit(variable, nullptr); } void putOuterMaps(); @@ -301,8 +335,8 @@ public: USHORT errorHandlers = 0; // count of active error handlers USHORT clientDialect = 0; // dialect passed into the API call USHORT inOuterJoin = 0; // processing inside outer-join part - Firebird::string aliasRelationPrefix; // prefix for every relation-alias. - MetaName package; // package being defined + Firebird::ObjectsArray aliasRelationPrefix; // prefix for every relation-alias. + QualifiedName package; // package being defined Firebird::Stack currCtes; // current processing CTE's dsql_ctx* recursiveCtx = nullptr; // context of recursive CTE USHORT recursiveCtxId = 0; // id of recursive union stream context @@ -317,6 +351,7 @@ public: DsqlCompilerScratch* mainScratch = nullptr; Firebird::NonPooledMap outerMessagesMap; // Firebird::NonPooledMap outerVarsMap; // + MetaName ddlSchema; private: Firebird::HalfStaticArray ctes; // common table expressions diff --git a/src/dsql/DsqlRequests.cpp b/src/dsql/DsqlRequests.cpp index cb68720f7e..9c95a2f241 100644 --- a/src/dsql/DsqlRequests.cpp +++ b/src/dsql/DsqlRequests.cpp @@ -1055,7 +1055,10 @@ void DsqlDdlRequest::execute(thread_db* tdbb, jrd_tra** traHandle, (internalScratch->flags & DsqlCompilerScratch::FLAG_INTERNAL_REQUEST); if (!isInternalRequest && node->mustBeReplicated()) - REPL_exec_sql(tdbb, req_transaction, getDsqlStatement()->getOrgText()); + { + REPL_exec_sql(tdbb, req_transaction, getDsqlStatement()->getOrgText(), + *getDsqlStatement()->getSchemaSearchPath()); + } } catch (status_exception& ex) { diff --git a/src/dsql/DsqlStatementCache.cpp b/src/dsql/DsqlStatementCache.cpp index 2ba98386a2..5d50e5cfab 100644 --- a/src/dsql/DsqlStatementCache.cpp +++ b/src/dsql/DsqlStatementCache.cpp @@ -259,16 +259,37 @@ void DsqlStatementCache::buildStatementKey(thread_db* tdbb, RefStrPtr& key, cons { const auto attachment = tdbb->getAttachment(); + const auto searchPathLen = std::accumulate( + attachment->att_schema_search_path->begin(), + attachment->att_schema_search_path->end(), + 0u, + [](const auto& len, const auto& pathItem) { + return len + pathItem.length() + 1u; + } + ); + const SSHORT charSetId = isInternalRequest ? CS_METADATA : attachment->att_charset; const int debugOptions = (int) attachment->getDebugOptions().getDsqlKeepBlr(); key = FB_NEW_POOL(getPool()) RefString(getPool()); + key->resize(1 + sizeof(charSetId) + text.length() + 1 + searchPathLen + 1); - key->resize(1 + sizeof(charSetId) + text.length()); char* p = key->begin(); - *p = (clientDialect << 2) | (int(isInternalRequest) << 1) | debugOptions; - memcpy(p + 1, &charSetId, sizeof(charSetId)); - memcpy(p + 1 + sizeof(charSetId), text.c_str(), text.length()); + *p++ = (clientDialect << 2) | (int(isInternalRequest) << 1) | debugOptions; + memcpy(p, &charSetId, sizeof(charSetId)); + p += sizeof(charSetId); + memcpy(p, text.c_str(), text.length() + 1); + p += text.length() + 1; + + for (const auto& pathItem : *attachment->att_schema_search_path) + { + memcpy(p, pathItem.c_str(), pathItem.length() + 1); + p += pathItem.length() + 1; + } + + *p = '\0'; + + fb_assert(p + 1 == key->end()); } void DsqlStatementCache::buildVerifyKey(thread_db* tdbb, string& key, bool isInternalRequest) diff --git a/src/dsql/DsqlStatements.cpp b/src/dsql/DsqlStatements.cpp index 47117b26a6..8741004cf1 100644 --- a/src/dsql/DsqlStatements.cpp +++ b/src/dsql/DsqlStatements.cpp @@ -36,6 +36,16 @@ using namespace Jrd; // Class DsqlStatement +DsqlStatement::DsqlStatement(MemoryPool& pool, dsql_dbb* aDsqlAttachment) + : PermanentStorage(pool), + dsqlAttachment(aDsqlAttachment), + ports(pool) +{ + pool.setStatsGroup(memoryStats); + + schemaSearchPath = dsqlAttachment->dbb_attachment->att_schema_search_path; +} + // Rethrow an exception with isc_no_meta_update and prefix codes. void DsqlStatement::rethrowDdlException(status_exception& ex, bool metadataUpdate, DdlNode* node) { @@ -80,6 +90,7 @@ int DsqlStatement::release() void DsqlStatement::doRelease() { + fb_assert(!cacheKey.hasData()); setSqlText(nullptr); setOrgText(nullptr, 0); diff --git a/src/dsql/DsqlStatements.h b/src/dsql/DsqlStatements.h index 1ab48fc986..15ba7d0d91 100644 --- a/src/dsql/DsqlStatements.h +++ b/src/dsql/DsqlStatements.h @@ -68,16 +68,7 @@ public: static void rethrowDdlException(Firebird::status_exception& ex, bool metadataUpdate, DdlNode* node); public: - DsqlStatement(MemoryPool& pool, dsql_dbb* aDsqlAttachment) - : PermanentStorage(pool), - dsqlAttachment(aDsqlAttachment), - type(TYPE_SELECT), - flags(0), - blrVersion(5), - ports(pool) - { - pool.setStatsGroup(memoryStats); - } + DsqlStatement(MemoryPool& pool, dsql_dbb* aDsqlAttachment); protected: virtual ~DsqlStatement() = default; @@ -139,6 +130,8 @@ public: void setCacheKey(Firebird::RefStrPtr& value) { cacheKey = value; } void resetCacheKey() { cacheKey = nullptr; } + const auto getSchemaSearchPath() const { return schemaSearchPath; } + public: virtual bool isDml() const { @@ -174,9 +167,9 @@ protected: protected: dsql_dbb* dsqlAttachment; Firebird::MemoryStats memoryStats; - Type type; // Type of statement - ULONG flags; // generic flag - unsigned blrVersion; + Type type = TYPE_SELECT; // Type of statement + ULONG flags = 0; // generic flag + unsigned blrVersion = 5; Firebird::RefStrPtr sqlText; Firebird::RefStrPtr orgText; Firebird::RefStrPtr cacheKey; @@ -185,6 +178,7 @@ protected: dsql_msg* receiveMsg = nullptr; // Per record message to be received dsql_par* eof = nullptr; // End of file parameter DsqlCompilerScratch* scratch = nullptr; + Firebird::RefPtr>> schemaSearchPath; private: Firebird::AtomicCounter refCounter; diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index 8320ab355b..17fc95f6fe 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -4007,7 +4007,7 @@ dsc* CoalesceNode::execute(thread_db* tdbb, Request* request) const //-------------------- -CollateNode::CollateNode(MemoryPool& pool, ValueExprNode* aArg, const MetaName& aCollation) +CollateNode::CollateNode(MemoryPool& pool, ValueExprNode* aArg, const QualifiedName& aCollation) : TypedNode(pool), arg(aArg), collation(pool, aCollation) @@ -4033,7 +4033,7 @@ ValueExprNode* CollateNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) } ValueExprNode* CollateNode::pass1Collate(DsqlCompilerScratch* dsqlScratch, ValueExprNode* input, - const MetaName& collation) + QualifiedName& collation) { thread_db* tdbb = JRD_get_thread_data(); MemoryPool& pool = *tdbb->getDefaultPool(); @@ -4735,6 +4735,98 @@ ValueExprNode* CurrentRoleNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) //-------------------- +static RegisterNode regCurrentSchemaNode({blr_current_schema}); + +DmlNode* CurrentSchemaNode::parse(thread_db* /*tdbb*/, MemoryPool& pool, CompilerScratch* /*csb*/, + const UCHAR /*blrOp*/) +{ + return FB_NEW_POOL(pool) CurrentSchemaNode(pool); +} + +string CurrentSchemaNode::internalPrint(NodePrinter& printer) const +{ + ValueExprNode::internalPrint(printer); + + return "CurrentSchemaNode"; +} + +void CurrentSchemaNode::setParameterName(dsql_par* parameter) const +{ + parameter->par_name = parameter->par_alias = "CURRENT_SCHEMA"; +} + +void CurrentSchemaNode::genBlr(DsqlCompilerScratch* dsqlScratch) +{ + dsqlScratch->appendUChar(blr_current_schema); +} + +void CurrentSchemaNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) +{ + desc->dsc_dtype = dtype_varying; + desc->dsc_scale = 0; + desc->dsc_flags = DSC_nullable; + desc->dsc_ttype() = ttype_metadata; + desc->dsc_length = MAX_SQL_IDENTIFIER_LEN + sizeof(USHORT); +} + +void CurrentSchemaNode::getDesc(thread_db* /*tdbb*/, CompilerScratch* /*csb*/, dsc* desc) +{ + desc->dsc_dtype = dtype_text; + desc->dsc_ttype() = ttype_metadata; + desc->dsc_length = MAX_SQL_IDENTIFIER_LEN; + desc->dsc_scale = 0; + desc->dsc_flags = DSC_nullable; +} + +ValueExprNode* CurrentSchemaNode::copy(thread_db* tdbb, NodeCopier& /*copier*/) const +{ + return FB_NEW_POOL(*tdbb->getDefaultPool()) CurrentSchemaNode(*tdbb->getDefaultPool()); +} + +ValueExprNode* CurrentSchemaNode::pass2(thread_db* tdbb, CompilerScratch* csb) +{ + ValueExprNode::pass2(tdbb, csb); + + dsc desc; + getDesc(tdbb, csb, &desc); + impureOffset = csb->allocImpure(); + + return this; +} + +dsc* CurrentSchemaNode::execute(thread_db* tdbb, Request* request) const +{ + const auto attachment = tdbb->getAttachment(); + + QualifiedName name; + attachment->qualifyNewName(tdbb, name); + + if (name.schema.hasData()) + { + const auto impure = request->getImpure(impureOffset); + + impure->vlu_desc.dsc_dtype = dtype_text; + impure->vlu_desc.dsc_sub_type = 0; + impure->vlu_desc.dsc_scale = 0; + impure->vlu_desc.setTextType(ttype_metadata); + + impure->vlu_desc.dsc_address = reinterpret_cast(const_cast(name.schema.c_str())); + impure->vlu_desc.dsc_length = static_cast(name.schema.length()); + return &impure->vlu_desc; + } + else + return nullptr; +} + +ValueExprNode* CurrentSchemaNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) +{ + return FB_NEW_POOL(dsqlScratch->getPool()) CurrentSchemaNode(dsqlScratch->getPool()); +} + + +//-------------------- + + static RegisterNode regCurrentUserNode({blr_user_name}); DmlNode* CurrentUserNode::parse(thread_db* /*tdbb*/, MemoryPool& pool, CompilerScratch* /*csb*/, @@ -5072,9 +5164,9 @@ dsc* DecodeNode::execute(thread_db* tdbb, Request* request) const //-------------------- -static RegisterNode regDefaultNode({blr_default}); +static RegisterNode regDefaultNode({blr_default, blr_default2}); -DefaultNode::DefaultNode(MemoryPool& pool, const MetaName& aRelationName, +DefaultNode::DefaultNode(MemoryPool& pool, const QualifiedName& aRelationName, const MetaName& aFieldName) : DsqlNode(pool), relationName(aRelationName), @@ -5083,10 +5175,17 @@ DefaultNode::DefaultNode(MemoryPool& pool, const MetaName& aRelationName, { } -DmlNode* DefaultNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR /*blrOp*/) +DmlNode* DefaultNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp) { - MetaName relationName, fieldName; - csb->csb_blr_reader.getMetaName(relationName); + QualifiedName relationName; + + if (blrOp == blr_default2) + csb->csb_blr_reader.getMetaName(relationName.schema); + + csb->csb_blr_reader.getMetaName(relationName.object); + csb->qualifyExistingName(tdbb, relationName, obj_relation); + + MetaName fieldName; csb->csb_blr_reader.getMetaName(fieldName); if (csb->collectingDependencies()) @@ -5113,7 +5212,7 @@ DmlNode* DefaultNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* if (fld) { - if (fld->fld_source_rel_field.first.hasData()) + if (fld->fld_source_rel_field.first.object.hasData()) { relationName = fld->fld_source_rel_field.first; fieldName = fld->fld_source_rel_field.second; @@ -5136,7 +5235,7 @@ DmlNode* DefaultNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* ValueExprNode* DefaultNode::createFromField(thread_db* tdbb, CompilerScratch* csb, StreamType* map, jrd_fld* fld) { - if (fld->fld_generator_name.hasData()) + if (fld->fld_generator_name.object.hasData()) { // Make a (next value for ) expression. @@ -5145,10 +5244,15 @@ ValueExprNode* DefaultNode::createFromField(thread_db* tdbb, CompilerScratch* cs bool sysGen = false; if (!MET_load_generator(tdbb, genNode->generator, &sysGen, &genNode->step)) - status_exception::raise(Arg::Gds(isc_gennotdef) << Arg::Str(fld->fld_generator_name)); + status_exception::raise(Arg::Gds(isc_gennotdef) << fld->fld_generator_name.toQuotedString()); if (sysGen) - status_exception::raise(Arg::Gds(isc_cant_modify_sysobj) << "generator" << fld->fld_generator_name); + { + status_exception::raise( + Arg::Gds(isc_cant_modify_sysobj) << + "generator" << + fld->fld_generator_name.toQuotedString()); + } return genNode; } @@ -5194,8 +5298,15 @@ bool DefaultNode::setParameterType(DsqlCompilerScratch* /*dsqlScratch*/, void DefaultNode::genBlr(DsqlCompilerScratch* dsqlScratch) { - dsqlScratch->appendUChar(blr_default); - dsqlScratch->appendMetaString(relationName.c_str()); + if (relationName.schema != dsqlScratch->ddlSchema) + { + dsqlScratch->appendUChar(blr_default2); + dsqlScratch->appendMetaString(relationName.schema.c_str()); + } + else + dsqlScratch->appendUChar(blr_default); + + dsqlScratch->appendMetaString(relationName.object.c_str()); dsqlScratch->appendMetaString(fieldName.c_str()); } @@ -5947,7 +6058,7 @@ DmlNode* FieldNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* cs const USHORT context = csb->csb_blr_reader.getByte(); // check if this is a VALUE of domain's check constraint - if (!csb->csb_domain_validation.isEmpty() && context == 0 && + if (!csb->csb_domain_validation.object.isEmpty() && context == 0 && (blrOp == blr_fid || blrOp == blr_field)) { if (blrOp == blr_fid) @@ -6024,7 +6135,7 @@ DmlNode* FieldNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* cs if ((id = PAR_find_proc_field(procedure, name)) == -1) { PAR_error(csb, Arg::Gds(isc_fldnotdef2) << - Arg::Str(name) << Arg::Str(procedure->getName().toString())); + Arg::Str(name) << Arg::Str(procedure->getName().toQuotedString())); } } else @@ -6056,12 +6167,12 @@ DmlNode* FieldNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* cs if (tdbb->getAttachment()->isGbak()) { PAR_warning(Arg::Warning(isc_fldnotdef) << Arg::Str(name) << - Arg::Str(relation->rel_name)); + relation->rel_name.toQuotedString()); } else if (!(relation->rel_flags & REL_deleted)) { PAR_error(csb, Arg::Gds(isc_fldnotdef) << Arg::Str(name) << - Arg::Str(relation->rel_name)); + relation->rel_name.toQuotedString()); } else PAR_error(csb, Arg::Gds(isc_ctxnotdef)); @@ -6129,7 +6240,7 @@ ValueExprNode* FieldNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) return this; } - if (dsqlScratch->isPsql() && !dsqlQualifier.hasData()) + if (dsqlScratch->isPsql() && dsqlQualifier.object.isEmpty()) { VariableNode* node = FB_NEW_POOL(dsqlScratch->getPool()) VariableNode(dsqlScratch->getPool()); node->line = line; @@ -6153,7 +6264,7 @@ ValueExprNode* FieldNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, Rec thread_db* tdbb = JRD_get_thread_data(); if (list) - *list = NULL; + *list = nullptr; /* CVC: PLEASE READ THIS EXPLANATION IF YOU NEED TO CHANGE THIS CODE. You should ensure that this function: @@ -6213,7 +6324,7 @@ ValueExprNode* FieldNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, Rec dsql_ctx* context = stack.object(); if (context->ctx_scope_level != currentScopeLevel - 1 || - ((context->ctx_flags & CTX_cursor) && dsqlQualifier.isEmpty()) || + ((context->ctx_flags & CTX_cursor) && dsqlQualifier.object.isEmpty()) || (!(context->ctx_flags & CTX_cursor) && dsqlCursorField)) { continue; @@ -6229,31 +6340,33 @@ ValueExprNode* FieldNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, Rec { // If there's no name then we have most probable an asterisk that // needs to be exploded. This should be handled by the caller and - // when the caller can handle this, list is true. + // when the caller can handle this, list is not nullptr. if (dsqlName.isEmpty()) { if (list) { - dsql_ctx* stackContext = stack.object(); + ambiguousCtxStack.push(context); + // FIXME: "Ambiguous field name between table @1 and table @2" is wrong here + PASS1_ambiguity_check(dsqlScratch, dsqlName, ambiguousCtxStack); if (context->ctx_relation) { RelationSourceNode* relNode = FB_NEW_POOL(*tdbb->getDefaultPool()) RelationSourceNode(*tdbb->getDefaultPool()); - relNode->dsqlContext = stackContext; + relNode->dsqlContext = context; *list = relNode; } else if (context->ctx_procedure) { ProcedureSourceNode* procNode = FB_NEW_POOL(*tdbb->getDefaultPool()) ProcedureSourceNode(*tdbb->getDefaultPool()); - procNode->dsqlContext = stackContext; + procNode->dsqlContext = context; *list = procNode; } //// TODO: LocalTableSourceNode fb_assert(*list); - return NULL; + continue; } break; @@ -6265,7 +6378,7 @@ ValueExprNode* FieldNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, Rec { if (field->fld_name == dsqlName.c_str()) { - if (dsqlQualifier.isEmpty()) + if (dsqlQualifier.object.isEmpty()) { if (!context->getImplicitJoinField(field->fld_name, usingField)) { @@ -6290,7 +6403,7 @@ ValueExprNode* FieldNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, Rec node->column = column; ***/ } - else if (dsqlQualifier.hasData() && !field) + else if (dsqlQualifier.object.hasData() && !field) { if (!(context->ctx_flags & CTX_view_with_check_modify)) { @@ -6334,11 +6447,14 @@ ValueExprNode* FieldNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, Rec { // if an qualifier is present check if we have the same derived // table else continue; - if (dsqlQualifier.hasData()) + if (dsqlQualifier.object.hasData()) { if (context->ctx_alias.hasData()) { - if (dsqlQualifier != context->ctx_alias) + // FIXME: + fb_assert(context->ctx_alias.getCount() == 1); + + if (dsqlQualifier != context->ctx_alias[0]) continue; } else @@ -6373,7 +6489,7 @@ ValueExprNode* FieldNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, Rec { NestConst usingField = NULL; - if (dsqlQualifier.isEmpty()) + if (dsqlQualifier.object.isEmpty()) { if (!context->getImplicitJoinField(dsqlName, usingField)) break; @@ -6401,7 +6517,7 @@ ValueExprNode* FieldNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, Rec } } - if (!node && dsqlQualifier.hasData()) + if (!node && dsqlQualifier.object.hasData()) { // If a qualifier was present and we didn't find // a matching field then we should stop searching. @@ -6424,14 +6540,14 @@ ValueExprNode* FieldNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, Rec // Clean up stack ambiguousCtxStack.clear(); - if (!node) - PASS1_field_unknown(dsqlQualifier.nullStr(), dsqlName.nullStr(), this); + if (!node && !(list && *list)) + PASS1_field_unknown(dsqlQualifier.toQuotedString().nullStr(), dsqlName.toQuotedString().nullStr(), this); return node; } // Attempt to resolve field against context. Return first field in context if successful, NULL if not. -dsql_fld* FieldNode::resolveContext(DsqlCompilerScratch* dsqlScratch, const MetaName& qualifier, dsql_ctx* context) +dsql_fld* FieldNode::resolveContext(DsqlCompilerScratch* dsqlScratch, const QualifiedName& qualifier, dsql_ctx* context) { // CVC: Warning: the second param, "name" is not used anymore and // therefore it was removed. Thus, the local variable "table_name" @@ -6451,37 +6567,29 @@ dsql_fld* FieldNode::resolveContext(DsqlCompilerScratch* dsqlScratch, const Meta if (!relation && !procedure) return nullptr; - // if there is no qualifier, then we cannot match against - // a context of a different scoping level - // AB: Yes we can, but the scope level where the field is has priority. - /*** - if (qualifier.isEmpty() && context->ctx_scope_level != dsqlScratch->scopeLevel) - return nullptr; - ***/ - // AB: If this context is a system generated context as in NEW/OLD inside // triggers, the qualifier by the field is mandatory. While we can't // fall back from a higher scope-level to the NEW/OLD contexts without // the qualifier present. // An exception is a check-constraint that is allowed to reference fields // without the qualifier. - if (!dsqlScratch->checkConstraintTrigger && (context->ctx_flags & CTX_system) && qualifier.isEmpty()) + if (!dsqlScratch->checkConstraintTrigger && (context->ctx_flags & CTX_system) && qualifier.object.isEmpty()) return nullptr; - MetaString aliasName = context->ctx_internal_alias; + auto aliasName = context->ctx_internal_alias; // AB: For a check constraint we should ignore the alias if the alias // contains the "NEW" alias. This is because it is possible // to reference a field by the complete table-name as alias // (see EMPLOYEE table in examples for a example). - if (dsqlScratch->checkConstraintTrigger && aliasName.hasData()) + if (dsqlScratch->checkConstraintTrigger && aliasName.object.hasData()) { // If a qualifier is present and it's equal to the alias then we've already the right table-name - if (qualifier.isEmpty() || qualifier != aliasName) + if (qualifier.object.isEmpty() || qualifier != aliasName) // FIXME: { - if (aliasName == NEW_CONTEXT_NAME) + if (aliasName == QualifiedName(NEW_CONTEXT_NAME)) aliasName.clear(); - else if (aliasName == OLD_CONTEXT_NAME) + else if (aliasName == QualifiedName(OLD_CONTEXT_NAME)) { // Only use the OLD context if it is explicit used. That means the // qualifer should hold the "OLD" alias. @@ -6490,13 +6598,13 @@ dsql_fld* FieldNode::resolveContext(DsqlCompilerScratch* dsqlScratch, const Meta } } - if (aliasName.isEmpty()) - aliasName = relation ? relation->rel_name : procedure->prc_name.identifier; + if (aliasName.object.isEmpty()) + aliasName = relation ? relation->rel_name : procedure->prc_name; - fb_assert(aliasName.hasData()); + fb_assert(aliasName.object.hasData()); // If a context qualifier is present, make sure this is the proper context - if (qualifier.hasData() && qualifier != aliasName) + if (qualifier.object.hasData() && !PASS1_compare_alias(aliasName, qualifier)) return nullptr; // Lookup field in relation or procedure @@ -6811,7 +6919,10 @@ ValueExprNode* FieldNode::pass1(thread_db* tdbb, CompilerScratch* csb) const SLONG ssRelationId = tail->csb_view ? tail->csb_view->rel_id : (csb->csb_view ? csb->csb_view->rel_id : 0); - CMP_post_access(tdbb, csb, relation->rel_security_name, ssRelationId, + CMP_post_access(tdbb, csb, relation->rel_security_name.schema, ssRelationId, + SCL_usage, obj_schemas, QualifiedName(relation->rel_name.schema)); + + CMP_post_access(tdbb, csb, relation->rel_security_name.object, ssRelationId, privilege, obj_relations, relation->rel_name); // Field-level privilege access is posted for every operation except DELETE @@ -6819,7 +6930,7 @@ ValueExprNode* FieldNode::pass1(thread_db* tdbb, CompilerScratch* csb) if (privilege != SCL_delete) { CMP_post_access(tdbb, csb, field->fld_security_name, ssRelationId, - privilege, obj_column, field->fld_name, relation->rel_name); + privilege, obj_column, relation->rel_name, field->fld_name); } } @@ -6835,7 +6946,7 @@ ValueExprNode* FieldNode::pass1(thread_db* tdbb, CompilerScratch* csb) // Msg 364 "cannot access column %s in view %s" ERR_post(Arg::Gds(isc_no_field_access) << Arg::Str(field->fld_name) << - Arg::Str(relation->rel_name)); + relation->rel_name.toQuotedString()); } // The previous test below is an apparent temporary fix @@ -6886,7 +6997,7 @@ ValueExprNode* FieldNode::pass1(thread_db* tdbb, CompilerScratch* csb) // This is an assignment to a computed column. Report the error here when we have the field name. ERR_post( Arg::Gds(isc_read_only_field) << - (string(relation->rel_name.c_str()) + "." + field->fld_name.c_str())); + (relation->rel_name.toQuotedString() + "." + field->fld_name.toQuotedString())); } FB_SIZE_T pos; @@ -7058,10 +7169,10 @@ dsc* FieldNode::execute(thread_db* tdbb, Request* request) const //-------------------- -static RegisterNode regGenIdNode({blr_gen_id, blr_gen_id2}); +static RegisterNode regGenIdNode({blr_gen_id, blr_gen_id2, blr_gen_id3}); GenIdNode::GenIdNode(MemoryPool& pool, bool aDialect1, - const MetaName& name, + const QualifiedName& name, ValueExprNode* aArg, bool aImplicit, bool aIdentity) : TypedNode(pool), @@ -7077,25 +7188,34 @@ GenIdNode::GenIdNode(MemoryPool& pool, bool aDialect1, DmlNode* GenIdNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp) { - MetaName name; - csb->csb_blr_reader.getMetaName(name); + QualifiedName name; - ValueExprNode* explicitStep = (blrOp == blr_gen_id2) ? NULL : PAR_parse_value(tdbb, csb); - GenIdNode* const node = - FB_NEW_POOL(pool) GenIdNode(pool, (csb->blrVersion == 4), name, explicitStep, - (blrOp == blr_gen_id2), false); + if (blrOp == blr_gen_id3) + csb->csb_blr_reader.getMetaName(name.schema); + + csb->csb_blr_reader.getMetaName(name.object); + + if (name.object.isEmpty() && (name.schema == SYSTEM_SCHEMA || name.schema.isEmpty())) + name.schema = SYSTEM_SCHEMA; + else + csb->qualifyExistingName(tdbb, name, obj_generator); + + const bool useExplicitStep = blrOp == blr_gen_id || (blrOp == blr_gen_id3 && csb->csb_blr_reader.getByte() != 0); + const auto explicitStep = useExplicitStep ? PAR_parse_value(tdbb, csb) : nullptr; + const auto node = FB_NEW_POOL(pool) GenIdNode(pool, (csb->blrVersion == 4), name, explicitStep, + !useExplicitStep, false); // This check seems faster than ==, but assumes the special generator is named "" - if (name.length() == 0) //(name == MASTER_GENERATOR) + if (name.schema == SYSTEM_SCHEMA && name.object.isEmpty()) //(name == MASTER_GENERATOR) { fb_assert(!MASTER_GENERATOR[0]); if (!(csb->csb_g_flags & csb_internal)) - PAR_error(csb, Arg::Gds(isc_gennotdef) << Arg::Str(name)); + PAR_error(csb, Arg::Gds(isc_gennotdef) << name.toQuotedString()); node->generator.id = 0; } else if (!MET_load_generator(tdbb, node->generator, &node->sysGen, &node->step)) - PAR_error(csb, Arg::Gds(isc_gennotdef) << Arg::Str(name)); + PAR_error(csb, Arg::Gds(isc_gennotdef) << name.toQuotedString()); if (csb->collectingDependencies()) { @@ -7124,6 +7244,8 @@ string GenIdNode::internalPrint(NodePrinter& printer) const ValueExprNode* GenIdNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { + dsqlScratch->qualifyExistingName(generator.name, obj_generator); + GenIdNode* const node = FB_NEW_POOL(dsqlScratch->getPool()) GenIdNode(dsqlScratch->getPool(), dialect1, generator.name, doDsqlPass(dsqlScratch, arg), implicit, identity); node->generator = generator; @@ -7145,16 +7267,33 @@ bool GenIdNode::setParameterType(DsqlCompilerScratch* dsqlScratch, void GenIdNode::genBlr(DsqlCompilerScratch* dsqlScratch) { - if (implicit) + if (generator.name.schema != dsqlScratch->ddlSchema) { - dsqlScratch->appendUChar(blr_gen_id2); - dsqlScratch->appendNullString(generator.name.c_str()); + dsqlScratch->appendUChar(blr_gen_id3); + dsqlScratch->appendNullString(generator.name.schema.c_str()); + dsqlScratch->appendNullString(generator.name.object.c_str()); + + if (implicit) + dsqlScratch->appendUChar(0); + else + { + dsqlScratch->appendUChar(1); + GEN_expr(dsqlScratch, arg); + } } else { - dsqlScratch->appendUChar(blr_gen_id); - dsqlScratch->appendNullString(generator.name.c_str()); - GEN_expr(dsqlScratch, arg); + if (implicit) + { + dsqlScratch->appendUChar(blr_gen_id2); + dsqlScratch->appendNullString(generator.name.object.c_str()); + } + else + { + dsqlScratch->appendUChar(blr_gen_id); + dsqlScratch->appendNullString(generator.name.object.c_str()); + GEN_expr(dsqlScratch, arg); + } } } @@ -7227,8 +7366,10 @@ ValueExprNode* GenIdNode::pass1(thread_db* tdbb, CompilerScratch* csb) if (!identity) { - CMP_post_access(tdbb, csb, generator.secName, 0, - SCL_usage, obj_generators, generator.name); + CMP_post_access(tdbb, csb, generator.secName.schema, 0, SCL_usage, obj_schemas, + QualifiedName(generator.name.schema)); + + CMP_post_access(tdbb, csb, generator.secName.object, 0, SCL_usage, obj_generators, generator.name); } return this; @@ -7265,7 +7406,7 @@ dsc* GenIdNode::execute(thread_db* tdbb, Request* request) const if (sysGen && change != 0) { if (!request->hasInternalStatement() && !tdbb->getAttachment()->isRWGbak()) - status_exception::raise(Arg::Gds(isc_cant_modify_sysobj) << "generator" << generator.name); + status_exception::raise(Arg::Gds(isc_cant_modify_sysobj) << "generator" << generator.name.toQuotedString()); } const SINT64 new_val = DPM_gen_id(tdbb, generator.id, false, change); @@ -7357,7 +7498,7 @@ void InternalInfoNode::make(DsqlCompilerScratch* /*dsqlScratch*/, dsc* desc) break; case INFO_TYPE_EXCEPTION: - desc->makeVarying(MAX_SQL_IDENTIFIER_LEN, ttype_metadata); + desc->makeVarying(MAX_QUALIFIED_NAME_TO_STRING_LEN, ttype_metadata); break; case INFO_TYPE_ERROR_MSG: @@ -7399,7 +7540,7 @@ void InternalInfoNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) break; case INFO_TYPE_EXCEPTION: - desc->makeVarying(MAX_SQL_IDENTIFIER_LEN, ttype_metadata); + desc->makeVarying(MAX_QUALIFIED_NAME_TO_STRING_LEN, ttype_metadata); break; case INFO_TYPE_ERROR_MSG: @@ -7476,14 +7617,16 @@ dsc* InternalInfoNode::execute(thread_db* tdbb, Request* request) const if (!xcpCode) return NULL; - MetaName xcpName; + QualifiedName xcpName; MET_lookup_exception(tdbb, xcpCode, xcpName, NULL); - if (xcpName.isEmpty()) + if (xcpName.object.isEmpty()) return NULL; + const auto xcpNameStr = xcpName.toQuotedString(); + dsc desc; - desc.makeText(xcpName.length(), ttype_metadata, (UCHAR*) xcpName.c_str()); + desc.makeText(xcpNameStr.length(), ttype_metadata, (UCHAR*) xcpNameStr.c_str()); EVL_make_value(tdbb, &desc, impure); return &impure->vlu_desc; @@ -7920,27 +8063,27 @@ ValueExprNode* LiteralNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) constant->dsqlStr = dsqlStr; constant->litDesc = litDesc; - if (dsqlStr && dsqlStr->getCharSet().hasData()) + if (dsqlStr && dsqlStr->getCharSet().object.hasData()) { - const dsql_intlsym* resolved = METD_get_charset(dsqlScratch->getTransaction(), - dsqlStr->getCharSet().length(), dsqlStr->getCharSet().c_str()); + auto charSet = dsqlStr->getCharSet(); + dsqlScratch->qualifyExistingName(charSet, obj_charset); + dsqlStr->setCharSet(charSet); + + const dsql_intlsym* resolved = METD_get_charset(dsqlScratch->getTransaction(), charSet); if (!resolved) { // character set name is not defined ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-504) << - Arg::Gds(isc_charset_not_found) << dsqlStr->getCharSet()); + Arg::Gds(isc_charset_not_found) << charSet.toQuotedString()); } constant->litDesc.setTextType(resolved->intlsym_ttype); } else { - const MetaName charSetName = METD_get_charset_name( - dsqlScratch->getTransaction(), constant->litDesc.getCharSet()); - - const dsql_intlsym* sym = METD_get_charset(dsqlScratch->getTransaction(), - charSetName.length(), charSetName.c_str()); + const auto charSetName = METD_get_charset_name(dsqlScratch->getTransaction(), constant->litDesc.getCharSet()); + const dsql_intlsym* sym = METD_get_charset(dsqlScratch->getTransaction(), charSetName); fb_assert(sym); if (sym) @@ -7974,7 +8117,7 @@ ValueExprNode* LiteralNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) Arg::Gds(isc_dsql_string_char_length) << Arg::Num(charLength) << Arg::Num(MAX_STR_SIZE / charSet->maxBytesPerChar()) << - METD_get_charset_name(dsqlScratch->getTransaction(), constant->litDesc.getCharSet())); + METD_get_charset_name(dsqlScratch->getTransaction(), constant->litDesc.getCharSet()).toQuotedString()); } else constant->litDesc.dsc_length = charLength * charSet->maxBytesPerChar(); @@ -8125,7 +8268,7 @@ ValueExprNode* LiteralNode::pass2(thread_db* tdbb, CompilerScratch* csb) } } - delete dsqlStr; // Not needed anymore + delete dsqlStr.getObject(); // Not needed anymore dsqlStr = nullptr; ValueExprNode::pass2(tdbb, csb); @@ -8767,7 +8910,7 @@ void DerivedFieldNode::setParameterName(dsql_par* parameter) const value->setParameterName(parameter); parameter->par_alias = name; - parameter->par_rel_alias = context->ctx_alias; + parameter->par_rel_alias = context->getConcatenatedAlias(); } void DerivedFieldNode::genBlr(DsqlCompilerScratch* dsqlScratch) @@ -10007,7 +10150,7 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const static RegisterNode regRecordKeyNode({blr_dbkey, blr_record_version, blr_record_version2}); -RecordKeyNode::RecordKeyNode(MemoryPool& pool, UCHAR aBlrOp, const MetaName& aDsqlQualifier) +RecordKeyNode::RecordKeyNode(MemoryPool& pool, UCHAR aBlrOp, const QualifiedName& aDsqlQualifier) : TypedNode(pool), dsqlQualifier(pool, aDsqlQualifier), dsqlRelation(NULL), @@ -10049,11 +10192,11 @@ string RecordKeyNode::internalPrint(NodePrinter& printer) const ValueExprNode* RecordKeyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { thread_db* tdbb = JRD_get_thread_data(); + DsqlContextStack contexts; + ValueExprNode* node = nullptr; - if (dsqlQualifier.isEmpty()) + if (dsqlQualifier.object.isEmpty()) { - DsqlContextStack contexts; - for (DsqlContextStack::iterator stack(*dsqlScratch->context); stack.hasData(); ++stack) { dsql_ctx* context = stack.object(); @@ -10075,19 +10218,19 @@ ValueExprNode* RecordKeyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) raiseError(context); if (context->ctx_flags & CTX_null) - return NullNode::instance(); + node = NullNode::instance(); + else + { + //// TODO: LocalTableSourceNode + auto relNode = FB_NEW_POOL(dsqlScratch->getPool()) RelationSourceNode( + dsqlScratch->getPool()); + relNode->dsqlContext = context; - PASS1_ambiguity_check(dsqlScratch, getAlias(true), contexts); - - //// TODO: LocalTableSourceNode - auto relNode = FB_NEW_POOL(dsqlScratch->getPool()) RelationSourceNode( - dsqlScratch->getPool()); - relNode->dsqlContext = context; - - auto node = FB_NEW_POOL(dsqlScratch->getPool()) RecordKeyNode(dsqlScratch->getPool(), blrOp); - node->dsqlRelation = relNode; - - return node; + const auto recordKeyNode = FB_NEW_POOL(dsqlScratch->getPool()) RecordKeyNode( + dsqlScratch->getPool(), blrOp); + recordKeyNode->dsqlRelation = relNode; + node = recordKeyNode; + } } } else @@ -10097,10 +10240,10 @@ ValueExprNode* RecordKeyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) dsql_ctx* context = stack.object(); if ((!context->ctx_relation || - context->ctx_relation->rel_name != dsqlQualifier || - context->ctx_internal_alias.hasData()) && - (context->ctx_internal_alias.isEmpty() || - strcmp(dsqlQualifier.c_str(), context->ctx_internal_alias.c_str()) != 0)) + !PASS1_compare_alias(context->ctx_relation->rel_name, dsqlQualifier) || + context->ctx_internal_alias.object.hasData()) && + (context->ctx_internal_alias.object.isEmpty() || + !PASS1_compare_alias(context->ctx_internal_alias, dsqlQualifier))) { continue; } @@ -10109,24 +10252,30 @@ ValueExprNode* RecordKeyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) raiseError(context); if (context->ctx_flags & CTX_null) - return NullNode::instance(); + node = NullNode::instance(); + else + { + //// TODO: LocalTableSourceNode + auto relNode = FB_NEW_POOL(dsqlScratch->getPool()) RelationSourceNode(dsqlScratch->getPool()); + relNode->dsqlContext = context; - //// TODO: LocalTableSourceNode - auto relNode = FB_NEW_POOL(dsqlScratch->getPool()) RelationSourceNode( - dsqlScratch->getPool()); - relNode->dsqlContext = context; - - auto node = FB_NEW_POOL(dsqlScratch->getPool()) RecordKeyNode(dsqlScratch->getPool(), blrOp); - node->dsqlRelation = relNode; - - return node; + const auto recordKeyNode = FB_NEW_POOL(dsqlScratch->getPool()) RecordKeyNode( + dsqlScratch->getPool(), blrOp); + recordKeyNode->dsqlRelation = relNode; + node = recordKeyNode; + } } } - // Field unresolved. - PASS1_field_unknown(dsqlQualifier.nullStr(), getAlias(false), this); + PASS1_ambiguity_check(dsqlScratch, getAlias(true), contexts); - return NULL; + if (!node) + { + // Field unresolved. + PASS1_field_unknown(dsqlQualifier.toQuotedString().nullStr(), getAlias(false), this); + } + + return node; } bool RecordKeyNode::dsqlAggregate2Finder(Aggregate2Finder& /*visitor*/) @@ -10555,14 +10704,14 @@ void RecordKeyNode::raiseError(dsql_ctx* context) const } string name = context->getObjectName(); - const string& alias = context->ctx_internal_alias; + const auto& alias = context->ctx_internal_alias; - if (alias.hasData() && name != alias) + if (alias.object.hasData() && name != alias.toQuotedString()) { if (name.hasData()) - name += " (alias " + alias + ")"; + name += " (alias " + alias.toQuotedString() + ")"; else - name = alias; + name = alias.toQuotedString(); } status_exception::raise( @@ -12344,12 +12493,16 @@ DmlNode* SysFuncCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScrat if (literal && literal->litDesc.isText()) { - MetaName relName; - CVT2_make_metaname(&literal->litDesc, relName, tdbb->getAttachment()->att_dec_status); + MoveBuffer buff; + UCHAR* ptr = nullptr; + const auto len = CVT2_make_string2(&literal->litDesc, CS_METADATA, &ptr, buff, + tdbb->getAttachment()->att_dec_status); + name.assign(reinterpret_cast(ptr), len); - const jrd_rel* const relation = MET_lookup_relation(tdbb, relName); + auto relName = QualifiedName::parseSchemaObject(string(reinterpret_cast(ptr), len)); + csb->qualifyExistingName(tdbb, relName, obj_relation); - if (relation) + if (const auto* const relation = MET_lookup_relation(tdbb, relName)) node->args->items[0] = MAKE_const_slong(relation->rel_id); } } @@ -12484,15 +12637,7 @@ dsc* SysFuncCallNode::execute(thread_db* tdbb, Request* request) const ValueExprNode* SysFuncCallNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { - QualifiedName qualifName(name); - - if (!dsqlSpecialSyntax && METD_get_function(dsqlScratch->getTransaction(), dsqlScratch, qualifName)) - { - UdfCallNode* node = FB_NEW_POOL(dsqlScratch->getPool()) UdfCallNode(dsqlScratch->getPool(), qualifName, args); - return node->dsqlPass(dsqlScratch); - } - - SysFuncCallNode* node = FB_NEW_POOL(dsqlScratch->getPool()) SysFuncCallNode(dsqlScratch->getPool(), name, + const auto node = FB_NEW_POOL(dsqlScratch->getPool()) SysFuncCallNode(dsqlScratch->getPool(), name, doDsqlPass(dsqlScratch, args)); node->dsqlSpecialSyntax = dsqlSpecialSyntax; @@ -12976,42 +13121,55 @@ DmlNode* UdfCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* { switch (subCode) { - case blr_invoke_function_type: + case blr_invoke_function_id: { - UCHAR functionType = blrReader.getByte(); + bool isSub = false; + UCHAR functionIdCode; - switch (functionType) + while ((functionIdCode = blrReader.getByte()) != blr_end) { - case blr_invoke_function_type_packaged: - blrReader.getMetaName(name.package); - break; + switch (functionIdCode) + { + case blr_invoke_function_id_schema: + blrReader.getMetaName(name.schema); + break; - case blr_invoke_function_type_standalone: - case blr_invoke_function_type_sub: - break; + case blr_invoke_function_id_package: + blrReader.getMetaName(name.package); + break; - default: - PAR_error(csb, Arg::Gds(isc_random) << "Invalid blr_invoke_function_type"); - break; + case blr_invoke_function_id_name: + blrReader.getMetaName(name.object); + break; + + case blr_invoke_function_id_sub: + isSub = true; + break; + + default: + PAR_error(csb, Arg::Gds(isc_random) << "Invalid blr_invoke_function_id"); + break; + } } - blrReader.getMetaName(name.identifier); - - if (functionType == blr_invoke_function_type_sub) + if (isSub) { for (auto curCsb = csb; curCsb && !node->function; curCsb = curCsb->mainCsb) { - if (DeclareSubFuncNode* declareNode; curCsb->subFunctions.get(name.identifier, declareNode)) + if (DeclareSubFuncNode* declareNode; curCsb->subFunctions.get(name.object, declareNode)) node->function = declareNode->routine; } } else if (!node->function) + { + csb->qualifyExistingName(tdbb, name, obj_udf); node->function = Function::lookup(tdbb, name, false); + } if (!node->function) { blrReader.setPos(startPos); - PAR_error(csb, Arg::Gds(isc_funnotdef) << name.toString()); + PAR_error(csb, Arg::Gds(isc_funnotdef) << name.toQuotedString()); } break; @@ -13019,7 +13177,7 @@ DmlNode* UdfCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* case blr_invoke_function_arg_names: { - predateCheck(node->function, "blr_invoke_function_type", "blr_invoke_function_arg_names"); + predateCheck(node->function, "blr_invoke_function_id", "blr_invoke_function_arg_names"); predateCheck(!node->args, "blr_invoke_function_arg_names", "blr_invoke_function_args"); argNamesPos = blrReader.getPos(); @@ -13038,7 +13196,7 @@ DmlNode* UdfCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* } case blr_invoke_function_args: - predateCheck(node->function, "blr_invoke_function_type", "blr_invoke_function_args"); + predateCheck(node->function, "blr_invoke_function_id", "blr_invoke_function_args"); argCount = blrReader.getWord(); node->args = PAR_args(tdbb, csb, argCount, MAX(argCount, node->function->fun_inputs)); @@ -13054,10 +13212,11 @@ DmlNode* UdfCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* if (blrOp == blr_function2) blrReader.getMetaName(name.package); - blrReader.getMetaName(name.identifier); + blrReader.getMetaName(name.object); if (blrOp == blr_function && - (name.identifier == "RDB$GET_CONTEXT" || name.identifier == "RDB$SET_CONTEXT")) + (name.schema.isEmpty() || name.schema == SYSTEM_SCHEMA) && + (name.object == "RDB$GET_CONTEXT" || name.object == "RDB$SET_CONTEXT")) { blrReader.setPos(startPos); return SysFuncCallNode::parse(tdbb, pool, csb, blr_sys_function); @@ -13067,17 +13226,20 @@ DmlNode* UdfCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* { for (auto curCsb = csb; curCsb && !node->function; curCsb = curCsb->mainCsb) { - if (DeclareSubFuncNode* declareNode; curCsb->subFunctions.get(name.identifier, declareNode)) + if (DeclareSubFuncNode* declareNode; curCsb->subFunctions.get(name.object, declareNode)) node->function = declareNode->routine; } } else if (!node->function) + { + csb->qualifyExistingName(tdbb, name, obj_udf); node->function = Function::lookup(tdbb, name, false); + } if (!node->function) { blrReader.setPos(startPos); - PAR_error(csb, Arg::Gds(isc_funnotdef) << name.toString()); + PAR_error(csb, Arg::Gds(isc_funnotdef) << name.toQuotedString()); } argCount = blrReader.getByte(); @@ -13098,13 +13260,13 @@ DmlNode* UdfCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* { if (tdbb->getAttachment()->isGbak() || (tdbb->tdbb_flags & TDBB_replicator)) { - PAR_warning(Arg::Warning(isc_funnotdef) << name.toString() << + PAR_warning(Arg::Warning(isc_funnotdef) << name.toQuotedString() << Arg::Warning(isc_modnotfound)); } else { blrReader.setPos(startPos); - PAR_error(csb, Arg::Gds(isc_funnotdef) << name.toString() << + PAR_error(csb, Arg::Gds(isc_funnotdef) << name.toQuotedString() << Arg::Gds(isc_modnotfound)); } } @@ -13180,15 +13342,15 @@ DmlNode* UdfCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* FieldInfo fieldInfo; if (parameter->prm_mechanism != prm_mech_type_of && - !fb_utils::implicit_domain(parameter->prm_field_source.c_str())) + !fb_utils::implicit_domain(parameter->prm_field_source.object.c_str())) { - const MetaNamePair namePair(parameter->prm_field_source, ""); + const QualifiedNameMetaNamePair entry(parameter->prm_field_source, {}); - if (!csb->csb_map_field_info.get(namePair, fieldInfo)) + if (!csb->csb_map_field_info.get(entry, fieldInfo)) { dsc dummyDesc; MET_get_domain(tdbb, csb->csb_pool, parameter->prm_field_source, &dummyDesc, &fieldInfo); - csb->csb_map_field_info.put(namePair, fieldInfo); + csb->csb_map_field_info.put(entry, fieldInfo); } } @@ -13211,7 +13373,7 @@ DmlNode* UdfCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* } if (mismatchStatus.hasData()) - status_exception::raise(Arg::Gds(isc_fun_param_mismatch) << name.toString() << mismatchStatus); + status_exception::raise(Arg::Gds(isc_fun_param_mismatch) << name.toQuotedString() << mismatchStatus); // CVC: I will track ufds only if a function is not being dropped. if (!node->function->isSubRoutine() && csb->collectingDependencies()) @@ -13249,29 +13411,37 @@ string UdfCallNode::internalPrint(NodePrinter& printer) const void UdfCallNode::setParameterName(dsql_par* parameter) const { - parameter->par_name = parameter->par_alias = dsqlFunction->udf_name.identifier; + parameter->par_name = parameter->par_alias = dsqlFunction->udf_name.object; } void UdfCallNode::genBlr(DsqlCompilerScratch* dsqlScratch) { - if (dsqlArgNames || args->items.getCount() >= UCHAR_MAX) + if (dsqlArgNames || args->items.getCount() >= UCHAR_MAX || dsqlFunction->udf_name.schema != dsqlScratch->ddlSchema) { dsqlScratch->appendUChar(blr_invoke_function); - dsqlScratch->appendUChar(blr_invoke_function_type); + dsqlScratch->appendUChar(blr_invoke_function_id); - if (dsqlFunction->udf_name.package.hasData()) - { - dsqlScratch->appendUChar(blr_invoke_function_type_packaged); - dsqlScratch->appendMetaString(dsqlFunction->udf_name.package.c_str()); - } + if (dsqlFunction->udf_flags & UDF_subfunc) + dsqlScratch->appendUChar(blr_invoke_function_id_sub); else { - dsqlScratch->appendUChar((dsqlFunction->udf_flags & UDF_subfunc) ? - blr_invoke_function_type_sub : blr_invoke_function_type_standalone); + if (dsqlFunction->udf_name.schema != dsqlScratch->ddlSchema) + { + dsqlScratch->appendUChar(blr_invoke_function_id_schema); + dsqlScratch->appendMetaString(dsqlFunction->udf_name.schema.c_str()); + } + + if (dsqlFunction->udf_name.package.hasData()) + { + dsqlScratch->appendUChar(blr_invoke_function_id_package); + dsqlScratch->appendMetaString(dsqlFunction->udf_name.package.c_str()); + } } - dsqlScratch->appendMetaString(dsqlFunction->udf_name.identifier.c_str()); + dsqlScratch->appendUChar(blr_invoke_function_id_name); + dsqlScratch->appendMetaString(dsqlFunction->udf_name.object.c_str()); + dsqlScratch->appendUChar(blr_end); if (dsqlArgNames && dsqlArgNames->hasData()) { @@ -13301,7 +13471,7 @@ void UdfCallNode::genBlr(DsqlCompilerScratch* dsqlScratch) dsqlScratch->appendMetaString(dsqlFunction->udf_name.package.c_str()); } - dsqlScratch->appendMetaString(dsqlFunction->udf_name.identifier.c_str()); + dsqlScratch->appendMetaString(dsqlFunction->udf_name.object.c_str()); dsqlScratch->appendUChar(args->items.getCount()); for (auto& arg : args->items) @@ -13382,24 +13552,26 @@ ValueExprNode* UdfCallNode::pass1(thread_db* tdbb, CompilerScratch* csb) { if (!(csb->csb_g_flags & (csb_internal | csb_ignore_perm))) { + SLONG ssRelationId = csb->csb_view ? csb->csb_view->rel_id : 0; + + CMP_post_access(tdbb, csb, function->getSecurityName().schema, ssRelationId, + SCL_usage, obj_schemas, QualifiedName(function->getName().schema)); + if (function->getName().package.isEmpty()) { - SLONG ssRelationId = csb->csb_view ? csb->csb_view->rel_id : 0; - if (!ssRelationId && csb->csb_parent_relation) { fb_assert(csb->csb_parent_relation->rel_ss_definer.asBool()); ssRelationId = csb->csb_parent_relation->rel_id; } - CMP_post_access(tdbb, csb, function->getSecurityName(), ssRelationId, - SCL_execute, obj_functions, function->getName().identifier); + CMP_post_access(tdbb, csb, function->getSecurityName().object, ssRelationId, + SCL_execute, obj_functions, function->getName()); } else { - CMP_post_access(tdbb, csb, function->getSecurityName(), - (csb->csb_view ? csb->csb_view->rel_id : 0), - SCL_execute, obj_packages, function->getName().package); + CMP_post_access(tdbb, csb, function->getSecurityName().object, ssRelationId, + SCL_execute, obj_packages, function->getName().getSchemaAndPackage()); } ExternalAccess temp(ExternalAccess::exa_function, function->getId()); @@ -13476,12 +13648,12 @@ dsc* UdfCallNode::execute(thread_db* tdbb, Request* request) const { status_exception::raise( Arg::Gds(isc_func_pack_not_implemented) << - Arg::Str(function->getName().identifier) << Arg::Str(function->getName().package)); + Arg::Str(function->getName().object) << function->getName().getSchemaAndPackage().toQuotedString()); } else if (!function->isDefined()) { status_exception::raise( - Arg::Gds(isc_funnotdef) << Arg::Str(function->getName().toString()) << + Arg::Gds(isc_funnotdef) << Arg::Str(function->getName().toQuotedString()) << Arg::Gds(isc_modnotfound)); } @@ -13656,27 +13828,63 @@ dsc* UdfCallNode::execute(thread_db* tdbb, Request* request) const ValueExprNode* UdfCallNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { + dsql_udf* function = nullptr; + + if (name.package.isEmpty()) + { + if (name.schema.isEmpty()) + { + if (const auto subFunction = dsqlScratch->getSubFunction(name.object)) + function = subFunction->dsqlFunction; + else if (dsqlScratch->package.object.hasData()) + { + const QualifiedName packagedName(name.object, dsqlScratch->package.schema, dsqlScratch->package.object); + function = METD_get_function(dsqlScratch->getTransaction(), dsqlScratch, packagedName); + } + + if (!function) + dsqlScratch->qualifyExistingName(name, obj_udf); + } + else + { + QualifiedName packageName(name.schema); + dsqlScratch->qualifyExistingName(packageName, obj_package_header); + + if (MET_check_package_exists(JRD_get_thread_data(), packageName)) + { + name.schema = packageName.schema; + name.package = packageName.object; + } + } + } + + if (!function) + function = METD_get_function(dsqlScratch->getTransaction(), dsqlScratch, name); + + if (!function) + { + ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-804) << + Arg::Gds(isc_dsql_function_err) << + Arg::Gds(isc_random) << name.toQuotedString()); + } + + if (function->udf_private && function->udf_name.getSchemaAndPackage() != dsqlScratch->package) + { + status_exception::raise( + Arg::Gds(isc_private_function) << + function->udf_name.object << + function->udf_name.getSchemaAndPackage().toQuotedString()); + } + + name = function->udf_name; + const auto node = FB_NEW_POOL(dsqlScratch->getPool()) UdfCallNode(dsqlScratch->getPool(), name, doDsqlPass(dsqlScratch, args), dsqlArgNames ? FB_NEW_POOL(dsqlScratch->getPool()) ObjectsArray(dsqlScratch->getPool(), *dsqlArgNames) : nullptr); - if (name.package.isEmpty()) - { - DeclareSubFuncNode* subFunction = dsqlScratch->getSubFunction(name.identifier); - node->dsqlFunction = subFunction ? subFunction->dsqlFunction : NULL; - } - - if (!node->dsqlFunction) - node->dsqlFunction = METD_get_function(dsqlScratch->getTransaction(), dsqlScratch, name); - - if (!node->dsqlFunction) - { - ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-804) << - Arg::Gds(isc_dsql_function_err) << - Arg::Gds(isc_random) << Arg::Str(name.toString())); - } + node->dsqlFunction = function; auto argIt = node->args->items.begin(); unsigned pos = 0; @@ -13719,7 +13927,7 @@ ValueExprNode* UdfCallNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) } if (mismatchStatus.hasData()) - status_exception::raise(Arg::Gds(isc_fun_param_mismatch) << name.toString() << mismatchStatus); + status_exception::raise(Arg::Gds(isc_fun_param_mismatch) << name.toQuotedString() << mismatchStatus); } return node; @@ -14063,7 +14271,7 @@ ValueExprNode* VariableNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) if (!node->dsqlVar || (node->dsqlVar->type == dsql_var::TYPE_LOCAL && !node->dsqlVar->initialized && !dsqlScratch->mainScratch)) { - PASS1_field_unknown(NULL, dsqlName.c_str(), this); + PASS1_field_unknown(NULL, dsqlName.toQuotedString().c_str(), this); } return node; @@ -14394,16 +14602,16 @@ static void setParameterInfo(dsql_par* parameter, const dsql_ctx* context) if (context->ctx_relation) { - parameter->par_rel_name = context->ctx_relation->rel_name.c_str(); - parameter->par_owner_name = context->ctx_relation->rel_owner.c_str(); + parameter->par_rel_name = context->ctx_relation->rel_name; + parameter->par_owner_name = context->ctx_relation->rel_owner; } else if (context->ctx_procedure) { - parameter->par_rel_name = context->ctx_procedure->prc_name.identifier.c_str(); - parameter->par_owner_name = context->ctx_procedure->prc_owner.c_str(); + parameter->par_rel_name = context->ctx_procedure->prc_name; + parameter->par_owner_name = context->ctx_procedure->prc_owner; } - parameter->par_rel_alias = context->ctx_alias.c_str(); + parameter->par_rel_alias = context->getConcatenatedAlias(); } diff --git a/src/dsql/ExprNodes.h b/src/dsql/ExprNodes.h index fb79beccf5..50b74a9d37 100644 --- a/src/dsql/ExprNodes.h +++ b/src/dsql/ExprNodes.h @@ -339,7 +339,7 @@ public: class CollateNode final : public TypedNode { public: - CollateNode(MemoryPool& pool, ValueExprNode* aArg, const MetaName& aCollation); + CollateNode(MemoryPool& pool, ValueExprNode* aArg, const QualifiedName& aCollation); virtual void getChildren(NodeRefsHolder& holder, bool dsql) const { @@ -353,7 +353,7 @@ public: virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); static ValueExprNode* pass1Collate(DsqlCompilerScratch* dsqlScratch, ValueExprNode* input, - const MetaName& collation); + QualifiedName& collation); // This class is used only in the parser. It turns in a CastNode in dsqlPass. @@ -394,7 +394,7 @@ private: public: NestConst arg; - MetaName collation; + QualifiedName collation; }; @@ -530,6 +530,29 @@ public: }; +class CurrentSchemaNode final : public TypedNode +{ +public: + explicit CurrentSchemaNode(MemoryPool& pool) + : TypedNode(pool) + { + } + + static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp); + + Firebird::string internalPrint(NodePrinter& printer) const override; + ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) override; + void setParameterName(dsql_par* parameter) const override; + void genBlr(DsqlCompilerScratch* dsqlScratch) override; + void make(DsqlCompilerScratch* dsqlScratch, dsc* desc) override; + + void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) override; + ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier) const override; + ValueExprNode* pass2(thread_db* tdbb, CompilerScratch* csb) override; + dsc* execute(thread_db* tdbb, Request* request) const override; +}; + + class CurrentUserNode final : public TypedNode { public: @@ -612,7 +635,7 @@ public: class DefaultNode : public DsqlNode { public: - explicit DefaultNode(MemoryPool& pool, const MetaName& aRelationName, + explicit DefaultNode(MemoryPool& pool, const QualifiedName& aRelationName, const MetaName& aFieldName); static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp); @@ -631,7 +654,7 @@ public: virtual ValueExprNode* pass1(thread_db* tdbb, CompilerScratch* csb); public: - const MetaName relationName; + const QualifiedName relationName; const MetaName fieldName; private: @@ -839,10 +862,10 @@ public: private: static dsql_fld* resolveContext(DsqlCompilerScratch* dsqlScratch, - const MetaName& qualifier, dsql_ctx* context); + const QualifiedName& qualifier, dsql_ctx* context); public: - MetaName dsqlQualifier; + QualifiedName dsqlQualifier; MetaName dsqlName; dsql_ctx* const dsqlContext; dsql_fld* const dsqlField; @@ -860,7 +883,7 @@ class GenIdNode final : public TypedNode { public: GenIdNode(MemoryPool& pool, bool aDialect1, - const MetaName& name, + const QualifiedName& name, ValueExprNode* aArg, bool aImplicit, bool aIdentity); @@ -987,7 +1010,7 @@ public: void fixMinSInt128(MemoryPool& pool); public: - const IntlString* dsqlStr = nullptr; + NestConst dsqlStr; dsc litDesc; USHORT litNumStringLength = 0; }; @@ -1671,7 +1694,7 @@ public: class RecordKeyNode final : public TypedNode { public: - RecordKeyNode(MemoryPool& pool, UCHAR aBlrOp, const MetaName& aDsqlQualifier = NULL); + RecordKeyNode(MemoryPool& pool, UCHAR aBlrOp, const QualifiedName& aDsqlQualifier = {}); static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp); @@ -1748,7 +1771,7 @@ private: void raiseError(dsql_ctx* context) const; public: - MetaName dsqlQualifier; + QualifiedName dsqlQualifier; NestConst dsqlRelation; StreamType recStream; const UCHAR blrOp; diff --git a/src/dsql/NodePrinter.h b/src/dsql/NodePrinter.h index 4caa8fedc9..0f042b6b79 100644 --- a/src/dsql/NodePrinter.h +++ b/src/dsql/NodePrinter.h @@ -85,7 +85,7 @@ public: text += "<"; text += s; text += ">"; - text += value.toString(); + text += value.toQuotedString(); text += "\n"; diff --git a/src/dsql/Nodes.h b/src/dsql/Nodes.h index 4df8900d54..d328c4445b 100644 --- a/src/dsql/Nodes.h +++ b/src/dsql/Nodes.h @@ -173,8 +173,6 @@ public: }; -class DdlNode; - class DdlNode : public Node { public: @@ -183,14 +181,24 @@ public: { } + static void protectSystemSchema(const MetaName& name, ObjectType objType) + { + if (name == SYSTEM_SCHEMA) + { + Firebird::status_exception::raise( + Firebird::Arg::Gds(isc_dyn_cannot_mod_obj_sys_schema) << + getObjectName(objType)); + } + } + static bool deleteSecurityClass(thread_db* tdbb, jrd_tra* transaction, const MetaName& secClass); static void storePrivileges(thread_db* tdbb, jrd_tra* transaction, - const MetaName& name, int type, const char* privileges); + const QualifiedName& name, int type, const char* privileges); static void deletePrivilegesByRelName(thread_db* tdbb, jrd_tra* transaction, - const MetaName& name, int type); + const QualifiedName& name, int type); public: // Check permission on DDL operation. Return true if everything is OK. @@ -221,8 +229,8 @@ public: enum DdlTriggerWhen { DTW_BEFORE, DTW_AFTER }; static void executeDdlTrigger(thread_db* tdbb, jrd_tra* transaction, - DdlTriggerWhen when, int action, const MetaName& objectName, - const MetaName& oldNewObjectName, const Firebird::string& sqlText); + DdlTriggerWhen when, int action, const QualifiedName& objectName, + const QualifiedName& oldNewObjectName, const Firebird::string& sqlText); protected: typedef Firebird::Pair > MetaNameBidPair; @@ -246,9 +254,9 @@ protected: } void executeDdlTrigger(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, - DdlTriggerWhen when, int action, const MetaName& objectName, - const MetaName& oldNewObjectName); - void storeGlobalField(thread_db* tdbb, jrd_tra* transaction, MetaName& name, + DdlTriggerWhen when, int action, const QualifiedName& objectName, + const QualifiedName& oldNewObjectName); + void storeGlobalField(thread_db* tdbb, jrd_tra* transaction, QualifiedName& name, const TypeClause* field, const Firebird::string& computedSource = "", const BlrDebugWriter::BlrData& computedValue = BlrDebugWriter::BlrData()); @@ -468,6 +476,7 @@ public: TYPE_CURRENT_TIME, TYPE_CURRENT_TIMESTAMP, TYPE_CURRENT_ROLE, + TYPE_CURRENT_SCHEMA, TYPE_CURRENT_USER, TYPE_DERIVED_EXPR, TYPE_DECODE, @@ -1655,7 +1664,7 @@ public: class GeneratorItem : public Printable { public: - GeneratorItem(Firebird::MemoryPool& pool, const MetaName& name) + GeneratorItem(Firebird::MemoryPool& pool, const QualifiedName& name) : id(0), name(pool, name), secName(pool) {} @@ -1672,8 +1681,8 @@ public: public: SLONG id; - MetaName name; - MetaName secName; + QualifiedName name; + QualifiedName secName; }; typedef Firebird::Array StreamMap; diff --git a/src/dsql/PackageNodes.epp b/src/dsql/PackageNodes.epp index c13853ce09..4057fddf58 100644 --- a/src/dsql/PackageNodes.epp +++ b/src/dsql/PackageNodes.epp @@ -55,7 +55,7 @@ namespace { // Return function and procedure names (in the user charset) and optionally its details for a // given package. - void collectPackagedItems(thread_db* tdbb, jrd_tra* transaction, const MetaName& metaName, + void collectPackagedItems(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& packageName, SortedObjectsArray& functions, SortedObjectsArray& procedures, bool details) { @@ -64,7 +64,8 @@ namespace FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) FUN IN RDB$FUNCTIONS - WITH FUN.RDB$PACKAGE_NAME EQ metaName.c_str() + WITH FUN.RDB$SCHEMA_NAME EQ packageName.schema.c_str() AND + FUN.RDB$PACKAGE_NAME EQ packageName.object.c_str() { Signature function(FUN.RDB$FUNCTION_NAME); function.defined = !FUN.RDB$FUNCTION_BLR.NULL || !FUN.RDB$ENTRYPOINT.NULL; @@ -77,21 +78,23 @@ namespace FOR (REQUEST_HANDLE requestHandle2 TRANSACTION_HANDLE transaction) ARG IN RDB$FUNCTION_ARGUMENTS CROSS FLD IN RDB$FIELDS - WITH ARG.RDB$PACKAGE_NAME EQ metaName.c_str() AND + WITH ARG.RDB$SCHEMA_NAME EQ FUN.RDB$SCHEMA_NAME AND + ARG.RDB$PACKAGE_NAME EQ FUN.RDB$PACKAGE_NAME AND ARG.RDB$FUNCTION_NAME EQ FUN.RDB$FUNCTION_NAME AND + FLD.RDB$SCHEMA_NAME EQUIV ARG.RDB$FIELD_SOURCE_SCHEMA_NAME AND FLD.RDB$FIELD_NAME EQ ARG.RDB$FIELD_SOURCE { SignatureParameter parameter(*getDefaultMemoryPool()); parameter.number = ARG.RDB$ARGUMENT_POSITION; parameter.name = ARG.RDB$ARGUMENT_NAME; - parameter.fieldSource = ARG.RDB$FIELD_SOURCE; + parameter.fieldSource = QualifiedName(ARG.RDB$FIELD_SOURCE, ARG.RDB$FIELD_SOURCE_SCHEMA_NAME); parameter.mechanism = ARG.RDB$ARGUMENT_MECHANISM; if (!ARG.RDB$FIELD_NAME.NULL) - parameter.fieldName = ARG.RDB$FIELD_NAME; + parameter.fieldName = QualifiedName(ARG.RDB$FIELD_NAME); if (!ARG.RDB$RELATION_NAME.NULL) - parameter.relationName = ARG.RDB$RELATION_NAME; + parameter.relationName = QualifiedName(ARG.RDB$RELATION_NAME, ARG.RDB$RELATION_SCHEMA_NAME); if (!ARG.RDB$COLLATION_ID.NULL) parameter.collationId = ARG.RDB$COLLATION_ID; if (!ARG.RDB$NULL_FLAG.NULL) @@ -132,7 +135,8 @@ namespace FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PRC IN RDB$PROCEDURES - WITH PRC.RDB$PACKAGE_NAME EQ metaName.c_str() + WITH PRC.RDB$SCHEMA_NAME EQ packageName.schema.c_str() AND + PRC.RDB$PACKAGE_NAME EQ packageName.object.c_str() { Signature procedure(PRC.RDB$PROCEDURE_NAME); procedure.defined = !PRC.RDB$PROCEDURE_BLR.NULL || !PRC.RDB$ENTRYPOINT.NULL; @@ -142,21 +146,23 @@ namespace FOR (REQUEST_HANDLE requestHandle2 TRANSACTION_HANDLE transaction) PRM IN RDB$PROCEDURE_PARAMETERS CROSS FLD IN RDB$FIELDS - WITH PRM.RDB$PACKAGE_NAME EQ metaName.c_str() AND + WITH PRM.RDB$SCHEMA_NAME EQ PRC.RDB$SCHEMA_NAME AND + PRM.RDB$PACKAGE_NAME EQ PRC.RDB$PACKAGE_NAME AND PRM.RDB$PROCEDURE_NAME EQ PRC.RDB$PROCEDURE_NAME AND + FLD.RDB$SCHEMA_NAME EQUIV PRM.RDB$FIELD_SOURCE_SCHEMA_NAME AND FLD.RDB$FIELD_NAME EQ PRM.RDB$FIELD_SOURCE { SignatureParameter parameter(*getDefaultMemoryPool()); parameter.type = PRM.RDB$PARAMETER_TYPE; parameter.number = PRM.RDB$PARAMETER_NUMBER; parameter.name = PRM.RDB$PARAMETER_NAME; - parameter.fieldSource = PRM.RDB$FIELD_SOURCE; + parameter.fieldSource = QualifiedName(PRM.RDB$FIELD_SOURCE, PRM.RDB$FIELD_SOURCE_SCHEMA_NAME); parameter.mechanism = PRM.RDB$PARAMETER_MECHANISM; if (!PRM.RDB$FIELD_NAME.NULL) - parameter.fieldName = PRM.RDB$FIELD_NAME; + parameter.fieldName = QualifiedName(PRM.RDB$FIELD_NAME); if (!PRM.RDB$RELATION_NAME.NULL) - parameter.relationName = PRM.RDB$RELATION_NAME; + parameter.relationName = QualifiedName(PRM.RDB$RELATION_NAME, PRM.RDB$RELATION_SCHEMA_NAME); if (!PRM.RDB$COLLATION_ID.NULL) parameter.collationId = PRM.RDB$COLLATION_ID; if (!PRM.RDB$NULL_FLAG.NULL) @@ -216,6 +222,14 @@ string CreateAlterPackageNode::internalPrint(NodePrinter& printer) const DdlNode* CreateAlterPackageNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { + if (create) + dsqlScratch->qualifyNewName(name); + else + dsqlScratch->qualifyExistingName(name, obj_package_header); + + protectSystemSchema(name.schema, obj_package_header); + dsqlScratch->ddlSchema = name.schema; + if (alter && !items) return DdlNode::dsqlPass(dsqlScratch); @@ -235,18 +249,19 @@ DdlNode* CreateAlterPackageNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) CreateAlterFunctionNode* const fun = (*items)[i].function; ddlNode = fun; - if (functionNames.exist(fun->name)) + if (functionNames.exist(fun->name.object)) { status_exception::raise( Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_dyn_duplicate_package_item) << - Arg::Str("FUNCTION") << Arg::Str(fun->name)); + Arg::Str("FUNCTION") << fun->name.object); } - functionNames.add(fun->name); + functionNames.add(fun->name.object); fun->alter = true; - fun->package = name; + fun->name.schema = name.schema; + fun->name.package = name.object; break; } @@ -255,18 +270,19 @@ DdlNode* CreateAlterPackageNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) CreateAlterProcedureNode* const proc = (*items)[i].procedure; ddlNode = proc; - if (procedureNames.exist(proc->name)) + if (procedureNames.exist(proc->name.object)) { status_exception::raise( Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_dyn_duplicate_package_item) << - Arg::Str("PROCEDURE") << Arg::Str(proc->name)); + Arg::Str("PROCEDURE") << proc->name.object); } - procedureNames.add(proc->name); + procedureNames.add(proc->name.object); proc->alter = true; - proc->package = name; + proc->name.schema = name.schema; + proc->name.package = name.object; break; } @@ -280,6 +296,7 @@ DdlNode* CreateAlterPackageNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) FB_NEW_POOL(pool) DsqlCompilerScratch(pool, dsqlScratch->getAttachment(), dsqlScratch->getTransaction(), itemStatement); + itemScratch->ddlSchema = name.schema; itemScratch->clientDialect = dsqlScratch->clientDialect; itemScratch->flags |= DsqlCompilerScratch::FLAG_DDL; itemScratch->package = name; @@ -298,16 +315,13 @@ DdlNode* CreateAlterPackageNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) void CreateAlterPackageNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - dsc dscName; - dscName.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str()); - if (alter) { - if (SCL_check_package(tdbb, &dscName, SCL_alter) || !create) + if (SCL_check_package(tdbb, name, SCL_alter) || !create) return; } - SCL_check_create_access(tdbb, obj_packages); + SCL_check_create_access(tdbb, obj_packages, name.schema); } @@ -332,7 +346,7 @@ void CreateAlterPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlS if (!executeAlterIndividualParameters(tdbb, dsqlScratch, transaction)) status_exception::raise( Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_dyn_package_not_found) << Arg::Str(name)); + Arg::Gds(isc_dyn_package_not_found) << name.toQuotedString()); } else if (!executeAlter(tdbb, dsqlScratch, transaction)) { @@ -342,14 +356,14 @@ void CreateAlterPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlS { status_exception::raise( Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_dyn_package_not_found) << Arg::Str(name)); + Arg::Gds(isc_dyn_package_not_found) << name.toQuotedString()); } } - dsc desc; - desc.makeText(name.length(), ttype_metadata, - (UCHAR*) const_cast(name.c_str())); // safe const_cast - DFW_post_work(transaction, dfw_modify_package_header, &desc, 0); + dsc schemaDesc, nameDesc; + schemaDesc.makeText(name.schema.length(), ttype_metadata, (UCHAR*) const_cast(name.schema.c_str())); + nameDesc.makeText(name.object.length(), ttype_metadata, (UCHAR*) const_cast(name.object.c_str())); + DFW_post_work(transaction, dfw_modify_package_header, &nameDesc, &schemaDesc, 0); } else executeCreate(tdbb, dsqlScratch, transaction); @@ -367,8 +381,7 @@ void CreateAlterPackageNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_package_header)) return; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_CREATE_PACKAGE, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_PACKAGE, name, {}); DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_package_header); @@ -377,8 +390,11 @@ void CreateAlterPackageNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PKG IN RDB$PACKAGES USING { + PKG.RDB$SCHEMA_NAME.NULL = FALSE; + strcpy(PKG.RDB$SCHEMA_NAME, name.schema.c_str()); + PKG.RDB$PACKAGE_NAME.NULL = FALSE; - strcpy(PKG.RDB$PACKAGE_NAME, name.c_str()); + strcpy(PKG.RDB$PACKAGE_NAME, name.object.c_str()); PKG.RDB$SYSTEM_FLAG.NULL = FALSE; PKG.RDB$SYSTEM_FLAG = 0; @@ -405,8 +421,7 @@ void CreateAlterPackageNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* executeItems(tdbb, dsqlScratch, transaction); - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_PACKAGE, - name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_PACKAGE, name, {}); } @@ -420,12 +435,12 @@ bool CreateAlterPackageNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PKG IN RDB$PACKAGES - WITH PKG.RDB$PACKAGE_NAME EQ name.c_str() + WITH PKG.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + PKG.RDB$PACKAGE_NAME EQ name.object.c_str() { modified = true; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_ALTER_PACKAGE, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_PACKAGE, name, {}); SortedObjectsArray existingFuncs(pool); SortedObjectsArray existingProcs(pool); @@ -436,8 +451,7 @@ bool CreateAlterPackageNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* { if (!functionNames.exist(i->name)) { - DropFunctionNode dropNode(pool, i->name); - dropNode.package = name; + DropFunctionNode dropNode(pool, QualifiedName(i->name, name.schema, name.object)); dropNode.dsqlPass(dsqlScratch); dropNode.executeDdl(tdbb, dsqlScratch, transaction, true); } @@ -448,8 +462,7 @@ bool CreateAlterPackageNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* { if (!procedureNames.exist(i->name)) { - DropProcedureNode dropNode(pool, i->name); - dropNode.package = name; + DropProcedureNode dropNode(pool, QualifiedName(i->name, name.schema, name.object)); dropNode.dsqlPass(dsqlScratch); dropNode.executeDdl(tdbb, dsqlScratch, transaction, true); } @@ -474,10 +487,10 @@ bool CreateAlterPackageNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* owner = PKG.RDB$OWNER_NAME; - dsc desc; - desc.makeText(name.length(), ttype_metadata, - (UCHAR*) const_cast(name.c_str())); // safe const_cast - DFW_post_work(transaction, dfw_drop_package_body, &desc, 0); + dsc schemaDesc, nameDesc; + schemaDesc.makeText(name.schema.length(), ttype_metadata, (UCHAR*) const_cast(name.schema.c_str())); + nameDesc.makeText(name.object.length(), ttype_metadata, (UCHAR*) const_cast(name.object.c_str())); + DFW_post_work(transaction, dfw_drop_package_body, &nameDesc, &schemaDesc, 0); } END_FOR @@ -485,8 +498,7 @@ bool CreateAlterPackageNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* { executeItems(tdbb, dsqlScratch, transaction); - executeDdlTrigger(tdbb, dsqlScratch, transaction, - DTW_AFTER, DDL_TRIGGER_ALTER_PACKAGE, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_PACKAGE, name, {}); } return modified; @@ -500,12 +512,12 @@ bool CreateAlterPackageNode::executeAlterIndividualParameters(thread_db* tdbb, D FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PKG IN RDB$PACKAGES - WITH PKG.RDB$PACKAGE_NAME EQ name.c_str() + WITH PKG.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + PKG.RDB$PACKAGE_NAME EQ name.object.c_str() { modified = true; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_ALTER_PACKAGE, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_PACKAGE, name, {}); MODIFY PKG if (ssDefiner.has_value()) @@ -523,10 +535,7 @@ bool CreateAlterPackageNode::executeAlterIndividualParameters(thread_db* tdbb, D END_FOR if (modified) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, - DTW_AFTER, DDL_TRIGGER_ALTER_PACKAGE, name, NULL); - } + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_PACKAGE, name, {}); return modified; } @@ -568,14 +577,11 @@ string DropPackageNode::internalPrint(NodePrinter& printer) const void DropPackageNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - dsc dscName; - dscName.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str()); - SCL_check_package(tdbb, &dscName, SCL_drop); + SCL_check_package(tdbb, name, SCL_drop); } -void DropPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - jrd_tra* transaction) +void DropPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { MemoryPool& pool = dsqlScratch->getPool(); @@ -587,22 +593,22 @@ void DropPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PKG IN RDB$PACKAGES - WITH PKG.RDB$PACKAGE_NAME EQ name.c_str() + WITH PKG.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + PKG.RDB$PACKAGE_NAME EQ name.object.c_str() { found = true; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_DROP_PACKAGE, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_PACKAGE, name, {}); ERASE PKG; if (!PKG.RDB$SECURITY_CLASS.NULL) deleteSecurityClass(tdbb, transaction, PKG.RDB$SECURITY_CLASS); - dsc desc; - desc.makeText(name.length(), ttype_metadata, - (UCHAR*) const_cast(name.c_str())); // safe const_cast - DFW_post_work(transaction, dfw_drop_package_header, &desc, 0); + dsc schemaDesc, nameDesc; + schemaDesc.makeText(name.schema.length(), ttype_metadata, (UCHAR*) const_cast(name.schema.c_str())); + nameDesc.makeText(name.object.length(), ttype_metadata, (UCHAR*) const_cast(name.object.c_str())); + DFW_post_work(transaction, dfw_drop_package_header, &nameDesc, &schemaDesc, 0); } END_FOR @@ -610,7 +616,7 @@ void DropPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, { status_exception::raise( Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_dyn_package_not_found) << Arg::Str(name)); + Arg::Gds(isc_dyn_package_not_found) << name.toQuotedString()); } SortedObjectsArray existingFuncs(pool); @@ -620,8 +626,7 @@ void DropPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, for (SortedObjectsArray::iterator i = existingFuncs.begin(); i != existingFuncs.end(); ++i) { - DropFunctionNode dropNode(pool, i->name); - dropNode.package = name; + DropFunctionNode dropNode(pool, QualifiedName(i->name, name.schema, name.object)); dropNode.dsqlPass(dsqlScratch); dropNode.executeDdl(tdbb, dsqlScratch, transaction, true); } @@ -629,8 +634,7 @@ void DropPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, for (SortedObjectsArray::iterator i = existingProcs.begin(); i != existingProcs.end(); ++i) { - DropProcedureNode dropNode(pool, i->name); - dropNode.package = name; + DropProcedureNode dropNode(pool, QualifiedName(i->name, name.schema, name.object)); dropNode.dsqlPass(dsqlScratch); dropNode.executeDdl(tdbb, dsqlScratch, transaction, true); } @@ -639,9 +643,12 @@ void DropPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PRIV IN RDB$USER_PRIVILEGES - WITH ((PRIV.RDB$RELATION_NAME EQ name.c_str() AND - PRIV.RDB$OBJECT_TYPE = obj_package_header) OR - (PRIV.RDB$USER EQ name.c_str() AND PRIV.RDB$USER_TYPE = obj_package_header)) AND + WITH ((PRIV.RDB$RELATION_SCHEMA_NAME EQ name.schema.c_str() AND + PRIV.RDB$RELATION_NAME EQ name.object.c_str() AND + PRIV.RDB$OBJECT_TYPE = obj_package_header) OR + (PRIV.RDB$USER_SCHEMA_NAME EQ name.schema.c_str() AND + PRIV.RDB$USER EQ name.object.c_str() AND + PRIV.RDB$USER_TYPE = obj_package_header)) AND PRIV.RDB$GRANTOR NOT MISSING { ERASE PRIV; @@ -649,10 +656,7 @@ void DropPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, END_FOR if (found) - { - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_PACKAGE, - name, NULL); - } + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_PACKAGE, name, {}); savePoint.release(); // everything is ok } @@ -676,6 +680,10 @@ string CreatePackageBodyNode::internalPrint(NodePrinter& printer) const DdlNode* CreatePackageBodyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { + dsqlScratch->qualifyExistingName(name, obj_package_header); + protectSystemSchema(name.schema, obj_package_header); + dsqlScratch->ddlSchema = name.schema; + MemoryPool& pool = dsqlScratch->getPool(); source.ltrim("\n\r\t "); @@ -701,17 +709,18 @@ DdlNode* CreatePackageBodyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) CreateAlterFunctionNode* const fun = (*arrays[i])[j].function; ddlNode = fun; - if (functionNames[i].exist(fun->name)) + if (functionNames[i].exist(fun->name.object)) { status_exception::raise( Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_dyn_duplicate_package_item) << - Arg::Str("FUNCTION") << Arg::Str(fun->name)); + Arg::Str("FUNCTION") << fun->name.object); } - functionNames[i].add(fun->name); + functionNames[i].add(fun->name.object); - fun->package = name; + fun->name.schema = name.schema; + fun->name.package = name.object; fun->create = true; if (arrays[i] == items) @@ -725,17 +734,18 @@ DdlNode* CreatePackageBodyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) CreateAlterProcedureNode* const proc = (*arrays[i])[j].procedure; ddlNode = proc; - if (procedureNames[i].exist(proc->name)) + if (procedureNames[i].exist(proc->name.object)) { status_exception::raise( Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_dyn_duplicate_package_item) << - Arg::Str("PROCEDURE") << Arg::Str(proc->name)); + Arg::Str("PROCEDURE") << proc->name.object); } - procedureNames[i].add(proc->name); + procedureNames[i].add(proc->name.object); - proc->package = name; + proc->name.schema = name.schema; + proc->name.package = name.object; proc->create = true; if (arrays[i] == items) @@ -754,6 +764,7 @@ DdlNode* CreatePackageBodyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) FB_NEW_POOL(pool) DsqlCompilerScratch(pool, dsqlScratch->getAttachment(), dsqlScratch->getTransaction(), itemStatement); + itemScratch->ddlSchema = name.schema; itemScratch->clientDialect = dsqlScratch->clientDialect; itemScratch->flags |= DsqlCompilerScratch::FLAG_DDL; itemScratch->package = name; @@ -773,12 +784,11 @@ DdlNode* CreatePackageBodyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) void CreatePackageBodyNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - SCL_check_create_access(tdbb, obj_packages); + SCL_check_create_access(tdbb, obj_packages, name.schema); } -void CreatePackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - jrd_tra* transaction) +void CreatePackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { MemoryPool& pool = dsqlScratch->getPool(); Attachment* attachment = transaction->getAttachment(); @@ -791,7 +801,8 @@ void CreatePackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlSc FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PKG IN RDB$PACKAGES - WITH PKG.RDB$PACKAGE_NAME EQ name.c_str() + WITH PKG.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + PKG.RDB$PACKAGE_NAME EQ name.object.c_str() { if (!PKG.RDB$VALID_BODY_FLAG.NULL && PKG.RDB$VALID_BODY_FLAG != 0) { @@ -800,11 +811,10 @@ void CreatePackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlSc status_exception::raise( Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_dyn_package_body_exists) << Arg::Str(name)); + Arg::Gds(isc_dyn_package_body_exists) << name.toQuotedString()); } - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_CREATE_PACKAGE_BODY, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_PACKAGE_BODY, name, {}); MODIFY PKG PKG.RDB$VALID_BODY_FLAG.NULL = FALSE; @@ -824,7 +834,7 @@ void CreatePackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlSc { status_exception::raise( Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_dyn_package_not_found) << Arg::Str(name)); + Arg::Gds(isc_dyn_package_not_found) << name.toQuotedString()); } SortedObjectsArray headerFuncs(pool); @@ -861,18 +871,18 @@ void CreatePackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlSc CreateAlterFunctionNode* func = elem.function; if (arrays[i] == items) - func->privateScope = !headerFuncs.exist(Signature(func->name)); - else if (existingFuncs.exist(Signature(func->name))) + func->privateScope = !headerFuncs.exist(Signature(func->name.object)); + else if (existingFuncs.exist(Signature(func->name.object))) { status_exception::raise( Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_dyn_duplicate_package_item) << - Arg::Str("FUNCTION") << Arg::Str(func->name)); + Arg::Str("FUNCTION") << func->name.toQuotedString()); } func->packageOwner = owner; func->preserveDefaults = - existingFuncs.exist(Signature(func->name)) && arrays[i] == items; + existingFuncs.exist(Signature(func->name.object)) && arrays[i] == items; func->executeDdl(tdbb, elem.dsqlScratch, transaction, true); break; } @@ -882,18 +892,18 @@ void CreatePackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlSc CreateAlterProcedureNode* proc = elem.procedure; if (arrays[i] == items) - proc->privateScope = !headerProcs.exist(Signature(proc->name)); - else if (existingProcs.exist(Signature(proc->name))) + proc->privateScope = !headerProcs.exist(Signature(proc->name.object)); + else if (existingProcs.exist(Signature(proc->name.object))) { status_exception::raise( Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_dyn_duplicate_package_item) << - Arg::Str("PROCEDURE") << Arg::Str(proc->name)); + Arg::Str("PROCEDURE") << proc->name.toQuotedString()); } proc->packageOwner = owner; proc->preserveDefaults = - existingProcs.exist(Signature(proc->name)) && arrays[i] == items; + existingProcs.exist(Signature(proc->name.object)) && arrays[i] == items; proc->executeDdl(tdbb, elem.dsqlScratch, transaction, true); break; } @@ -914,12 +924,12 @@ void CreatePackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlSc if (!found || !newFuncs[pos].defined) { status_exception::raise( - Arg::Gds(isc_dyn_funcnotdef_package) << i->name.c_str() << name.c_str()); + Arg::Gds(isc_dyn_funcnotdef_package) << i->name << name.toQuotedString()); } else if (newFuncs[pos] != *i) { status_exception::raise( - Arg::Gds(isc_dyn_funcsignat_package) << i->name.c_str() << name.c_str()); + Arg::Gds(isc_dyn_funcsignat_package) << i->name << name.toQuotedString()); } } @@ -932,17 +942,16 @@ void CreatePackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlSc if (!found || !newProcs[pos].defined) { status_exception::raise( - Arg::Gds(isc_dyn_procnotdef_package) << i->name.c_str() << name.c_str()); + Arg::Gds(isc_dyn_procnotdef_package) << i->name << name.toQuotedString()); } else if (newProcs[pos] != *i) { status_exception::raise( - Arg::Gds(isc_dyn_procsignat_package) << i->name.c_str() << name.c_str()); + Arg::Gds(isc_dyn_procsignat_package) << i->name << name.toQuotedString()); } } - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, - DDL_TRIGGER_CREATE_PACKAGE_BODY, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_PACKAGE_BODY, name, {}); savePoint.release(); // everything is ok } @@ -964,9 +973,7 @@ string DropPackageBodyNode::internalPrint(NodePrinter& printer) const void DropPackageBodyNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) { - dsc dscName; - dscName.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str()); - SCL_check_package(tdbb, &dscName, SCL_drop); + SCL_check_package(tdbb, name, SCL_drop); } @@ -983,21 +990,21 @@ void DropPackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PKG IN RDB$PACKAGES - WITH PKG.RDB$PACKAGE_NAME EQ name.c_str() + WITH PKG.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + PKG.RDB$PACKAGE_NAME EQ name.object.c_str() { found = true; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, - DDL_TRIGGER_DROP_PACKAGE_BODY, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_PACKAGE_BODY, name, {}); MODIFY PKG PKG.RDB$VALID_BODY_FLAG.NULL = TRUE; PKG.RDB$PACKAGE_BODY_SOURCE.NULL = TRUE; - dsc desc; - desc.makeText(name.length(), ttype_metadata, - (UCHAR*) const_cast(name.c_str())); // safe const_cast - DFW_post_work(transaction, dfw_drop_package_body, &desc, 0); + dsc schemaDesc, nameDesc; + schemaDesc.makeText(name.schema.length(), ttype_metadata, (UCHAR*) const_cast(name.schema.c_str())); + nameDesc.makeText(name.object.length(), ttype_metadata, (UCHAR*) const_cast(name.object.c_str())); + DFW_post_work(transaction, dfw_drop_package_body, &nameDesc, &schemaDesc, 0); END_MODIFY } END_FOR @@ -1012,19 +1019,19 @@ void DropPackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra status_exception::raise( Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_dyn_package_not_found) << Arg::Str(name)); + Arg::Gds(isc_dyn_package_not_found) << name.toQuotedString()); } requestHandle.reset(tdbb, drq_m_pkg_fun, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) FUN IN RDB$FUNCTIONS - WITH FUN.RDB$PACKAGE_NAME EQ name.c_str() + WITH FUN.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + FUN.RDB$PACKAGE_NAME EQ name.object.c_str() { if (!FUN.RDB$PRIVATE_FLAG.NULL && FUN.RDB$PRIVATE_FLAG != 0) { - DropFunctionNode dropNode(pool, FUN.RDB$FUNCTION_NAME); - dropNode.package = name; + DropFunctionNode dropNode(pool, QualifiedName(FUN.RDB$FUNCTION_NAME, name.schema, name.object)); dropNode.dsqlPass(dsqlScratch); dropNode.executeDdl(tdbb, dsqlScratch, transaction, true); } @@ -1046,12 +1053,12 @@ void DropPackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PRC IN RDB$PROCEDURES - WITH PRC.RDB$PACKAGE_NAME EQ name.c_str() + WITH PRC.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + PRC.RDB$PACKAGE_NAME EQ name.object.c_str() { if (!PRC.RDB$PRIVATE_FLAG.NULL && PRC.RDB$PRIVATE_FLAG != 0) { - DropProcedureNode dropNode(pool, PRC.RDB$PROCEDURE_NAME); - dropNode.package = name; + DropProcedureNode dropNode(pool, QualifiedName(PRC.RDB$PROCEDURE_NAME, name.schema, name.object)); dropNode.dsqlPass(dsqlScratch); dropNode.executeDdl(tdbb, dsqlScratch, transaction, true); } @@ -1068,8 +1075,7 @@ void DropPackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra } END_FOR - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, - DDL_TRIGGER_DROP_PACKAGE_BODY, name, NULL); + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_PACKAGE_BODY, name, {}); savePoint.release(); // everything is ok } diff --git a/src/dsql/PackageNodes.h b/src/dsql/PackageNodes.h index 23868292dd..042f395562 100644 --- a/src/dsql/PackageNodes.h +++ b/src/dsql/PackageNodes.h @@ -68,7 +68,7 @@ public: }; public: - CreateAlterPackageNode(MemoryPool& pool, const MetaName& aName) + CreateAlterPackageNode(MemoryPool& pool, const QualifiedName& aName) : DdlNode(pool), name(pool, aName), create(true), @@ -94,7 +94,7 @@ protected: Firebird::Arg::Gds(createAlterCode(create, alter, isc_dsql_create_pack_failed, isc_dsql_alter_pack_failed, isc_dsql_create_alter_pack_failed)) << - name; + name.toQuotedString(); } private: @@ -104,7 +104,7 @@ private: void executeItems(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); public: - MetaName name; + QualifiedName name; bool create; bool alter; bool createIfNotExistsOnly = false; @@ -122,7 +122,7 @@ private: class DropPackageNode : public DdlNode { public: - DropPackageNode(MemoryPool& pool, const MetaName& aName) + DropPackageNode(MemoryPool& pool, const QualifiedName& aName) : DdlNode(pool), name(pool, aName), silent(false) @@ -134,15 +134,29 @@ public: virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + if (recreate) + dsqlScratch->qualifyNewName(name); + else + dsqlScratch->qualifyExistingName(name, obj_package_header); + + protectSystemSchema(name.schema, obj_package_header); + dsqlScratch->ddlSchema = name.schema; + + return DdlNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_drop_pack_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_drop_pack_failed) << name.toQuotedString(); } public: - MetaName name; + QualifiedName name; bool silent; + bool recreate = false; }; @@ -153,7 +167,7 @@ typedef RecreateNode* declaredItems; Firebird::Array* items; @@ -190,7 +204,7 @@ private: class DropPackageBodyNode : public DdlNode { public: - DropPackageBodyNode(MemoryPool& pool, const MetaName& aName) + DropPackageBodyNode(MemoryPool& pool, const QualifiedName& aName) : DdlNode(pool), name(pool, aName), silent(false) @@ -202,15 +216,25 @@ public: virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + dsqlScratch->qualifyExistingName(name, obj_package_header); + protectSystemSchema(name.schema, obj_package_header); + dsqlScratch->ddlSchema = name.schema; + + return DdlNode::dsqlPass(dsqlScratch); + } + protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_drop_pack_body_failed) << name; + statusVector << Firebird::Arg::Gds(isc_dsql_drop_pack_body_failed) << name.toQuotedString(); } public: - MetaName name; + QualifiedName name; bool silent; // Unused. Just to please RecreateNode template. + bool recreate = false; }; diff --git a/src/dsql/Parser.cpp b/src/dsql/Parser.cpp index c60bea0290..4b82e82659 100644 --- a/src/dsql/Parser.cpp +++ b/src/dsql/Parser.cpp @@ -408,28 +408,13 @@ int Parser::yylexAux() if (tok_class & CHR_INTRODUCER) { - // The Introducer (_) is skipped, all other idents are copied - // to become the name of the character set. - char* p = string; - for (; lex.ptr < lex.end && (classes(*lex.ptr) & CHR_IDENT); lex.ptr++) - { - if (lex.ptr >= lex.end) - return -1; + if (lex.ptr >= lex.end) + return -1; - check_copy_incr(p, UPPER7(*lex.ptr), string); - } + if (classes(*lex.ptr) & (CHR_IDENT | CHR_QUOTE)) + return TOK_INTRODUCER; - check_bound(p, string); - - if (p > string + MAX_SQL_IDENTIFIER_LEN || p > string + METADATA_IDENTIFIER_CHAR_LEN) - yyabandon(yyposn, -104, isc_dyn_name_longer); - - *p = 0; - - // make a string value to hold the name, the name is resolved in pass1_constant. - yylval.metaNamePtr = FB_NEW_POOL(pool) MetaName(pool, string, p - string); - - return TOK_INTRODUCER; + return (UCHAR) c; } // parse a quoted string, being sure to look for double quotes @@ -711,15 +696,14 @@ int Parser::yylexAux() if (introducerCharSetName) { - const auto symbol = METD_get_charset(scratch->getTransaction(), - introducerCharSetName->length(), introducerCharSetName->c_str()); + const auto symbol = METD_get_charset(scratch->getTransaction(), *introducerCharSetName); if (!symbol) { // character set name is not defined ERRD_post( Arg::Gds(isc_sqlerr) << Arg::Num(-504) << - Arg::Gds(isc_charset_not_found) << *introducerCharSetName); + Arg::Gds(isc_charset_not_found) << introducerCharSetName->toQuotedString()); } currentCharSet = INTL_charset_lookup(tdbb, symbol->intlsym_ttype); diff --git a/src/dsql/Parser.h b/src/dsql/Parser.h index 51cb519562..d1a34f727b 100644 --- a/src/dsql/Parser.h +++ b/src/dsql/Parser.h @@ -225,6 +225,11 @@ private: return (name ? *name : MetaName()); } + QualifiedName optName(QualifiedName* name) + { + return (name ? *name : QualifiedName()); + } + void transformString(const char* start, unsigned length, Firebird::string& dest); Firebird::string makeParseStr(const Position& p1, const Position& p2); ParameterNode* make_parameter(); @@ -323,6 +328,11 @@ private: return clause.hasData(); } + bool isDuplicateClause(const QualifiedName& clause) + { + return clause.object.hasData(); + } + bool isDuplicateClause(const Firebird::TriState& clause) { return clause.isAssigned(); @@ -340,7 +350,7 @@ private: return clause.hasData(); } - void setCollate(TypeClause* fld, MetaName* name) + void setCollate(TypeClause* fld, QualifiedName* name) { if (name) setClause(fld->collate, "COLLATE", *name); @@ -380,7 +390,7 @@ private: DsqlStatement* parsedStatement; // Parser feedback for lexer - MetaName* introducerCharSetName = nullptr; + QualifiedName* introducerCharSetName = nullptr; // These value/posn are taken from the lexer YYSTYPE yylval; diff --git a/src/dsql/StmtNodes.cpp b/src/dsql/StmtNodes.cpp index 3252da179b..2bf62f1e6c 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -247,10 +247,10 @@ void AssignmentNode::validateTarget(CompilerScratch* csb, const ValueExprNode* t if (error) { jrd_fld* field = MET_get_field(tail->csb_relation, fieldNode->fieldId); - string fieldName(field ? field->fld_name.c_str() : ""); + string fieldName(field ? field->fld_name.toQuotedString() : ""); if (field && tail->csb_relation) - fieldName = string(tail->csb_relation->rel_name.c_str()) + "." + fieldName; + fieldName = tail->csb_relation->rel_name.toQuotedString() + "." + fieldName; ERR_post(Arg::Gds(isc_read_only_field) << fieldName.c_str()); } @@ -266,8 +266,10 @@ void AssignmentNode::dsqlValidateTarget(const ValueExprNode* target) if (fieldNode && fieldNode->context && (fieldNode->context->ctx_flags & (CTX_system | CTX_cursor)) == CTX_cursor) { + const auto contextAliases = fieldNode->context->getConcatenatedAlias(); + ERR_post(Arg::Gds(isc_read_only_field) << - (fieldNode->context->ctx_alias + "." + fieldNode->name.c_str())); + (contextAliases + "." + fieldNode->name.toQuotedString())); } } @@ -733,7 +735,7 @@ bool BlockNode::testAndFixupError(thread_db* tdbb, Request* request, const Excep { FB_SQLSTATE_STRING sqlstate; fb_sqlstate(sqlstate, statusVector->getErrors()); - if (conditions[i].name == sqlstate) + if (conditions[i].name.object == sqlstate) found = true; } break; @@ -1662,7 +1664,7 @@ DeclareSubFuncNode* DeclareSubFuncNode::dsqlPass(DsqlCompilerScratch* dsqlScratc dsqlFunction = implemetingForward ? prevDecl->dsqlFunction : FB_NEW_POOL(pool) dsql_udf(pool); dsqlFunction->udf_flags = UDF_subfunc; - dsqlFunction->udf_name.identifier = name; + dsqlFunction->udf_name.object = name; fb_assert(dsqlBlock->returns.getCount() == 1); const auto returnType = dsqlBlock->returns[0]->type; @@ -1990,7 +1992,7 @@ DeclareSubProcNode* DeclareSubProcNode::dsqlPass(DsqlCompilerScratch* dsqlScratc dsqlProcedure = implemetingForward ? prevDecl->dsqlProcedure : FB_NEW_POOL(pool) dsql_prc(pool); dsqlProcedure->prc_flags = PRC_subproc; - dsqlProcedure->prc_name.identifier = name; + dsqlProcedure->prc_name.object = name; dsqlProcedure->prc_in_count = USHORT(dsqlBlock->parameters.getCount()); dsqlProcedure->prc_out_count = USHORT(dsqlBlock->returns.getCount()); @@ -2298,6 +2300,8 @@ StmtNode* EraseNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { auto relation = dsqlRelation; + dsqlScratch->qualifyExistingName(relation->dsqlName, obj_relation); + const auto node = FB_NEW_POOL(dsqlScratch->getPool()) EraseNode(dsqlScratch->getPool()); node->dsqlCursorName = dsqlCursorName; node->dsqlSkipLocked = dsqlSkipLocked; @@ -2849,22 +2853,31 @@ DmlNode* ErrorHandlerNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScra case blr_sql_state: item.type = ExceptionItem::SQL_STATE; - csb->csb_blr_reader.getString(item.name); + csb->csb_blr_reader.getMetaName(item.name.object); break; case blr_gds_code: + { item.type = ExceptionItem::GDS_CODE; - csb->csb_blr_reader.getString(item.name); - item.name.lower(); - if (!(item.code = PAR_symbol_to_gdscode(item.name))) - PAR_error(csb, Arg::Gds(isc_codnotdef) << item.name); + string str; + csb->csb_blr_reader.getString(str); + str.lower(); + item.name.object = str; + if (!(item.code = PAR_symbol_to_gdscode(str))) + PAR_error(csb, Arg::Gds(isc_codnotdef) << item.name.object); break; + } case blr_exception: - { - csb->csb_blr_reader.getString(item.name); + case blr_exception2: + if (codeType == blr_exception2) + csb->csb_blr_reader.getMetaName(item.name.schema); + + csb->csb_blr_reader.getMetaName(item.name.object); + csb->qualifyExistingName(tdbb, item.name, obj_exception); + if (!MET_load_exception(tdbb, item)) - PAR_error(csb, Arg::Gds(isc_xcpnotdef) << item.name); + PAR_error(csb, Arg::Gds(isc_xcpnotdef) << item.name.toQuotedString()); if (csb->collectingDependencies()) { @@ -2874,7 +2887,6 @@ DmlNode* ErrorHandlerNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScra } break; - } case blr_default_code: item.type = ExceptionItem::XCP_DEFAULT; @@ -2927,17 +2939,26 @@ void ErrorHandlerNode::genBlr(DsqlCompilerScratch* dsqlScratch) case ExceptionItem::SQL_STATE: dsqlScratch->appendUChar(blr_sql_state); - dsqlScratch->appendNullString(i->name.c_str()); + dsqlScratch->appendNullString(i->name.object.c_str()); break; case ExceptionItem::GDS_CODE: dsqlScratch->appendUChar(blr_gds_code); - dsqlScratch->appendNullString(i->name.c_str()); + dsqlScratch->appendNullString(i->name.object.c_str()); break; case ExceptionItem::XCP_CODE: - dsqlScratch->appendUChar(blr_exception); - dsqlScratch->appendNullString(i->name.c_str()); + if (i->name.schema != dsqlScratch->ddlSchema) + { + dsqlScratch->appendUChar(blr_exception2); + dsqlScratch->appendNullString(i->name.schema.c_str()); + dsqlScratch->appendNullString(i->name.object.c_str()); + } + else + { + dsqlScratch->appendUChar(blr_exception); + dsqlScratch->appendNullString(i->name.object.c_str()); + } break; case ExceptionItem::XCP_DEFAULT: @@ -3033,44 +3054,57 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr { switch (subCode) { - case blr_invsel_procedure_type: + case blr_invsel_procedure_id: { - UCHAR procedureType = blrReader.getByte(); + bool isSub = false; + UCHAR procedureIdCode; - switch (procedureType) + while ((procedureIdCode = blrReader.getByte()) != blr_end) { - case blr_invsel_procedure_type_packaged: - blrReader.getMetaName(name.package); - break; + switch (procedureIdCode) + { + case blr_invsel_procedure_id_schema: + blrReader.getMetaName(name.schema); + break; - case blr_invsel_procedure_type_standalone: - case blr_invsel_procedure_type_sub: - break; + case blr_invsel_procedure_id_package: + blrReader.getMetaName(name.package); + break; - default: - PAR_error(csb, Arg::Gds(isc_random) << "Invalid blr_invsel_procedure_type"); - break; + case blr_invsel_procedure_id_name: + blrReader.getMetaName(name.object); + break; + + case blr_invsel_procedure_id_sub: + isSub = true; + break; + + default: + PAR_error(csb, Arg::Gds(isc_random) << "Invalid blr_invsel_procedure_id"); + break; + } } - blrReader.getMetaName(name.identifier); - - if (procedureType == blr_invsel_procedure_type_sub) + if (isSub) { for (auto curCsb = csb; curCsb && !node->procedure; curCsb = curCsb->mainCsb) { - if (const auto declareNode = curCsb->subProcedures.get(name.identifier)) + if (const auto declareNode = curCsb->subProcedures.get(name.object)) node->procedure = (*declareNode)->routine; } } else if (!node->procedure) + { + csb->qualifyExistingName(tdbb, name, obj_procedure); node->procedure = MET_lookup_procedure(tdbb, name, false); + } break; } case blr_invsel_procedure_in_arg_names: { - predateCheck(node->procedure, "blr_invsel_procedure_type", "blr_invsel_procedure_in_arg_names"); + predateCheck(node->procedure, "blr_invsel_procedure_id", "blr_invsel_procedure_in_arg_names"); predateCheck(!node->inputSources, "blr_invsel_procedure_in_arg_names", "blr_invsel_procedure_in_args"); @@ -3090,7 +3124,7 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr } case blr_invsel_procedure_in_args: - predateCheck(node->procedure, "blr_invsel_procedure_type", "blr_invsel_procedure_in_args"); + predateCheck(node->procedure, "blr_invsel_procedure_id", "blr_invsel_procedure_in_args"); inArgCount = blrReader.getWord(); node->inputSources = PAR_args(tdbb, csb, inArgCount, MAX(inArgCount, node->procedure->getInputFields().getCount())); @@ -3099,7 +3133,7 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr case blr_invsel_procedure_out_arg_names: { predateCheck(node->procedure, - "blr_invsel_procedure_type", "blr_invsel_procedure_out_arg_names"); + "blr_invsel_procedure_id", "blr_invsel_procedure_out_arg_names"); predateCheck(!node->outputTargets, "blr_invsel_procedure_out_arg_names", "blr_invsel_procedure_out_args"); @@ -3120,7 +3154,7 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr } case blr_invsel_procedure_out_args: - predateCheck(node->procedure, "blr_invsel_procedure_type", "blr_invsel_procedure_out_args"); + predateCheck(node->procedure, "blr_invsel_procedure_id", "blr_invsel_procedure_out_args"); outArgCount = blrReader.getWord(); node->outputTargets = PAR_args(tdbb, csb, outArgCount, outArgCount); break; @@ -3128,7 +3162,7 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr case blr_invsel_procedure_inout_arg_names: { predateCheck(node->procedure, - "blr_invsel_procedure_type", "blr_invsel_procedure_inout_arg_names"); + "blr_invsel_procedure_id", "blr_invsel_procedure_inout_arg_names"); predateCheck(!inOutArgs, "blr_invsel_procedure_inout_arg_names", "blr_invsel_procedure_inout_args"); @@ -3148,7 +3182,7 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr } case blr_invsel_procedure_inout_args: - predateCheck(node->procedure, "blr_invsel_procedure_type", "blr_invsel_procedure_inout_args"); + predateCheck(node->procedure, "blr_invsel_procedure_id", "blr_invsel_procedure_inout_args"); inOutArgCount = blrReader.getWord(); inOutArgs = PAR_args(tdbb, csb, inOutArgCount, inOutArgCount); break; @@ -3165,7 +3199,7 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr { const USHORT pid = blrReader.getWord(); if (!(node->procedure = MET_lookup_procedure_id(tdbb, pid, false, false, 0))) - name.identifier.printf("id %d", pid); + name.object.printf("id %d", pid); break; } @@ -3173,18 +3207,21 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr if (blrOp == blr_exec_proc2) blrReader.getMetaName(name.package); - blrReader.getMetaName(name.identifier); + blrReader.getMetaName(name.object); if (blrOp == blr_exec_subproc) { for (auto curCsb = csb; curCsb && !node->procedure; curCsb = curCsb->mainCsb) { - if (const auto declareNode = curCsb->subProcedures.get(name.identifier)) + if (const auto declareNode = curCsb->subProcedures.get(name.object)) node->procedure = (*declareNode)->routine; } } else + { + csb->qualifyExistingName(tdbb, name, obj_procedure); node->procedure = MET_lookup_procedure(tdbb, name, false); + } break; } @@ -3192,7 +3229,7 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr if (!node->procedure) { blrReader.setPos(blrStartPos); - PAR_error(csb, Arg::Gds(isc_prcnotdef) << name.toString()); + PAR_error(csb, Arg::Gds(isc_prcnotdef) << name.toQuotedString()); } if ((inOutArgs || inOutArgNames) && (node->inputSources || inArgNames || node->outputTargets || outArgNames)) @@ -3300,14 +3337,14 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr if (tdbb->getAttachment()->isGbak() || (tdbb->tdbb_flags & TDBB_replicator)) { PAR_warning( - Arg::Warning(isc_prcnotdef) << name.toString() << + Arg::Warning(isc_prcnotdef) << name.toQuotedString() << Arg::Warning(isc_modnotfound)); } else { csb->csb_blr_reader.setPos(blrStartPos); PAR_error(csb, - Arg::Gds(isc_prcnotdef) << name.toString() << + Arg::Gds(isc_prcnotdef) << name.toQuotedString() << Arg::Gds(isc_modnotfound)); } } @@ -3343,7 +3380,7 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr if (mismatchStatus.hasData()) { status_exception::raise(Arg::Gds(isc_prcmismat) << - node->procedure->getName().toString() << mismatchStatus); + node->procedure->getName().toQuotedString() << mismatchStatus); } if (csb->collectingDependencies() && !node->procedure->isSubRoutine()) @@ -3400,13 +3437,37 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr ExecProcedureNode* ExecProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { - auto& pool = dsqlScratch->getPool(); dsql_prc* procedure = nullptr; if (dsqlName.package.isEmpty()) { - DeclareSubProcNode* subProcedure = dsqlScratch->getSubProcedure(dsqlName.identifier); - procedure = subProcedure ? subProcedure->dsqlProcedure : NULL; + if (dsqlName.schema.isEmpty()) + { + if (const auto subProcedure = dsqlScratch->getSubProcedure(dsqlName.object)) + procedure = subProcedure->dsqlProcedure; + else if (dsqlScratch->package.object.hasData()) + { + const QualifiedName packagedName(dsqlName.object, + dsqlScratch->package.schema, dsqlScratch->package.object); + + if ((procedure = METD_get_procedure(dsqlScratch->getTransaction(), dsqlScratch, packagedName))) + dsqlName = packagedName; + } + + if (!procedure) + dsqlScratch->qualifyExistingName(dsqlName, obj_procedure); + } + else + { + QualifiedName packageName(dsqlName.schema); + dsqlScratch->qualifyExistingName(packageName, obj_package_header); + + if (MET_check_package_exists(JRD_get_thread_data(), packageName)) + { + dsqlName.schema = packageName.schema; + dsqlName.package = packageName.object; + } + } } if (!procedure) @@ -3416,13 +3477,24 @@ ExecProcedureNode* ExecProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) << Arg::Gds(isc_dsql_procedure_err) << - Arg::Gds(isc_random) << - dsqlName.toString()); + Arg::Gds(isc_random) << dsqlName.toQuotedString()); } + if (procedure->prc_private && procedure->prc_name.getSchemaAndPackage() != dsqlScratch->package) + { + status_exception::raise( + Arg::Gds(isc_private_procedure) << + procedure->prc_name.object << + procedure->prc_name.getSchemaAndPackage().toQuotedString()); + } + + dsqlName = procedure->prc_name; + if (!dsqlScratch->isPsql()) dsqlScratch->getDsqlStatement()->setType(DsqlStatement::TYPE_EXEC_PROCEDURE); + auto& pool = dsqlScratch->getPool(); + if (dsqlCallSyntax && !dsqlScratch->isPsql() && inputSources && inputSources->items.hasData()) { const auto positionalArgCount = inputSources->items.getCount() - @@ -3498,9 +3570,9 @@ ExecProcedureNode* ExecProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) paramNode->dsqlParameterIndex = parameter->par_index; DsqlDescMaker::fromField(¶meter->par_desc, field); - parameter->par_name = parameter->par_alias = field->fld_name.c_str(); - parameter->par_rel_name = procedure->prc_name.identifier.c_str(); - parameter->par_owner_name = procedure->prc_owner.c_str(); + parameter->par_name = parameter->par_alias = field->fld_name; + parameter->par_rel_name = procedure->prc_name; + parameter->par_owner_name = procedure->prc_owner; } field = field->fld_next; @@ -3530,9 +3602,9 @@ ExecProcedureNode* ExecProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) paramNode->dsqlParameterIndex = parameter->par_index; DsqlDescMaker::fromField(¶meter->par_desc, *field); - parameter->par_name = parameter->par_alias = (*field)->fld_name.c_str(); - parameter->par_rel_name = procedure->prc_name.identifier.c_str(); - parameter->par_owner_name = procedure->prc_owner.c_str(); + parameter->par_name = parameter->par_alias = (*field)->fld_name; + parameter->par_rel_name = procedure->prc_name; + parameter->par_owner_name = procedure->prc_owner; } } else @@ -3542,7 +3614,7 @@ ExecProcedureNode* ExecProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) } if (mismatchStatus.hasData()) - status_exception::raise(Arg::Gds(isc_prcmismat) << dsqlName.toString() << mismatchStatus); + status_exception::raise(Arg::Gds(isc_prcmismat) << dsqlName.toQuotedString() << mismatchStatus); } } } @@ -3621,7 +3693,7 @@ ExecProcedureNode* ExecProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) } if (mismatchStatus.hasData()) - status_exception::raise(Arg::Gds(isc_prcmismat) << dsqlName.toString() << mismatchStatus); + status_exception::raise(Arg::Gds(isc_prcmismat) << dsqlName.toQuotedString() << mismatchStatus); } } @@ -3634,7 +3706,7 @@ ExecProcedureNode* ExecProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) const USHORT outCount = outputTargets ? outputTargets->items.getCount() : 0; if (outCount != procedure->prc_out_count) - ERRD_post(Arg::Gds(isc_prc_out_param_mismatch) << Arg::Str(dsqlName.toString())); + ERRD_post(Arg::Gds(isc_prc_out_param_mismatch) << Arg::Str(dsqlName.toQuotedString())); } node->outputTargets = dsqlPassArray(dsqlScratch, outputTargets); @@ -3689,9 +3761,9 @@ ValueListNode* ExecProcedureNode::explodeOutputs(DsqlCompilerScratch* dsqlScratc paramNode->dsqlParameterIndex = parameter->par_index; DsqlDescMaker::fromField(¶meter->par_desc, field); - parameter->par_name = parameter->par_alias = field->fld_name.c_str(); - parameter->par_rel_name = procedure->prc_name.identifier.c_str(); - parameter->par_owner_name = procedure->prc_owner.c_str(); + parameter->par_name = parameter->par_alias = field->fld_name; + parameter->par_rel_name = procedure->prc_name; + parameter->par_owner_name = procedure->prc_owner; } return output; @@ -3726,24 +3798,32 @@ void ExecProcedureNode::genBlr(DsqlCompilerScratch* dsqlScratch) } } - if (dsqlInputArgNames || dsqlOutputArgNames || dsqlCallSyntax) + if (dsqlInputArgNames || dsqlOutputArgNames || dsqlCallSyntax || dsqlName.schema != dsqlScratch->ddlSchema) { dsqlScratch->appendUChar(blr_invoke_procedure); - dsqlScratch->appendUChar(blr_invsel_procedure_type); + dsqlScratch->appendUChar(blr_invsel_procedure_id); - if (dsqlName.package.hasData()) - { - dsqlScratch->appendUChar(blr_invsel_procedure_type_packaged); - dsqlScratch->appendMetaString(dsqlName.package.c_str()); - } + if (dsqlProcedure->prc_flags & PRC_subproc) + dsqlScratch->appendUChar(blr_invsel_procedure_id_sub); else { - dsqlScratch->appendUChar((dsqlProcedure->prc_flags & PRC_subproc) ? - blr_invsel_procedure_type_sub : blr_invsel_procedure_type_standalone); + if (dsqlName.schema != dsqlScratch->ddlSchema) + { + dsqlScratch->appendUChar(blr_invsel_procedure_id_schema); + dsqlScratch->appendMetaString(dsqlName.schema.c_str()); + } + + if (dsqlName.package.hasData()) + { + dsqlScratch->appendUChar(blr_invsel_procedure_id_package); + dsqlScratch->appendMetaString(dsqlName.package.c_str()); + } } - dsqlScratch->appendMetaString(dsqlName.identifier.c_str()); + dsqlScratch->appendUChar(blr_invsel_procedure_id_name); + dsqlScratch->appendMetaString(dsqlName.object.c_str()); + dsqlScratch->appendUChar(blr_end); const bool useInOut = dsqlScratch->isPsql() && dsqlCallSyntax; @@ -3799,7 +3879,7 @@ void ExecProcedureNode::genBlr(DsqlCompilerScratch* dsqlScratch) else dsqlScratch->appendUChar((dsqlProcedure->prc_flags & PRC_subproc) ? blr_exec_subproc : blr_exec_proc); - dsqlScratch->appendMetaString(dsqlName.identifier.c_str()); + dsqlScratch->appendMetaString(dsqlName.object.c_str()); // Input parameters. if (inputSources) @@ -3884,12 +3964,12 @@ void ExecProcedureNode::executeProcedure(thread_db* tdbb, Request* request) cons { status_exception::raise( Arg::Gds(isc_proc_pack_not_implemented) << - Arg::Str(procedure->getName().identifier) << Arg::Str(procedure->getName().package)); + Arg::Str(procedure->getName().object) << Arg::Str(procedure->getName().package)); } else if (!procedure->isDefined()) { status_exception::raise( - Arg::Gds(isc_prcnotdef) << Arg::Str(procedure->getName().toString()) << + Arg::Gds(isc_prcnotdef) << Arg::Str(procedure->getName().toQuotedString()) << Arg::Gds(isc_modnotfound)); } @@ -5129,7 +5209,7 @@ void ExecBlockNode::genBlr(DsqlCompilerScratch* dsqlScratch) const auto& variables = subRoutine ? dsqlScratch->outputVariables : dsqlScratch->variables; for (const auto variable : variables) - dsqlScratch->putLocalVariable(variable, nullptr, {}); + dsqlScratch->putLocalVariable(variable); dsqlScratch->setPsql(true); @@ -5189,62 +5269,78 @@ DmlNode* ExceptionNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch const UCHAR /*blrOp*/) { ExceptionNode* node = FB_NEW_POOL(pool) ExceptionNode(pool); - const UCHAR type = csb->csb_blr_reader.peekByte(); const USHORT codeType = csb->csb_blr_reader.getByte(); // Don't create ExceptionItem if blr_raise is used. - if (codeType != blr_raise) + if (codeType == blr_raise) + return node; + + ExceptionItem* const item = FB_NEW_POOL(pool) ExceptionItem(pool); + + switch (codeType) { - ExceptionItem* const item = FB_NEW_POOL(pool) ExceptionItem(pool); - - switch (codeType) + case blr_gds_code: { - case blr_gds_code: - item->type = ExceptionItem::GDS_CODE; - csb->csb_blr_reader.getString(item->name); - item->name.lower(); - if (!(item->code = PAR_symbol_to_gdscode(item->name))) - PAR_error(csb, Arg::Gds(isc_codnotdef) << item->name); - break; - - case blr_exception: - case blr_exception_msg: - case blr_exception_params: - { - csb->csb_blr_reader.getString(item->name); - if (!MET_load_exception(tdbb, *item)) - PAR_error(csb, Arg::Gds(isc_xcpnotdef) << item->name); - - if (csb->collectingDependencies()) - { - CompilerScratch::Dependency dependency(obj_exception); - dependency.number = item->code; - csb->addDependency(dependency); - } - } - break; - - default: - fb_assert(false); - break; + item->type = ExceptionItem::GDS_CODE; + string str; + csb->csb_blr_reader.getString(str); + str.lower(); + item->name.object = str; + if (!(item->code = PAR_symbol_to_gdscode(str))) + PAR_error(csb, Arg::Gds(isc_codnotdef) << item->name.object); + break; } - node->exception = item; + case blr_exception: + case blr_exception2: + case blr_exception3: + case blr_exception_msg: + case blr_exception_params: + if (codeType == blr_exception2 || codeType == blr_exception3) + csb->csb_blr_reader.getMetaName(item->name.schema); + + csb->csb_blr_reader.getMetaName(item->name.object); + csb->qualifyExistingName(tdbb, item->name, obj_exception); + + if (!MET_load_exception(tdbb, *item)) + PAR_error(csb, Arg::Gds(isc_xcpnotdef) << item->name.toQuotedString()); + + if (csb->collectingDependencies()) + { + CompilerScratch::Dependency dependency(obj_exception); + dependency.number = item->code; + csb->addDependency(dependency); + } + + if (codeType == blr_exception_msg || + (codeType == blr_exception3 && csb->csb_blr_reader.getByte() != 0)) + { + node->messageExpr = PAR_parse_value(tdbb, csb); + } + + if (codeType == blr_exception_params || codeType == blr_exception3) + { + const USHORT count = csb->csb_blr_reader.getWord(); + node->parameters = PAR_args(tdbb, csb, count, count); + } + + break; + + default: + fb_assert(false); + break; } - if (type == blr_exception_params) - { - const USHORT count = csb->csb_blr_reader.getWord(); - node->parameters = PAR_args(tdbb, csb, count, count); - } - else if (type == blr_exception_msg) - node->messageExpr = PAR_parse_value(tdbb, csb); + node->exception = item; return node; } StmtNode* ExceptionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { + if (exception) + dsqlScratch->qualifyExistingName(exception->name, obj_exception); + if (parameters && parameters->items.getCount() > MsgFormat::SAFEARG_MAX_ARG) { status_exception::raise( @@ -5287,29 +5383,69 @@ void ExceptionNode::genBlr(DsqlCompilerScratch* dsqlScratch) // If exception value is defined, it means we have user-defined exception message // here, so blr_exception_msg verb should be generated. - if (parameters) - dsqlScratch->appendUChar(blr_exception_params); - else if (messageExpr) - dsqlScratch->appendUChar(blr_exception_msg); - else if (exception->type == ExceptionItem::GDS_CODE) - dsqlScratch->appendUChar(blr_gds_code); - else // Otherwise go usual way, i.e. generate blr_exception. - dsqlScratch->appendUChar(blr_exception); - - dsqlScratch->appendNullString(exception->name.c_str()); - - // If exception parameters or value is defined, generate appropriate BLR verbs. - if (parameters) + if (exception->type == ExceptionItem::GDS_CODE) { - dsqlScratch->appendUShort(parameters->items.getCount()); - - NestConst* ptr = parameters->items.begin(); - const NestConst* end = parameters->items.end(); - while (ptr < end) - GEN_expr(dsqlScratch, *ptr++); + dsqlScratch->appendUChar(blr_gds_code); + dsqlScratch->appendNullString(exception->name.object.c_str()); + } + else + { + if (exception->name.schema != dsqlScratch->ddlSchema) + { + if (!messageExpr && !parameters) + { + dsqlScratch->appendUChar(blr_exception2); + dsqlScratch->appendNullString(exception->name.schema.c_str()); + dsqlScratch->appendNullString(exception->name.object.c_str()); + } + else + { + dsqlScratch->appendUChar(blr_exception3); + dsqlScratch->appendNullString(exception->name.schema.c_str()); + dsqlScratch->appendNullString(exception->name.object.c_str()); + + if (messageExpr) + { + dsqlScratch->appendUChar(1); + GEN_expr(dsqlScratch, messageExpr); + } + else + dsqlScratch->appendUChar(0); + + if (parameters) + { + dsqlScratch->appendUShort(parameters->items.getCount()); + + for (auto parameter : parameters->items) + GEN_expr(dsqlScratch, parameter); + } + else + dsqlScratch->appendUShort(0); + } + } + else + { + if (parameters) + dsqlScratch->appendUChar(blr_exception_params); + else if (messageExpr) + dsqlScratch->appendUChar(blr_exception_msg); + else // Otherwise go usual way, i.e. generate blr_exception or blr_exception2. + dsqlScratch->appendUChar(blr_exception); + + dsqlScratch->appendNullString(exception->name.object.c_str()); + + // If exception parameters or value is defined, generate appropriate BLR verbs. + if (parameters) + { + dsqlScratch->appendUShort(parameters->items.getCount()); + + for (auto parameter : parameters->items) + GEN_expr(dsqlScratch, parameter); + } + else if (messageExpr) + GEN_expr(dsqlScratch, messageExpr); + } } - else if (messageExpr) - GEN_expr(dsqlScratch, messageExpr); } ExceptionNode* ExceptionNode::pass1(thread_db* tdbb, CompilerScratch* csb) @@ -5319,8 +5455,10 @@ ExceptionNode* ExceptionNode::pass1(thread_db* tdbb, CompilerScratch* csb) if (exception) { - CMP_post_access(tdbb, csb, exception->secName, 0, - SCL_usage, obj_exceptions, exception->name); + CMP_post_access(tdbb, csb, exception->secName.schema, 0, SCL_usage, obj_schemas, + QualifiedName(exception->name.schema)); + + CMP_post_access(tdbb, csb, exception->secName.object, 0, SCL_usage, obj_exceptions, exception->name); } return this; @@ -5374,8 +5512,8 @@ void ExceptionNode::setError(thread_db* tdbb) const ERR_punt(); } - MetaName exName; - MetaName relationName; + QualifiedName exName; + QualifiedName relationName; string message; if (messageExpr) @@ -5399,9 +5537,10 @@ void ExceptionNode::setError(thread_db* tdbb) const case ExceptionItem::GDS_CODE: if (xcpCode == isc_check_constraint) { - MET_lookup_cnstrt_for_trigger(tdbb, exName, relationName, + MetaName constraintName; + MET_lookup_cnstrt_for_trigger(tdbb, constraintName, relationName, request->getStatement()->triggerName); - ERR_post(Arg::Gds(xcpCode) << Arg::Str(exName) << Arg::Str(relationName)); + ERR_post(Arg::Gds(xcpCode) << constraintName.toQuotedString() << relationName.toQuotedString()); } else ERR_post(Arg::Gds(xcpCode)); @@ -5425,19 +5564,19 @@ void ExceptionNode::setError(thread_db* tdbb) const Arg::StatusVector status; ISC_STATUS msgCode = parameters ? isc_formatted_exception : isc_random; - if (s && exName.hasData()) + if (s && exName.object.hasData()) { status << Arg::Gds(isc_except) << Arg::Num(xcpCode) << - Arg::Gds(isc_random) << Arg::Str(exName) << + Arg::Gds(isc_random) << exName.toQuotedString() << Arg::Gds(msgCode); } else if (s) status << Arg::Gds(isc_except) << Arg::Num(xcpCode) << Arg::Gds(msgCode); - else if (exName.hasData()) + else if (exName.object.hasData()) { ERR_post(Arg::Gds(isc_except) << Arg::Num(xcpCode) << - Arg::Gds(isc_random) << Arg::Str(exName)); + Arg::Gds(isc_random) << exName.toQuotedString()); } else ERR_post(Arg::Gds(isc_except) << Arg::Num(xcpCode)); @@ -6087,7 +6226,7 @@ void LocalDeclarationsNode::checkUniqueFieldsNames(const LocalDeclarationsNode* { ERRD_post( Arg::Gds(isc_sqlerr) << Arg::Num(-637) << - Arg::Gds(isc_dsql_duplicate_spec) << Arg::Str(parameter->name)); + Arg::Gds(isc_dsql_duplicate_spec) << parameter->name); } } } @@ -6559,7 +6698,7 @@ StmtNode* MergeNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { const auto badRel = tmpCtx->ctx_relation; - PASS1_field_unknown((badRel ? badRel->rel_name.c_str() : NULL), + PASS1_field_unknown((badRel ? badRel->rel_name.toQuotedString().c_str() : NULL), tmpName, notMatched.fields[&field - fields.begin()]); } } @@ -7273,6 +7412,7 @@ StmtNode* ModifyNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, bool up NestConst relation = nodeAs(dsqlRelation); fb_assert(relation); + dsqlScratch->qualifyExistingName(relation->dsqlName, obj_relation); NestConst* ptr; @@ -8147,10 +8287,10 @@ const StmtNode* PostEventNode::execute(thread_db* tdbb, Request* request, ExeSta jrd_tra* transaction = request->req_transaction; DeferredWork* work = DFW_post_work(transaction, dfw_post_event, - EVL_expr(tdbb, request, event), 0); + EVL_expr(tdbb, request, event), nullptr, 0); if (argument) - DFW_post_work_arg(transaction, work, EVL_expr(tdbb, request, argument), 0); + DFW_post_work_arg(transaction, work, EVL_expr(tdbb, request, argument), nullptr, 0); // For an autocommit transaction, events can be posted without any updates. @@ -8387,7 +8527,7 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, { const auto badRel = tmpCtx->ctx_relation; - PASS1_field_unknown((badRel ? badRel->rel_name.c_str() : NULL), + PASS1_field_unknown((badRel ? badRel->rel_name.toQuotedString().c_str() : NULL), tmpName, dsqlFields[&field - fields.begin()]); } } @@ -8452,7 +8592,8 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, // marks it with CTX_null so all fields be resolved to NULL constant. dsql_ctx* old_context = FB_NEW_POOL(dsqlScratch->getPool()) dsql_ctx(dsqlScratch->getPool()); *old_context = *context; - old_context->ctx_alias = old_context->ctx_internal_alias = OLD_CONTEXT_NAME; + old_context->ctx_alias.add(QualifiedName(OLD_CONTEXT_NAME)); + old_context->ctx_internal_alias.object = OLD_CONTEXT_NAME; old_context->ctx_flags |= CTX_system | CTX_null | CTX_returning; dsqlScratch->context->push(old_context); @@ -8460,7 +8601,8 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, dsql_ctx* new_context = FB_NEW_POOL(dsqlScratch->getPool()) dsql_ctx(dsqlScratch->getPool()); *new_context = *context; new_context->ctx_scope_level = ++dsqlScratch->scopeLevel; - new_context->ctx_alias = new_context->ctx_internal_alias = NEW_CONTEXT_NAME; + new_context->ctx_alias.add(QualifiedName(NEW_CONTEXT_NAME)); + new_context->ctx_internal_alias.object = NEW_CONTEXT_NAME; new_context->ctx_flags |= CTX_system | CTX_returning; dsqlScratch->context->push(new_context); } @@ -8716,7 +8858,7 @@ void StoreNode::makeDefaults(thread_db* tdbb, CompilerScratch* csb) { ValueExprNode* value; - if (!*ptr1 || !((*ptr1)->fld_generator_name.hasData() || (value = (*ptr1)->fld_default_value))) + if (!*ptr1 || !((*ptr1)->fld_generator_name.object.hasData() || (value = (*ptr1)->fld_default_value))) continue; CompoundStmtNode* compoundNode = nodeAs(statement.getObject()); @@ -9153,7 +9295,7 @@ void SelectNode::genBlr(DsqlCompilerScratch* dsqlScratch) GEN_parameter(dsqlScratch, parameter); } - if (parameter->par_dbkey_relname.hasData() && parameter->par_context) + if (parameter->par_dbkey_relname.object.hasData() && parameter->par_context) { dsqlScratch->appendUChar(blr_assignment); dsqlScratch->appendUChar(blr_dbkey); @@ -9161,7 +9303,7 @@ void SelectNode::genBlr(DsqlCompilerScratch* dsqlScratch) GEN_parameter(dsqlScratch, parameter); } - if (parameter->par_rec_version_relname.hasData() && parameter->par_context) + if (parameter->par_rec_version_relname.object.hasData() && parameter->par_context) { dsqlScratch->appendUChar(blr_assignment); dsqlScratch->appendUChar(blr_record_version); @@ -9255,17 +9397,18 @@ static RegisterNode regSetGeneratorNode({blr_set_generator}); DmlNode* SetGeneratorNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR /*blrOp*/) { - MetaName name; - csb->csb_blr_reader.getMetaName(name); + QualifiedName name; + csb->csb_blr_reader.getMetaName(name.object); + csb->qualifyExistingName(tdbb, name, obj_generator); SetGeneratorNode* const node = FB_NEW_POOL(pool) SetGeneratorNode(pool, name); bool sysGen = false; if (!MET_load_generator(tdbb, node->generator, &sysGen)) - PAR_error(csb, Arg::Gds(isc_gennotdef) << Arg::Str(name)); + PAR_error(csb, Arg::Gds(isc_gennotdef) << name.toQuotedString()); if (sysGen) - PAR_error(csb, Arg::Gds(isc_cant_modify_sysobj) << "generator" << name); + PAR_error(csb, Arg::Gds(isc_cant_modify_sysobj) << "generator" << name.toQuotedString()); node->value = PAR_parse_value(tdbb, csb); @@ -9286,8 +9429,10 @@ SetGeneratorNode* SetGeneratorNode::pass1(thread_db* tdbb, CompilerScratch* csb) { doPass1(tdbb, csb, value.getAddress()); - CMP_post_access(tdbb, csb, generator.secName, 0, - SCL_usage, obj_generators, generator.name); + CMP_post_access(tdbb, csb, generator.secName.schema, 0, SCL_usage, obj_schemas, + QualifiedName(generator.name.schema)); + + CMP_post_access(tdbb, csb, generator.secName.object, 0, SCL_usage, obj_generators, generator.name); return this; } @@ -9305,13 +9450,13 @@ const StmtNode* SetGeneratorNode::execute(thread_db* tdbb, Request* request, Exe jrd_tra* const transaction = request->req_transaction; DdlNode::executeDdlTrigger(tdbb, transaction, DdlNode::DTW_BEFORE, - DDL_TRIGGER_ALTER_SEQUENCE, generator.name, NULL, *request->getStatement()->sqlText); + DDL_TRIGGER_ALTER_SEQUENCE, generator.name, {}, *request->getStatement()->sqlText); dsc* const desc = EVL_expr(tdbb, request, value); DPM_gen_id(tdbb, generator.id, true, MOV_get_int64(tdbb, desc, 0)); DdlNode::executeDdlTrigger(tdbb, transaction, DdlNode::DTW_AFTER, - DDL_TRIGGER_ALTER_SEQUENCE, generator.name, NULL, *request->getStatement()->sqlText); + DDL_TRIGGER_ALTER_SEQUENCE, generator.name, {}, *request->getStatement()->sqlText); request->req_operation = Request::req_return; } @@ -9770,12 +9915,13 @@ void SetTransactionNode::genTableLock(DsqlCompilerScratch* dsqlScratch, const USHORT lockMode = (tblLock.lockMode & LOCK_MODE_WRITE) ? isc_tpb_lock_write : isc_tpb_lock_read; - for (ObjectsArray::iterator i = tblLock.tables->begin(); + for (ObjectsArray::iterator i = tblLock.tables->begin(); i != tblLock.tables->end(); ++i) { dsqlScratch->appendUChar(lockMode); - dsqlScratch->appendNullString(i->c_str()); // stuff table name + // FIXME: schema + dsqlScratch->appendNullString(i->object.c_str()); // stuff table name dsqlScratch->appendUChar(lockLevel); } } @@ -10008,6 +10154,23 @@ void SetOptimizeNode::execute(thread_db* tdbb, DsqlRequest* /*request*/, jrd_tra //-------------------- +void SetSearchPathNode::execute(thread_db* tdbb, DsqlRequest* /*request*/, jrd_tra** /*traHandle*/) const +{ + const auto attachment = tdbb->getAttachment(); + + auto newSearchPath = makeRef( + FB_NEW_POOL(*attachment->att_pool) AnyRef>(*attachment->att_pool)); + + for (const auto& schema : *schemas) + newSearchPath->add(schema); + + attachment->att_schema_search_path = std::move(newSearchPath); +} + + +//-------------------- + + void SetTimeZoneNode::execute(thread_db* tdbb, DsqlRequest* request, jrd_tra** /*traHandle*/) const { Attachment* const attachment = tdbb->getAttachment(); @@ -10080,22 +10243,23 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { auto& pool = dsqlScratch->getPool(); + dsqlScratch->qualifyExistingName(relation->dsqlName, obj_relation); + if (!dsqlScratch->isPsql()) dsqlScratch->flags |= DsqlCompilerScratch::FLAG_UPDATE_OR_INSERT; - RelationSourceNode* target = relation; - const auto querySpec = FB_NEW_POOL(pool) RseNode(pool); querySpec->dsqlExplicitJoin = true; querySpec->dsqlFrom = FB_NEW_POOL(pool) RecSourceListNode(pool, 1); - querySpec->dsqlFrom->items[0] = target; + querySpec->dsqlFrom->items[0] = relation; querySpec->rse_plan = plan; const auto node = FB_NEW_POOL(pool) UpdateOrInsertNode(pool); node->returning = returning; - const auto& relationName = nodeAs(relation)->dsqlName; - MetaName baseName = relationName; + const auto& relationName = relation->dsqlName; + + auto baseName = relationName; bool needSavePoint; @@ -10123,8 +10287,7 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) if ((ctxRelation->rel_flags & REL_view) && matching.isEmpty()) { - auto baseRel = METD_get_view_base(dsqlScratch->getTransaction(), dsqlScratch, - relationName.c_str(), viewFields); + auto baseRel = METD_get_view_base(dsqlScratch->getTransaction(), dsqlScratch, relationName, viewFields); // Get the base table name if there is only one. if (baseRel) @@ -10160,10 +10323,10 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { equalityType = blr_eql; - METD_get_primary_key(dsqlScratch->getTransaction(), baseName.c_str(), matchingCopy); + METD_get_primary_key(dsqlScratch->getTransaction(), baseName, matchingCopy); if (matchingCopy.isEmpty()) - ERRD_post(Arg::Gds(isc_primary_key_required) << baseName); + ERRD_post(Arg::Gds(isc_primary_key_required) << baseName.toQuotedString()); } // Build a boolean to use in the UPDATE dsqlScratch. @@ -10240,7 +10403,7 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) if (matching.hasData()) ERRD_post(Arg::Gds(isc_upd_ins_doesnt_match_matching)); else - ERRD_post(Arg::Gds(isc_upd_ins_doesnt_match_pk) << baseName); + ERRD_post(Arg::Gds(isc_upd_ins_doesnt_match_pk) << baseName.toQuotedString()); } // build the UPDATE node @@ -10518,13 +10681,13 @@ static dsql_par* dsqlFindDbKey(const DsqlDmlStatement* statement, const Relation const dsql_msg* message = statement->getReceiveMsg(); dsql_par* candidate = NULL; - const MetaName& relName = relation_name->dsqlName; + const auto& relName = relation_name->dsqlName; for (FB_SIZE_T i = 0; i < message->msg_parameters.getCount(); ++i) { dsql_par* parameter = message->msg_parameters[i]; - if (parameter->par_dbkey_relname.hasData() && parameter->par_dbkey_relname == relName) + if (parameter->par_dbkey_relname.object.hasData() && parameter->par_dbkey_relname == relName) { if (candidate) return NULL; @@ -10541,13 +10704,13 @@ static dsql_par* dsqlFindRecordVersion(const DsqlDmlStatement* statement, const { const dsql_msg* message = statement->getReceiveMsg(); dsql_par* candidate = NULL; - const MetaName& relName = relation_name->dsqlName; + const auto& relName = relation_name->dsqlName; for (FB_SIZE_T i = 0; i < message->msg_parameters.getCount(); ++i) { dsql_par* parameter = message->msg_parameters[i]; - if (parameter->par_rec_version_relname.hasData() && + if (parameter->par_rec_version_relname.object.hasData() && parameter->par_rec_version_relname == relName) { if (candidate) @@ -10782,7 +10945,7 @@ static void dsqlFieldAppearsOnce(const Array >& values, if (name1 == name2) { - string str = field1->dsqlContext->ctx_relation->rel_name.c_str(); + string str = field1->dsqlContext->ctx_relation->rel_name.toQuotedString(); str += "."; str += name1.c_str(); @@ -10819,7 +10982,7 @@ static dsql_ctx* dsqlPassCursorContext(DsqlCompilerScratch* dsqlScratch, const M { DEV_BLKCHK(dsqlScratch, dsql_type_req); - const MetaName& relName = relation_name->dsqlName; + const auto& relName = relation_name->dsqlName; // this function must throw an error if no cursor was found const DeclareCursorNode* node = PASS1_cursor_name(dsqlScratch, cursor, @@ -10853,8 +11016,7 @@ static dsql_ctx* dsqlPassCursorContext(DsqlCompilerScratch* dsqlScratch, const M { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-504) << Arg::Gds(isc_dsql_cursor_err) << - Arg::Gds(isc_dsql_cursor_rel_ambiguous) << Arg::Str(relName) << - cursor); + Arg::Gds(isc_dsql_cursor_rel_ambiguous) << relName.toQuotedString() << cursor); } else context = candidate; @@ -10875,7 +11037,7 @@ static dsql_ctx* dsqlPassCursorContext(DsqlCompilerScratch* dsqlScratch, const M { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-504) << Arg::Gds(isc_dsql_cursor_err) << - Arg::Gds(isc_dsql_cursor_rel_not_found) << Arg::Str(relName) << cursor); + Arg::Gds(isc_dsql_cursor_rel_not_found) << relName.toQuotedString() << cursor); } return context; @@ -11206,8 +11368,8 @@ static ReturningClause* dsqlProcessReturning(DsqlCompilerScratch* dsqlScratch, d if (!input) return nullptr; - AutoSaveRestore autoOldAlias(&oldContext->ctx_alias); - AutoSaveRestore autoOldInternalAlias(&oldContext->ctx_internal_alias); + AutoSaveRestore> autoOldAlias(&oldContext->ctx_alias); + AutoSaveRestore autoOldInternalAlias(&oldContext->ctx_internal_alias); AutoSetRestore autoFlags(&oldContext->ctx_flags, oldContext->ctx_flags | CTX_system | CTX_returning); AutoSetRestore autoScopeLevel(&dsqlScratch->scopeLevel, dsqlScratch->scopeLevel + 1); @@ -11242,9 +11404,13 @@ static ReturningClause* dsqlProcessReturning(DsqlCompilerScratch* dsqlScratch, d newContext->ctx_flags |= CTX_null; } - oldContext->ctx_alias = oldContext->ctx_internal_alias = OLD_CONTEXT_NAME; + oldContext->ctx_alias.clear(); + oldContext->ctx_alias.add().object = OLD_CONTEXT_NAME; + oldContext->ctx_internal_alias.object = OLD_CONTEXT_NAME; - newContext->ctx_alias = newContext->ctx_internal_alias = NEW_CONTEXT_NAME; + newContext->ctx_alias.clear(); + newContext->ctx_alias.add().object = NEW_CONTEXT_NAME; + newContext->ctx_internal_alias.object = NEW_CONTEXT_NAME; newContext->ctx_flags |= CTX_returning; newContext->ctx_scope_level = dsqlScratch->scopeLevel; dsqlScratch->context->push(newContext); @@ -11304,8 +11470,8 @@ static void dsqlSetParameterName(DsqlCompilerScratch* dsqlScratch, ExprNode* exp { ParameterNode* paramNode = nodeAs(exprNode); dsql_par* parameter = paramNode->dsqlParameter; - parameter->par_name = fieldNode->dsqlField->fld_name.c_str(); - parameter->par_rel_name = relation->rel_name.c_str(); + parameter->par_name = fieldNode->dsqlField->fld_name; + parameter->par_rel_name = relation->rel_name; break; } } @@ -11525,7 +11691,12 @@ static RelationSourceNode* pass1Update(thread_db* tdbb, CompilerScratch* csb, jr // unless this is an internal request, check access permission - CMP_post_access(tdbb, csb, relation->rel_security_name, (view ? view->rel_id : 0), + const SLONG ssRelationId = view ? view->rel_id : 0; + + CMP_post_access(tdbb, csb, relation->rel_security_name.schema, ssRelationId, + SCL_usage, obj_schemas, QualifiedName(relation->rel_name.schema)); + + CMP_post_access(tdbb, csb, relation->rel_security_name.object, ssRelationId, priv, obj_relations, relation->rel_name); // ensure that the view is set for the input streams, @@ -11575,7 +11746,7 @@ static RelationSourceNode* pass1Update(thread_db* tdbb, CompilerScratch* csb, jr if (rse->rse_relations.getCount() != 1 || rse->rse_projection || rse->rse_sorted || rse->rse_relations[0]->getType() != RelationSourceNode::TYPE) { - ERR_post(Arg::Gds(isc_read_only_view) << Arg::Str(relation->rel_name)); + ERR_post(Arg::Gds(isc_read_only_view) << relation->rel_name.toQuotedString()); } // for an updateable view, return the view source @@ -11739,7 +11910,7 @@ static void preprocessAssignments(thread_db* tdbb, CompilerScratch* csb, if (nodeIs(assignFrom)) compoundNode->statements.remove(i); } - else if (relation->rel_view_rse && fld->fld_source_rel_field.first.hasData()) + else if (relation->rel_view_rse && fld->fld_source_rel_field.first.object.hasData()) { relation = MET_lookup_relation(tdbb, fld->fld_source_rel_field.first); @@ -11763,15 +11934,15 @@ static void preprocessAssignments(thread_db* tdbb, CompilerScratch* csb, if (insertOverride->has_value()) { if (!identityType.has_value()) - ERR_post(Arg::Gds(isc_overriding_without_identity) << relation->rel_name); + ERR_post(Arg::Gds(isc_overriding_without_identity) << relation->rel_name.toQuotedString()); if (identityType == IDENT_TYPE_BY_DEFAULT && *insertOverride == OverrideClause::SYSTEM_VALUE) - ERR_post(Arg::Gds(isc_overriding_system_invalid) << relation->rel_name); + ERR_post(Arg::Gds(isc_overriding_system_invalid) << relation->rel_name.toQuotedString()); } else { if (identityType == IDENT_TYPE_ALWAYS) - ERR_post(Arg::Gds(isc_overriding_missing) << relation->rel_name); + ERR_post(Arg::Gds(isc_overriding_missing) << relation->rel_name.toQuotedString()); } } @@ -11828,8 +11999,8 @@ static void validateExpressions(thread_db* tdbb, const Array& vali if (vector && fieldNode->fieldId < vector->count() && (field = (*vector)[fieldNode->fieldId])) { - if (!relation->rel_name.isEmpty()) - name.printf("\"%s\".\"%s\"", relation->rel_name.c_str(), field->fld_name.c_str()); + if (relation->rel_name.object.hasData()) + name.printf("%s.\"%s\"", relation->rel_name.toQuotedString().c_str(), field->fld_name.c_str()); else name.printf("\"%s\"", field->fld_name.c_str()); } diff --git a/src/dsql/StmtNodes.h b/src/dsql/StmtNodes.h index c6cede470d..a19bd464b1 100644 --- a/src/dsql/StmtNodes.h +++ b/src/dsql/StmtNodes.h @@ -97,11 +97,8 @@ public: public: Type type; SLONG code; - // ASF: There are some inconsistencies in the type of 'name'. Metanames have maximum of 31 chars, - // while there are system exceptions with 32 chars. The parser always expects metanames, but - // I'm following the legacy code and making this a string. - Firebird::string name; - MetaName secName; + QualifiedName name; + QualifiedName secName; }; typedef Firebird::ObjectsArray ExceptionArray; @@ -589,7 +586,7 @@ class ExecProcedureNode final : public TypedNode* aDsqlInputArgNames = nullptr) : TypedNode(pool), @@ -802,7 +799,7 @@ public: class ExceptionNode final : public TypedNode { public: - ExceptionNode(MemoryPool& pool, const MetaName& name, + ExceptionNode(MemoryPool& pool, const QualifiedName& name, ValueExprNode* aMessageExpr = NULL, ValueListNode* aParameters = NULL) : TypedNode(pool), messageExpr(aMessageExpr), @@ -810,7 +807,7 @@ public: { exception = FB_NEW_POOL(pool) ExceptionItem(pool); exception->type = ExceptionItem::XCP_CODE; - exception->name = name.c_str(); + exception->name = name; } explicit ExceptionNode(MemoryPool& pool) @@ -1386,7 +1383,7 @@ public: class SetGeneratorNode final : public TypedNode { public: - SetGeneratorNode(MemoryPool& pool, const MetaName& name, ValueExprNode* aValue = NULL) + SetGeneratorNode(MemoryPool& pool, const QualifiedName& name, ValueExprNode* aValue = NULL) : TypedNode(pool), generator(pool, name), value(aValue) { @@ -1561,7 +1558,7 @@ class SetTransactionNode : public TransactionNode public: struct RestrictionOption : Firebird::PermanentStorage { - RestrictionOption(MemoryPool& p, Firebird::ObjectsArray* aTables, + RestrictionOption(MemoryPool& p, Firebird::ObjectsArray* aTables, unsigned aLockMode) : PermanentStorage(p), tables(aTables), @@ -1569,7 +1566,7 @@ public: { } - Firebird::ObjectsArray* tables; + Firebird::ObjectsArray* tables; unsigned lockMode; }; @@ -1908,6 +1905,32 @@ public: }; +class SetSearchPathNode : public SessionManagementNode +{ +public: + SetSearchPathNode(MemoryPool& pool, Firebird::ObjectsArray* aSchemas) + : SessionManagementNode(pool), + schemas(aSchemas) + { + } + +public: + virtual Firebird::string internalPrint(NodePrinter& printer) const + { + SessionManagementNode::internalPrint(printer); + + NODE_PRINT(printer, schemas); + + return "SetSearchPathNode"; + } + + virtual void execute(thread_db* tdbb, DsqlRequest* request, jrd_tra** traHandle) const; + +public: + NestConst> schemas; +}; + + class SetTimeZoneNode : public SessionManagementNode { public: diff --git a/src/dsql/ddl.cpp b/src/dsql/ddl.cpp index 761a13913b..4c9487fe68 100644 --- a/src/dsql/ddl.cpp +++ b/src/dsql/ddl.cpp @@ -125,7 +125,7 @@ bool DDL_ids(const DsqlCompilerScratch* scratch) void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field, - const MetaName& collation_name, bool modifying) + QualifiedName& collation_name, bool modifying) { /************************************** * @@ -152,17 +152,18 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field, * **************************************/ - if (field->typeOfName.hasData()) + if (field->typeOfName.object.hasData()) { - if (field->typeOfTable.hasData()) + if (field->typeOfTable.object.hasData()) { - dsql_rel* relation = METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch, - field->typeOfTable.c_str()); + dsqlScratch->qualifyExistingName(field->typeOfTable, obj_relation); + + dsql_rel* relation = METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch, field->typeOfTable); const dsql_fld* fld = NULL; if (relation) { - const MetaName fieldName(field->typeOfName); + const MetaName fieldName(field->typeOfName.object); for (fld = relation->rel_fields; fld; fld = fld->fld_next) { @@ -188,16 +189,18 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field, { // column @1 does not exist in table/view @2 post_607(Arg::Gds(isc_dyn_column_does_not_exist) << - Arg::Str(field->typeOfName) << - field->typeOfTable); + field->typeOfName.toQuotedString() << + field->typeOfTable.toQuotedString()); } } else { + dsqlScratch->qualifyExistingName(field->typeOfName, obj_field); + if (!METD_get_domain(dsqlScratch->getTransaction(), field, field->typeOfName)) { // Specified domain or source field does not exist - post_607(Arg::Gds(isc_dsql_domain_not_found) << Arg::Str(field->typeOfName)); + post_607(Arg::Gds(isc_dsql_domain_not_found) << field->typeOfName.toQuotedString()); } } @@ -217,7 +220,7 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field, if ((field->dtype > dtype_any_text) && field->dtype != dtype_blob) { - if (field->charSet.hasData() || collation_name.hasData() || (field->flags & FLD_national)) + if (field->charSet.object.hasData() || collation_name.object.hasData() || (field->flags & FLD_national)) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) << Arg::Gds(isc_dsql_datatype_err) << Arg::Gds(isc_collation_requires_text)); @@ -236,7 +239,7 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field, ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) << Arg::Gds(isc_dsql_datatype_err) << Arg::Gds(isc_dsql_blob_type_unknown) << - Arg::Str(field->subTypeName)); + field->subTypeName); } field->subType = blob_sub_type; } @@ -248,17 +251,17 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field, Arg::Gds(isc_subtype_for_internal_use)); } - if (field->charSet.hasData() && (field->subType == isc_blob_untyped)) + if (field->charSet.object.hasData() && (field->subType == isc_blob_untyped)) field->subType = isc_blob_text; - if (field->charSet.hasData() && (field->subType != isc_blob_text)) + if (field->charSet.object.hasData() && (field->subType != isc_blob_text)) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) << Arg::Gds(isc_dsql_datatype_err) << Arg::Gds(isc_collation_requires_text)); } - if (collation_name.hasData() && (field->subType != isc_blob_text)) + if (collation_name.object.hasData() && (field->subType != isc_blob_text)) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) << Arg::Gds(isc_dsql_datatype_err) << @@ -269,14 +272,14 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field, return; } - if (field->charSetId.has_value() && collation_name.isEmpty()) + if (field->charSetId.has_value() && collation_name.object.isEmpty()) { // This field has already been resolved once, and the collation // hasn't changed. Therefore, no need to do it again. return; } - if (modifying && field->charSet.isEmpty() && field->collate.isEmpty()) + if (modifying && field->charSet.object.isEmpty() && field->collate.object.isEmpty()) { // Use charset and collation from already existing field if any const dsql_fld* afield = field->fld_next; @@ -311,15 +314,17 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field, } } - if (!modifying && !(field->charSet.hasData() || field->charSetId.has_value() || // set if a domain + if (!modifying && !(field->charSet.object.hasData() || field->charSetId.has_value() || // set if a domain (field->flags & FLD_national))) { // Attach the database default character set to the new field, if not otherwise specified - MetaName defaultCharSet; + QualifiedName defaultCharSet; - if (dsqlScratch->flags & DsqlCompilerScratch::FLAG_DDL) - defaultCharSet = METD_get_default_charset(dsqlScratch->getTransaction()); + if (dsqlScratch->ddlSchema.hasData()) + defaultCharSet = METD_get_schema_charset(dsqlScratch->getTransaction(), dsqlScratch->ddlSchema); + else if (dsqlScratch->flags & DsqlCompilerScratch::FLAG_DDL) + defaultCharSet = METD_get_database_charset(dsqlScratch->getTransaction()); else { USHORT charSet = dsqlScratch->getAttachment()->dbb_attachment->att_charset; @@ -327,7 +332,7 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field, defaultCharSet = METD_get_charset_name(dsqlScratch->getTransaction(), charSet); } - if (defaultCharSet.hasData()) + if (defaultCharSet.object.hasData()) field->charSet = defaultCharSet; else { @@ -336,25 +341,27 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field, assign_field_length(field, 1); field->textType = 0; - if (collation_name.isEmpty()) + if (collation_name.object.isEmpty()) return; } } - MetaName charset_name; + QualifiedName charset_name; if (field->flags & FLD_national) - charset_name = NATIONAL_CHARACTER_SET; - else if (field->charSet.hasData()) + charset_name = QualifiedName(NATIONAL_CHARACTER_SET, SYSTEM_SCHEMA); + else if (field->charSet.object.hasData()) + { + dsqlScratch->qualifyExistingName(field->charSet, obj_charset); charset_name = field->charSet; + } // Find an intlsym for any specified character set name & collation name const dsql_intlsym* resolved_type = NULL; - if (charset_name.hasData()) + if (charset_name.object.hasData()) { - const dsql_intlsym* resolved_charset = - METD_get_charset(dsqlScratch->getTransaction(), (USHORT) charset_name.length(), charset_name.c_str()); + const dsql_intlsym* resolved_charset = METD_get_charset(dsqlScratch->getTransaction(), charset_name); // Error code -204 (IBM's DB2 manual) is close enough if (!resolved_charset) @@ -362,23 +369,25 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field, // specified character set not found ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) << Arg::Gds(isc_dsql_datatype_err) << - Arg::Gds(isc_charset_not_found) << Arg::Str(charset_name)); + Arg::Gds(isc_charset_not_found) << charset_name.toQuotedString()); } field->charSetId = resolved_charset->intlsym_charset_id; resolved_type = resolved_charset; } - if (collation_name.hasData()) + if (collation_name.object.hasData()) { + dsqlScratch->qualifyExistingName(collation_name, obj_collation); + const dsql_intlsym* resolved_collation = METD_get_collation(dsqlScratch->getTransaction(), collation_name, field->charSetId.value_or(CS_NONE)); if (!resolved_collation) { - MetaName charSetName; + QualifiedName charSetName; - if (charset_name.hasData()) + if (charset_name.object.hasData()) charSetName = charset_name; else { @@ -389,7 +398,7 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field, // Specified collation not found ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) << ///Arg::Gds(isc_dsql_datatype_err) << // (too large status vector) - Arg::Gds(isc_collation_not_found) << collation_name << charSetName); + Arg::Gds(isc_collation_not_found) << collation_name.toQuotedString() << charSetName.toQuotedString()); } // If both specified, must be for same character set @@ -402,7 +411,7 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field, { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) << Arg::Gds(isc_dsql_datatype_err) << - Arg::Gds(isc_collation_not_for_charset) << collation_name); + Arg::Gds(isc_collation_not_for_charset) << collation_name.toQuotedString()); } field->explicitCollation = true; diff --git a/src/dsql/ddl_proto.h b/src/dsql/ddl_proto.h index 8b1fae8c2d..f67187cdfa 100644 --- a/src/dsql/ddl_proto.h +++ b/src/dsql/ddl_proto.h @@ -68,7 +68,7 @@ const USHORT blr_dtypes[] = { }; bool DDL_ids(const Jrd::DsqlCompilerScratch*); -void DDL_resolve_intl_type(Jrd::DsqlCompilerScratch*, Jrd::dsql_fld*, const Jrd::MetaName&, +void DDL_resolve_intl_type(Jrd::DsqlCompilerScratch*, Jrd::dsql_fld*, Jrd::QualifiedName&, bool = false); #endif // DSQL_DDL_PROTO_H diff --git a/src/dsql/dsql.cpp b/src/dsql/dsql.cpp index a6b9550662..c07bfd8ea5 100644 --- a/src/dsql/dsql.cpp +++ b/src/dsql/dsql.cpp @@ -121,6 +121,7 @@ dsql_dbb::dsql_dbb(MemoryPool& p, Attachment* attachment) dbb_charsets_by_id(p), dbb_cursors(p), dbb_pool(p), + dbb_schemas_dfl_charset(p), dbb_dfl_charset(p) { dbb_attachment = attachment; @@ -132,6 +133,13 @@ dsql_dbb::~dsql_dbb() } +void dsql_fld::resolve(DsqlCompilerScratch* dsqlScratch, bool modifying) +{ + dsqlScratch->qualifyExistingName(collate, obj_collation); + DDL_resolve_intl_type(dsqlScratch, this, collate, modifying); +} + + // Execute a dynamic SQL statement. void DSQL_execute(thread_db* tdbb, jrd_tra** tra_handle, @@ -711,15 +719,15 @@ string IntlString::toUtf8(jrd_tra* transaction) const { CHARSET_ID id = CS_dynamic; - if (charset.hasData()) + if (charset.object.hasData()) { - const dsql_intlsym* resolved = METD_get_charset(transaction, charset.length(), charset.c_str()); + const dsql_intlsym* resolved = METD_get_charset(transaction, charset); if (!resolved) { // character set name is not defined ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-504) << - Arg::Gds(isc_charset_not_found) << charset); + Arg::Gds(isc_charset_not_found) << charset.toQuotedString()); } id = resolved->intlsym_charset_id; @@ -1190,6 +1198,7 @@ static UCHAR* var_info(const dsql_msg* message, for (const UCHAR* describe = items; describe < end_describe;) { USHORT length; + string str; MetaName name; const UCHAR* buffer = buf; UCHAR item = *describe++; @@ -1235,10 +1244,21 @@ static UCHAR* var_info(const dsql_msg* message, length = 0; break; - case isc_info_sql_relation: - if (param->par_rel_name.hasData()) + case isc_info_sql_relation_schema: + if (param->par_rel_name.schema.hasData()) { - name = attachment->nameToUserCharSet(tdbb, param->par_rel_name); + name = attachment->nameToUserCharSet(tdbb, param->par_rel_name.schema); + length = name.length(); + buffer = reinterpret_cast(name.c_str()); + } + else + length = 0; + break; + + case isc_info_sql_relation: + if (param->par_rel_name.object.hasData()) + { + name = attachment->nameToUserCharSet(tdbb, param->par_rel_name.object); length = name.length(); buffer = reinterpret_cast(name.c_str()); } @@ -1260,9 +1280,9 @@ static UCHAR* var_info(const dsql_msg* message, case isc_info_sql_relation_alias: if (param->par_rel_alias.hasData()) { - name = attachment->nameToUserCharSet(tdbb, param->par_rel_alias); - length = name.length(); - buffer = reinterpret_cast(name.c_str()); + str = attachment->stringToUserCharSet(tdbb, param->par_rel_alias); + length = str.length(); + buffer = reinterpret_cast(str.c_str()); } else length = 0; diff --git a/src/dsql/dsql.h b/src/dsql/dsql.h index 422e36c396..ecbeb74735 100644 --- a/src/dsql/dsql.h +++ b/src/dsql/dsql.h @@ -34,6 +34,7 @@ #ifndef DSQL_DSQL_H #define DSQL_DSQL_H +#include #include "../common/classes/array.h" #include "../common/classes/fb_atomic.h" #include "../common/classes/GenericMap.h" @@ -116,18 +117,19 @@ namespace Jrd { class dsql_dbb : public pool_alloc { public: - Firebird::LeftPooledMap dbb_relations; // known relations in database + Firebird::LeftPooledMap dbb_relations; // known relations in database Firebird::LeftPooledMap dbb_procedures; // known procedures in database Firebird::LeftPooledMap dbb_functions; // known functions in database - Firebird::LeftPooledMap dbb_charsets; // known charsets in database - Firebird::LeftPooledMap dbb_collations; // known collations in database + Firebird::LeftPooledMap dbb_charsets; // known charsets in database + Firebird::LeftPooledMap dbb_collations; // known collations in database Firebird::NonPooledMap dbb_charsets_by_id; // charsets sorted by charset_id Firebird::LeftPooledMap dbb_cursors; // known cursors in database Firebird::AutoPtr dbb_statement_cache; MemoryPool& dbb_pool; // The current pool for the dbb Attachment* dbb_attachment; - MetaName dbb_dfl_charset; + Firebird::FullPooledMap dbb_schemas_dfl_charset; + QualifiedName dbb_dfl_charset; bool dbb_no_charset; dsql_dbb(MemoryPool& p, Attachment* attachment); @@ -156,7 +158,7 @@ public: dsql_fld* rel_fields; // Field block //dsql_rel* rel_base_relation; // base relation for an updatable view - MetaName rel_name; // Name of relation + QualifiedName rel_name; // Name of relation MetaName rel_owner; // Owner of relation USHORT rel_id; // Relation id USHORT rel_dbkey_length; @@ -175,7 +177,7 @@ enum rel_flags_vals { class TypeClause { public: - TypeClause(MemoryPool& pool, const MetaName& aCollate) + TypeClause(MemoryPool& pool, const QualifiedName& aCollate) : fieldSource(pool), typeOfTable(pool), typeOfName(pool), @@ -231,11 +233,11 @@ public: SSHORT textType = 0; bool fullDomain = false; // Domain name without TYPE OF prefix bool notNull = false; // NOT NULL was explicit specified - MetaName fieldSource; - MetaName typeOfTable; // TYPE OF table name - MetaName typeOfName; // TYPE OF - MetaName collate; - MetaName charSet; // empty means not specified + QualifiedName fieldSource; + QualifiedName typeOfTable; // TYPE OF table name + QualifiedName typeOfName; // TYPE OF + QualifiedName collate; + QualifiedName charSet; // empty means not specified MetaName subTypeName; // Subtype name for later resolution USHORT flags = 0; USHORT elementDtype = 0; // Data type of array element @@ -249,16 +251,13 @@ class dsql_fld : public TypeClause { public: explicit dsql_fld(MemoryPool& p) - : TypeClause(p, nullptr), + : TypeClause(p, {}), fld_name(p) { } public: - void resolve(DsqlCompilerScratch* dsqlScratch, bool modifying = false) - { - DDL_resolve_intl_type(dsqlScratch, this, collate, modifying); - } + void resolve(DsqlCompilerScratch* dsqlScratch, bool modifying = false); public: dsql_fld* fld_next = nullptr; // Next field in relation @@ -297,7 +296,7 @@ public: dsql_fld* prc_inputs = nullptr; // Input parameters dsql_fld* prc_outputs = nullptr; // Output parameters - QualifiedName prc_name; // Name of procedure + QualifiedName prc_name; // Name of procedure MetaName prc_owner; // Owner of procedure SSHORT prc_in_count = 0; SSHORT prc_def_count = 0; // number of inputs with default values @@ -401,7 +400,7 @@ public: { } - MetaName intlsym_name; + QualifiedName intlsym_name; USHORT intlsym_type = 0; // what type of name USHORT intlsym_flags = 0; SSHORT intlsym_ttype = 0; // id of implementation @@ -463,8 +462,8 @@ public: USHORT ctx_scope_level = 0; // Subquery level within this request USHORT ctx_flags = 0; // Various flag values USHORT ctx_in_outer_join = 0; // inOuterJoin when context was created - Firebird::string ctx_alias; // Context alias (can include concatenated derived table alias) - Firebird::string ctx_internal_alias; // Alias as specified in query + Firebird::ObjectsArray ctx_alias; // Context alias (can include concatenated derived table alias) + QualifiedName ctx_internal_alias; // Alias as specified in query DsqlContextStack ctx_main_derived_contexts; // contexts used for blr_derived_expr DsqlContextStack ctx_childs_derived_table; // Childs derived table context Firebird::LeftPooledMap ctx_imp_join; // Map of USING fieldname to ImplicitJoin @@ -497,12 +496,29 @@ public: Firebird::string getObjectName() const { if (ctx_relation) - return ctx_relation->rel_name.c_str(); + return ctx_relation->rel_name.toQuotedString(); if (ctx_procedure) - return ctx_procedure->prc_name.toString(); + return ctx_procedure->prc_name.toQuotedString(); return ""; } + Firebird::string getConcatenatedAlias() const + { + if (ctx_alias.hasData()) + { + return std::accumulate( + std::next(ctx_alias.begin()), + ctx_alias.end(), + ctx_alias[0].toQuotedString(), + [](const auto& a, const auto& b) { + return a + " " + b.toQuotedString(); + } + ); + } + + return {}; + } + bool getImplicitJoinField(const MetaName& name, NestConst& node); WindowMap* getWindowMap(DsqlCompilerScratch* dsqlScratch, WindowClause* windowNode); }; @@ -568,12 +584,12 @@ public: dsql_par* par_null = nullptr; // Null parameter, if used ValueExprNode* par_node = nullptr; // Associated value node, if any dsql_ctx* par_context = nullptr; // Context for SELECT FOR UPDATE - MetaName par_dbkey_relname; // Context of internally requested dbkey - MetaName par_rec_version_relname; // Context of internally requested rec. version + QualifiedName par_dbkey_relname; // Context of internally requested dbkey + QualifiedName par_rec_version_relname; // Context of internally requested rec. version MetaName par_name; // Parameter name, if any - MetaName par_rel_name; // Relation name, if any + QualifiedName par_rel_name; // Relation name, if any MetaName par_owner_name; // Owner name, if any - MetaName par_rel_alias; // Relation alias, if any + Firebird::string par_rel_alias; // Relation alias, if any MetaName par_alias; // Alias, if any dsc par_desc; // Field data type USHORT par_parameter = 0; // BLR parameter number @@ -605,7 +621,7 @@ public: s(p, str) { } - explicit IntlString(const Firebird::string& str, const MetaName& cs = NULL) + explicit IntlString(const Firebird::string& str, const QualifiedName& cs = {}) : charset(cs), s(str) { } @@ -622,12 +638,12 @@ public: Firebird::string toUtf8(jrd_tra* transaction) const; - const MetaName& getCharSet() const + const QualifiedName& getCharSet() const { return charset; } - void setCharSet(const MetaName& value) + void setCharSet(const QualifiedName& value) { charset = value; } @@ -648,7 +664,7 @@ public: } private: - MetaName charset; + QualifiedName charset; Firebird::string s; }; @@ -732,11 +748,11 @@ struct SignatureParameter SSHORT type = 0; SSHORT number = 0; MetaName name; - MetaName fieldSource; - MetaName fieldName; - MetaName relationName; - MetaName charSetName; - MetaName collationName; + QualifiedName fieldSource; + QualifiedName fieldName; + QualifiedName relationName; + QualifiedName charSetName; + QualifiedName collationName; MetaName subTypeName; std::optional collationId; std::optional nullFlag; @@ -763,8 +779,9 @@ struct SignatureParameter number == o.number && name == o.name && (fieldSource == o.fieldSource || - (fb_utils::implicit_domain(fieldSource.c_str()) && - fb_utils::implicit_domain(o.fieldSource.c_str()))) && + (fieldSource.schema == o.fieldSource.schema && + fb_utils::implicit_domain(fieldSource.object.c_str()) && + fb_utils::implicit_domain(o.fieldSource.object.c_str()))) && fieldName == o.fieldName && relationName == o.relationName && collationId == o.collationId && diff --git a/src/dsql/gen.cpp b/src/dsql/gen.cpp index ece4e4dc2d..ba648b46d4 100644 --- a/src/dsql/gen.cpp +++ b/src/dsql/gen.cpp @@ -505,10 +505,21 @@ static void gen_plan(DsqlCompilerScratch* dsqlScratch, const PlanNode* planNode) // now stuff the access method for this stream - ObjectsArray::const_iterator idx_iter = - node->accessType->items.begin(); + auto idx_iter = node->accessType->items.begin(); FB_SIZE_T idx_count = node->accessType->items.getCount(); + const auto checkIndexSchema = [&]() + { + if (node->recordSourceNode && + node->recordSourceNode->dsqlContext && + node->recordSourceNode->dsqlContext->ctx_relation && + idx_iter->indexName.schema.hasData() && + idx_iter->indexName.schema != node->recordSourceNode->dsqlContext->ctx_relation->rel_name.schema) + { + ERRD_post(Arg::Gds(isc_index_unused) << idx_iter->indexName.toQuotedString()); + } + }; + switch (node->accessType->type) { case PlanNode::AccessType::TYPE_SEQUENTIAL: @@ -516,8 +527,9 @@ static void gen_plan(DsqlCompilerScratch* dsqlScratch, const PlanNode* planNode) break; case PlanNode::AccessType::TYPE_NAVIGATIONAL: + checkIndexSchema(); dsqlScratch->appendUChar(blr_navigational); - dsqlScratch->appendNullString(idx_iter->indexName.c_str()); + dsqlScratch->appendNullString(idx_iter->indexName.object.c_str()); if (idx_count == 1) break; // dimitr: FALL INTO, if the plan item is ORDER ... INDEX (...) @@ -532,7 +544,10 @@ static void gen_plan(DsqlCompilerScratch* dsqlScratch, const PlanNode* planNode) dsqlScratch->appendUChar(idx_count); for (; idx_iter != node->accessType->items.end(); ++idx_iter) - dsqlScratch->appendNullString(idx_iter->indexName.c_str()); + { + checkIndexSchema(); + dsqlScratch->appendNullString(idx_iter->indexName.object.c_str()); + } break; } diff --git a/src/dsql/make.cpp b/src/dsql/make.cpp index 0ee75a0428..643e725fd1 100644 --- a/src/dsql/make.cpp +++ b/src/dsql/make.cpp @@ -342,7 +342,7 @@ ValueExprNode* MAKE_constant(const char* str, dsql_constant_type numeric_flag, S @param character_set **/ -LiteralNode* MAKE_str_constant(const IntlString* constant, SSHORT character_set) +LiteralNode* MAKE_str_constant(IntlString* constant, SSHORT character_set) { thread_db* tdbb = JRD_get_thread_data(); @@ -495,9 +495,9 @@ dsql_par* MAKE_parameter(dsql_msg* message, bool sqlda_flag, bool null_flag, message->msg_parameters.insert(0, parameter); parameter->par_parameter = message->msg_parameter++; - parameter->par_rel_name = NULL; + parameter->par_rel_name.clear(); parameter->par_owner_name = NULL; - parameter->par_rel_alias = NULL; + parameter->par_rel_alias.clear(); if (node) MAKE_parameter_names(parameter, node); diff --git a/src/dsql/make_proto.h b/src/dsql/make_proto.h index d68df999fb..93fcd17e40 100644 --- a/src/dsql/make_proto.h +++ b/src/dsql/make_proto.h @@ -82,7 +82,7 @@ namespace Jrd { Jrd::LiteralNode* MAKE_const_slong(SLONG); Jrd::LiteralNode* MAKE_const_sint64(SINT64 value, SCHAR scale); Jrd::ValueExprNode* MAKE_constant(const char*, Jrd::dsql_constant_type, SSHORT = 0); -Jrd::LiteralNode* MAKE_str_constant(const Jrd::IntlString*, SSHORT); +Jrd::LiteralNode* MAKE_str_constant(Jrd::IntlString*, SSHORT); Jrd::FieldNode* MAKE_field(Jrd::dsql_ctx*, Jrd::dsql_fld*, Jrd::ValueListNode*); Jrd::FieldNode* MAKE_field_name(const char*); Jrd::dsql_par* MAKE_parameter(Jrd::dsql_msg*, bool, bool, USHORT, const Jrd::ValueExprNode*); diff --git a/src/dsql/metd.epp b/src/dsql/metd.epp index 81e380c043..b28579bbc8 100644 --- a/src/dsql/metd.epp +++ b/src/dsql/metd.epp @@ -76,15 +76,16 @@ namespace } } - bool isSystemRelation(thread_db* tdbb, jrd_tra* transaction, const char* relName) + bool isSystemRelation(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& relName) { bool rc = false; AutoCacheRequest handle(tdbb, irq_system_relation, IRQ_REQUESTS); FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) - R IN RDB$RELATIONS WITH - R.RDB$RELATION_NAME EQ relName AND - R.RDB$SYSTEM_FLAG EQ 1 + R IN RDB$RELATIONS + WITH R.RDB$SCHEMA_NAME EQ relName.schema.c_str() AND + R.RDB$RELATION_NAME EQ relName.object.c_str() AND + R.RDB$SYSTEM_FLAG EQ 1 { rc = true; } @@ -93,15 +94,16 @@ namespace return rc; } - bool isSystemDomain(thread_db* tdbb, jrd_tra* transaction, const char* fldName) + bool isSystemDomain(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& fldName) { bool rc = false; AutoCacheRequest handle(tdbb, irq_system_domain, IRQ_REQUESTS); FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) - R IN RDB$FIELDS WITH - R.RDB$FIELD_NAME EQ fldName AND - R.RDB$SYSTEM_FLAG EQ 1 + R IN RDB$FIELDS + WITH R.RDB$SCHEMA_NAME EQ fldName.schema.c_str() AND + R.RDB$FIELD_NAME EQ fldName.object.c_str() AND + R.RDB$SYSTEM_FLAG EQ 1 { rc = true; } @@ -112,7 +114,7 @@ namespace } -void METD_drop_charset(jrd_tra* transaction, const MetaName& metaName) +void METD_drop_charset(jrd_tra* transaction, const QualifiedName& metaName) { /************************************** * @@ -142,7 +144,7 @@ void METD_drop_charset(jrd_tra* transaction, const MetaName& metaName) } -void METD_drop_collation(jrd_tra* transaction, const MetaName& name) +void METD_drop_collation(jrd_tra* transaction, const QualifiedName& name) { /************************************** * @@ -199,7 +201,7 @@ void METD_drop_function(jrd_tra* transaction, const QualifiedName& name) if (dbb->dbb_functions.get(name, function)) { - MET_dsql_cache_use(tdbb, SYM_udf, name.identifier, name.package); + MET_dsql_cache_use(tdbb, SYM_udf, name); function->udf_flags |= UDF_dropped; dbb->dbb_functions.remove(name); } @@ -232,14 +234,14 @@ void METD_drop_procedure(jrd_tra* transaction, const QualifiedName& name) if (dbb->dbb_procedures.get(name, procedure)) { - MET_dsql_cache_use(tdbb, SYM_procedure, name.identifier, name.package); + MET_dsql_cache_use(tdbb, SYM_procedure, name); procedure->prc_flags |= PRC_dropped; dbb->dbb_procedures.remove(name); } } -void METD_drop_relation(jrd_tra* transaction, const MetaName& name) +void METD_drop_relation(jrd_tra* transaction, const QualifiedName& name) { /************************************** * @@ -271,7 +273,7 @@ void METD_drop_relation(jrd_tra* transaction, const MetaName& name) } -dsql_intlsym* METD_get_collation(jrd_tra* transaction, const MetaName& name, USHORT charset_id) +dsql_intlsym* METD_get_collation(jrd_tra* transaction, const QualifiedName& name, USHORT charset_id) { /************************************** * @@ -311,7 +313,8 @@ dsql_intlsym* METD_get_collation(jrd_tra* transaction, const MetaName& name, USH FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) X IN RDB$COLLATIONS CROSS Y IN RDB$CHARACTER_SETS OVER RDB$CHARACTER_SET_ID - WITH X.RDB$COLLATION_NAME EQ name.c_str() AND + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$COLLATION_NAME EQ name.object.c_str() AND X.RDB$CHARACTER_SET_ID EQ charset_id; { symbol = FB_NEW_POOL(dbb->dbb_pool) dsql_intlsym(dbb->dbb_pool); @@ -336,7 +339,7 @@ dsql_intlsym* METD_get_collation(jrd_tra* transaction, const MetaName& name, USH } -dsql_intlsym* METD_get_charset(jrd_tra* transaction, USHORT length, const char* name) // UTF-8 +dsql_intlsym* METD_get_charset(jrd_tra* transaction, const QualifiedName& name) { /************************************** * @@ -354,14 +357,13 @@ dsql_intlsym* METD_get_charset(jrd_tra* transaction, USHORT length, const char* validateTransaction(transaction); dsql_dbb* dbb = transaction->getDsqlAttachment(); - MetaName metaName(name, length); // Start by seeing if symbol is already defined dsql_intlsym* symbol; - if (dbb->dbb_charsets.get(metaName, symbol) && !(symbol->intlsym_flags & INTLSYM_dropped)) + if (dbb->dbb_charsets.get(name, symbol) && !(symbol->intlsym_flags & INTLSYM_dropped)) { - if (MET_dsql_cache_use(tdbb, SYM_intlsym_charset, metaName)) + if (MET_dsql_cache_use(tdbb, SYM_intlsym_charset, name)) symbol->intlsym_flags |= INTLSYM_dropped; else return symbol; @@ -374,32 +376,34 @@ dsql_intlsym* METD_get_charset(jrd_tra* transaction, USHORT length, const char* AutoCacheRequest handle(tdbb, irq_charset, IRQ_REQUESTS); FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) - X IN RDB$COLLATIONS - CROSS Y IN RDB$CHARACTER_SETS OVER RDB$CHARACTER_SET_ID - CROSS Z IN RDB$TYPES - WITH Z.RDB$TYPE EQ Y.RDB$CHARACTER_SET_ID - AND Z.RDB$TYPE_NAME EQ name - AND Z.RDB$FIELD_NAME EQ "RDB$CHARACTER_SET_NAME" - AND Y.RDB$DEFAULT_COLLATE_NAME EQ X.RDB$COLLATION_NAME; + CS IN RDB$CHARACTER_SETS + CROSS COLL IN RDB$COLLATIONS OVER RDB$CHARACTER_SET_ID + CROSS T IN RDB$TYPES + WITH CS.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + T.RDB$TYPE_NAME EQ name.object.c_str() AND + COLL.RDB$SCHEMA_NAME EQ CS.RDB$DEFAULT_COLLATE_SCHEMA_NAME AND + COLL.RDB$COLLATION_NAME EQ CS.RDB$DEFAULT_COLLATE_NAME AND + T.RDB$FIELD_NAME EQ "RDB$CHARACTER_SET_NAME" AND + T.RDB$TYPE EQ CS.RDB$CHARACTER_SET_ID { symbol = FB_NEW_POOL(dbb->dbb_pool) dsql_intlsym(dbb->dbb_pool); - symbol->intlsym_name = metaName; + symbol->intlsym_name = name; symbol->intlsym_flags = 0; - symbol->intlsym_charset_id = X.RDB$CHARACTER_SET_ID; - symbol->intlsym_collate_id = X.RDB$COLLATION_ID; + symbol->intlsym_charset_id = COLL.RDB$CHARACTER_SET_ID; + symbol->intlsym_collate_id = COLL.RDB$COLLATION_ID; symbol->intlsym_ttype = INTL_CS_COLL_TO_TTYPE(symbol->intlsym_charset_id, symbol->intlsym_collate_id); symbol->intlsym_bytes_per_char = - (Y.RDB$BYTES_PER_CHARACTER.NULL) ? 1 : (Y.RDB$BYTES_PER_CHARACTER); + (CS.RDB$BYTES_PER_CHARACTER.NULL) ? 1 : (CS.RDB$BYTES_PER_CHARACTER); } END_FOR if (!symbol) return NULL; - dbb->dbb_charsets.put(metaName, symbol); + dbb->dbb_charsets.put(name, symbol); dbb->dbb_charsets_by_id.put(symbol->intlsym_charset_id, symbol); - MET_dsql_cache_use(tdbb, SYM_intlsym_charset, metaName); + MET_dsql_cache_use(tdbb, SYM_intlsym_charset, name); return symbol; } @@ -431,8 +435,8 @@ USHORT METD_get_charset_bpc(jrd_tra* transaction, SSHORT charset_id) dsql_intlsym* symbol = NULL; if (!dbb->dbb_charsets_by_id.get(charset_id, symbol)) { - const MetaName cs_name = METD_get_charset_name(transaction, charset_id); - symbol = METD_get_charset(transaction, cs_name.length(), cs_name.c_str()); + const auto cs_name = METD_get_charset_name(transaction, charset_id); + symbol = METD_get_charset(transaction, cs_name); } fb_assert(symbol); @@ -441,7 +445,7 @@ USHORT METD_get_charset_bpc(jrd_tra* transaction, SSHORT charset_id) } -MetaName METD_get_charset_name(jrd_tra* transaction, SSHORT charset_id) +QualifiedName METD_get_charset_name(jrd_tra* transaction, SSHORT charset_id) { /************************************** * @@ -462,14 +466,14 @@ MetaName METD_get_charset_name(jrd_tra* transaction, SSHORT charset_id) dsql_dbb* dbb = transaction->getDsqlAttachment(); - if (charset_id == CS_dynamic) + if (charset_id == CS_dynamic) charset_id = tdbb->getCharSet(); dsql_intlsym* sym = NULL; if (dbb->dbb_charsets_by_id.get(charset_id, sym)) return sym->intlsym_name; - MetaName name; + QualifiedName name; AutoCacheRequest handle(tdbb, irq_cs_name, IRQ_REQUESTS); @@ -477,62 +481,87 @@ MetaName METD_get_charset_name(jrd_tra* transaction, SSHORT charset_id) Y IN RDB$CHARACTER_SETS WITH Y.RDB$CHARACTER_SET_ID EQ charset_id { - name = Y.RDB$CHARACTER_SET_NAME; + name = QualifiedName(Y.RDB$CHARACTER_SET_NAME, Y.RDB$SCHEMA_NAME); } END_FOR // put new charset into hash table if needed - METD_get_charset(transaction, name.length(), name.c_str()); + METD_get_charset(transaction, name); return name; } -MetaName METD_get_default_charset(jrd_tra* transaction) +// Find the default character set for a database +QualifiedName METD_get_database_charset(jrd_tra* transaction) { -/************************************** - * - * M E T D _ g e t _ d e f a u l t _ c h a r s e t - * - ************************************** - * - * Functional description - * Find the default character set for a database - * - **************************************/ thread_db* tdbb = JRD_get_thread_data(); validateTransaction(transaction); dsql_dbb* dbb = transaction->getDsqlAttachment(); if (dbb->dbb_no_charset) - return NULL; + return {}; - if (dbb->dbb_dfl_charset.hasData()) + if (dbb->dbb_dfl_charset.object.hasData()) return dbb->dbb_dfl_charset; // Now see if it is in the database - AutoCacheRequest handle(tdbb, irq_default_cs, IRQ_REQUESTS); + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); - FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + FOR(REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) FIRST 1 DBB IN RDB$DATABASE - WITH DBB.RDB$CHARACTER_SET_NAME NOT MISSING; + WITH DBB.RDB$CHARACTER_SET_NAME NOT MISSING { - // Terminate ASCIIZ string on first trailing blank - fb_utils::exact_name(DBB.RDB$CHARACTER_SET_NAME); - dbb->dbb_dfl_charset = DBB.RDB$CHARACTER_SET_NAME; + dbb->dbb_dfl_charset = QualifiedName(DBB.RDB$CHARACTER_SET_NAME, DBB.RDB$CHARACTER_SET_SCHEMA_NAME); } END_FOR - if (dbb->dbb_dfl_charset.isEmpty()) + if (dbb->dbb_dfl_charset.object.isEmpty()) + { + fb_assert(false); dbb->dbb_no_charset = true; + } return dbb->dbb_dfl_charset; } -bool METD_get_domain(jrd_tra* transaction, TypeClause* field, const MetaName& name) // UTF-8 +// Find the default character set for a schema +QualifiedName METD_get_schema_charset(jrd_tra* transaction, const MetaName& schema) +{ + thread_db* tdbb = JRD_get_thread_data(); + + validateTransaction(transaction); + + dsql_dbb* dbb = transaction->getDsqlAttachment(); + + if (const auto charSet = dbb->dbb_schemas_dfl_charset.get(schema)) + return *charSet; + + // Now see if it is in the database + + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + + FOR(REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + FIRST 1 SCH IN RDB$SCHEMAS + WITH SCH.RDB$SCHEMA_NAME = schema.c_str() + { + QualifiedName charSet(SCH.RDB$CHARACTER_SET_NAME, SCH.RDB$CHARACTER_SET_SCHEMA_NAME); + dbb->dbb_schemas_dfl_charset.put(schema, charSet); + return charSet; + } + END_FOR + + fb_assert(false); + return {}; +} + + +bool METD_get_domain(jrd_tra* transaction, TypeClause* field, const QualifiedName& name) // UTF-8 { /************************************** * @@ -553,7 +582,9 @@ bool METD_get_domain(jrd_tra* transaction, TypeClause* field, const MetaName& na AutoCacheRequest handle(tdbb, irq_domain, IRQ_REQUESTS); FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) - FLX IN RDB$FIELDS WITH FLX.RDB$FIELD_NAME EQ name.c_str() + FLX IN RDB$FIELDS + WITH FLX.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + FLX.RDB$FIELD_NAME EQ name.object.c_str() { found = true; field->length = FLX.RDB$FIELD_LENGTH; @@ -592,8 +623,7 @@ bool METD_get_domain(jrd_tra* transaction, TypeClause* field, const MetaName& na } -dsql_udf* METD_get_function(jrd_tra* transaction, DsqlCompilerScratch* dsqlScratch, - const QualifiedName& name) +dsql_udf* METD_get_function(jrd_tra* transaction, DsqlCompilerScratch* dsqlScratch, const QualifiedName& name) { /************************************** * @@ -611,24 +641,13 @@ dsql_udf* METD_get_function(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat validateTransaction(transaction); dsql_dbb* dbb = transaction->getDsqlAttachment(); - QualifiedName metaName(name); - - bool maybeUnqualified = dsqlScratch->package.hasData() && metaName.package.isEmpty(); - if (maybeUnqualified) - metaName.package = dsqlScratch->package; // Start by seeing if symbol is already defined dsql_udf* userFunc = NULL; - if (dbb->dbb_functions.get(metaName, userFunc)) + if (dbb->dbb_functions.get(name, userFunc)) { - if (userFunc->udf_private && metaName.package != dsqlScratch->package) - { - status_exception::raise(Arg::Gds(isc_private_function) << - Arg::Str(metaName.identifier) << Arg::Str(metaName.package)); - } - - if (MET_dsql_cache_use(tdbb, SYM_udf, metaName.identifier, metaName.package)) + if (MET_dsql_cache_use(tdbb, SYM_udf, name)) userFunc->udf_flags |= UDF_dropped; } @@ -642,43 +661,34 @@ dsql_udf* METD_get_function(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat USHORT return_arg = 0; - while (!userFunc) + AutoCacheRequest handle1(tdbb, irq_function, IRQ_REQUESTS); + + FOR(REQUEST_HANDLE handle1 TRANSACTION_HANDLE transaction) + X IN RDB$FUNCTIONS + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$FUNCTION_NAME EQ name.object.c_str() AND + X.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') { - AutoCacheRequest handle1(tdbb, irq_function, IRQ_REQUESTS); + userFunc = FB_NEW_POOL(dbb->dbb_pool) dsql_udf(dbb->dbb_pool); + userFunc->udf_name = name; + userFunc->udf_private = !X.RDB$PRIVATE_FLAG.NULL && X.RDB$PRIVATE_FLAG != 0; - FOR(REQUEST_HANDLE handle1 TRANSACTION_HANDLE transaction) - X IN RDB$FUNCTIONS WITH - X.RDB$FUNCTION_NAME EQ metaName.identifier.c_str() AND - X.RDB$PACKAGE_NAME EQUIV NULLIF(metaName.package.c_str(), '') - { - userFunc = FB_NEW_POOL(dbb->dbb_pool) dsql_udf(dbb->dbb_pool); - userFunc->udf_name = metaName; - userFunc->udf_private = !X.RDB$PRIVATE_FLAG.NULL && X.RDB$PRIVATE_FLAG != 0; - - return_arg = X.RDB$RETURN_ARGUMENT; - } - END_FOR - - if (!userFunc) - { - if (maybeUnqualified) - { - maybeUnqualified = false; - metaName.package = ""; - } - else - return NULL; - } + return_arg = X.RDB$RETURN_ARGUMENT; } + END_FOR + + if (!userFunc) + return nullptr; SSHORT defaults = 0; AutoCacheRequest handle2(tdbb, irq_func_return, IRQ_REQUESTS); FOR(REQUEST_HANDLE handle2 TRANSACTION_HANDLE transaction) - X IN RDB$FUNCTION_ARGUMENTS WITH - X.RDB$FUNCTION_NAME EQ metaName.identifier.c_str() AND - X.RDB$PACKAGE_NAME EQUIV NULLIF(metaName.package.c_str(), '') + X IN RDB$FUNCTION_ARGUMENTS + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$FUNCTION_NAME EQ name.object.c_str() AND + X.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') SORTED BY X.RDB$ARGUMENT_POSITION { if (!X.RDB$FIELD_SOURCE.NULL) @@ -687,6 +697,7 @@ dsql_udf* METD_get_function(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat FOR(REQUEST_HANDLE handle3 TRANSACTION_HANDLE transaction) F IN RDB$FIELDS WITH + F.RDB$SCHEMA_NAME EQUIV X.RDB$FIELD_SOURCE_SCHEMA_NAME AND F.RDB$FIELD_NAME EQ X.RDB$FIELD_SOURCE { if (X.RDB$ARGUMENT_POSITION == return_arg) @@ -717,14 +728,20 @@ dsql_udf* METD_get_function(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat !X.RDB$RELATION_NAME.NULL && X.RDB$RELATION_NAME[0]) { // type of column used in declaration - if (isSystemRelation(tdbb, transaction, X.RDB$RELATION_NAME)) + if (isSystemRelation(tdbb, transaction, + QualifiedName(X.RDB$RELATION_NAME, X.RDB$RELATION_SCHEMA_NAME))) + { userFunc->udf_flags |= UDF_sys_based; + } } else if (!X.RDB$FIELD_SOURCE.NULL && X.RDB$FIELD_SOURCE[0]) { // domain used in declaration - if (isSystemDomain(tdbb, transaction, X.RDB$FIELD_SOURCE)) + if (isSystemDomain(tdbb, transaction, + QualifiedName(X.RDB$FIELD_SOURCE, X.RDB$FIELD_SOURCE_SCHEMA_NAME))) + { userFunc->udf_flags |= UDF_sys_based; + } } } else @@ -896,19 +913,13 @@ dsql_udf* METD_get_function(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat dbb->dbb_functions.put(userFunc->udf_name, userFunc); - if (userFunc->udf_private && metaName.package != dsqlScratch->package) - { - status_exception::raise(Arg::Gds(isc_private_function) << - Arg::Str(metaName.identifier) << Arg::Str(metaName.package)); - } - - MET_dsql_cache_use(tdbb, SYM_udf, userFunc->udf_name.identifier, userFunc->udf_name.package); + MET_dsql_cache_use(tdbb, SYM_udf, userFunc->udf_name); return userFunc; } -void METD_get_primary_key(jrd_tra* transaction, const MetaName& relationName, +void METD_get_primary_key(jrd_tra* transaction, const QualifiedName& relationName, Array >& fields) { /************************************** @@ -931,13 +942,12 @@ void METD_get_primary_key(jrd_tra* transaction, const MetaName& relationName, AutoCacheRequest handle(tdbb, irq_primary_key, IRQ_REQUESTS); FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) - X IN RDB$INDICES CROSS - Y IN RDB$INDEX_SEGMENTS - OVER RDB$INDEX_NAME CROSS - Z IN RDB$RELATION_CONSTRAINTS - OVER RDB$INDEX_NAME - WITH Z.RDB$RELATION_NAME EQ relationName.c_str() - AND Z.RDB$CONSTRAINT_TYPE EQ "PRIMARY KEY" + X IN RDB$INDICES + CROSS Y IN RDB$INDEX_SEGMENTS OVER RDB$SCHEMA_NAME, RDB$INDEX_NAME + CROSS Z IN RDB$RELATION_CONSTRAINTS OVER RDB$SCHEMA_NAME, RDB$INDEX_NAME + WITH Z.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + Z.RDB$RELATION_NAME EQ relationName.object.c_str() AND + Z.RDB$CONSTRAINT_TYPE EQ "PRIMARY KEY" SORTED BY Y.RDB$FIELD_POSITION { FieldNode* fieldNode = FB_NEW_POOL(pool) FieldNode(pool); @@ -948,8 +958,7 @@ void METD_get_primary_key(jrd_tra* transaction, const MetaName& relationName, } -dsql_prc* METD_get_procedure(jrd_tra* transaction, DsqlCompilerScratch* dsqlScratch, - const QualifiedName& name) +dsql_prc* METD_get_procedure(jrd_tra* transaction, DsqlCompilerScratch* dsqlScratch, const QualifiedName& name) { /************************************** * @@ -1003,24 +1012,14 @@ dsql_prc* METD_get_procedure(jrd_tra* transaction, DsqlCompilerScratch* dsqlScra // // I hope for a solution, involving savepoint logic. - QualifiedName metaName(name); - - bool maybeUnqualified = dsqlScratch->package.hasData() && metaName.package.isEmpty(); - if (maybeUnqualified) - metaName.package = dsqlScratch->package; + QualifiedName qualifiedName(name); // Start by seeing if symbol is already defined dsql_prc* procedure = NULL; - if (dbb->dbb_procedures.get(metaName, procedure)) + if (dbb->dbb_procedures.get(qualifiedName, procedure)) { - if (procedure->prc_private && metaName.package != dsqlScratch->package) - { - status_exception::raise(Arg::Gds(isc_private_procedure) << - Arg::Str(metaName.identifier) << Arg::Str(metaName.package)); - } - - if (MET_dsql_cache_use(tdbb, SYM_procedure, metaName.identifier, metaName.package)) + if (MET_dsql_cache_use(tdbb, SYM_procedure, qualifiedName)) procedure->prc_flags |= PRC_dropped; } @@ -1032,36 +1031,24 @@ dsql_prc* METD_get_procedure(jrd_tra* transaction, DsqlCompilerScratch* dsqlScra // now see if it is in the database - while (!procedure) + AutoCacheRequest handle1(tdbb, irq_procedure, IRQ_REQUESTS); + + FOR(REQUEST_HANDLE handle1 TRANSACTION_HANDLE transaction) + X IN RDB$PROCEDURES + WITH X.RDB$SCHEMA_NAME EQ qualifiedName.schema.c_str() AND + X.RDB$PROCEDURE_NAME EQ qualifiedName.object.c_str() AND + X.RDB$PACKAGE_NAME EQUIV NULLIF(qualifiedName.package.c_str(), '') { - AutoCacheRequest handle1(tdbb, irq_procedure, IRQ_REQUESTS); - - FOR(REQUEST_HANDLE handle1 TRANSACTION_HANDLE transaction) - X IN RDB$PROCEDURES - WITH X.RDB$PROCEDURE_NAME EQ metaName.identifier.c_str() AND - X.RDB$PACKAGE_NAME EQUIV NULLIF(metaName.package.c_str(), '') - { - fb_utils::exact_name(X.RDB$OWNER_NAME); - - procedure = FB_NEW_POOL(dbb->dbb_pool) dsql_prc(dbb->dbb_pool); - procedure->prc_id = X.RDB$PROCEDURE_ID; - procedure->prc_name = metaName; - procedure->prc_owner = X.RDB$OWNER_NAME; - procedure->prc_private = !X.RDB$PRIVATE_FLAG.NULL && X.RDB$PRIVATE_FLAG != 0; - } - END_FOR - - if (!procedure) - { - if (maybeUnqualified) - { - maybeUnqualified = false; - metaName.package = ""; - } - else - return NULL; - } + procedure = FB_NEW_POOL(dbb->dbb_pool) dsql_prc(dbb->dbb_pool); + procedure->prc_id = X.RDB$PROCEDURE_ID; + procedure->prc_name = qualifiedName; + procedure->prc_owner = X.RDB$OWNER_NAME; + procedure->prc_private = !X.RDB$PRIVATE_FLAG.NULL && X.RDB$PRIVATE_FLAG != 0; } + END_FOR + + if (!procedure) + return nullptr; // Lookup parameter stuff @@ -1076,10 +1063,12 @@ dsql_prc* METD_get_procedure(jrd_tra* transaction, DsqlCompilerScratch* dsqlScra FOR (REQUEST_HANDLE handle2 TRANSACTION_HANDLE transaction) PR IN RDB$PROCEDURE_PARAMETERS CROSS FLD IN RDB$FIELDS - WITH FLD.RDB$FIELD_NAME EQ PR.RDB$FIELD_SOURCE AND - PR.RDB$PROCEDURE_NAME EQ metaName.identifier.c_str() AND + WITH PR.RDB$SCHEMA_NAME EQ qualifiedName.schema.c_str() AND + PR.RDB$PROCEDURE_NAME EQ qualifiedName.object.c_str() AND PR.RDB$PARAMETER_TYPE = type AND - PR.RDB$PACKAGE_NAME EQUIV NULLIF(metaName.package.c_str(), '') + PR.RDB$PACKAGE_NAME EQUIV NULLIF(qualifiedName.package.c_str(), '') AND + FLD.RDB$SCHEMA_NAME EQUIV PR.RDB$FIELD_SOURCE_SCHEMA_NAME AND + FLD.RDB$FIELD_NAME EQ PR.RDB$FIELD_SOURCE SORTED BY DESCENDING PR.RDB$PARAMETER_NUMBER { const SSHORT pr_collation_id_null = PR.RDB$COLLATION_ID.NULL; @@ -1106,7 +1095,7 @@ dsql_prc* METD_get_procedure(jrd_tra* transaction, DsqlCompilerScratch* dsqlScra // get parameter information parameter->fld_name = PR.RDB$PARAMETER_NAME; - parameter->fieldSource = PR.RDB$FIELD_SOURCE; + parameter->fieldSource = QualifiedName(PR.RDB$FIELD_SOURCE, PR.RDB$FIELD_SOURCE_SCHEMA_NAME); parameter->fld_id = PR.RDB$PARAMETER_NUMBER; parameter->length = FLD.RDB$FIELD_LENGTH; @@ -1138,28 +1127,25 @@ dsql_prc* METD_get_procedure(jrd_tra* transaction, DsqlCompilerScratch* dsqlScra if (!PR.RDB$FIELD_NAME.NULL) { fb_utils::exact_name(PR.RDB$FIELD_NAME); - parameter->typeOfName = PR.RDB$FIELD_NAME; + parameter->typeOfName = QualifiedName(PR.RDB$FIELD_NAME, PR.RDB$FIELD_SOURCE_SCHEMA_NAME); } if (!PR.RDB$RELATION_NAME.NULL) - { - fb_utils::exact_name(PR.RDB$RELATION_NAME); - parameter->typeOfTable = PR.RDB$RELATION_NAME; - } + parameter->typeOfTable = QualifiedName(PR.RDB$RELATION_NAME, PR.RDB$RELATION_SCHEMA_NAME); - if (parameter->typeOfTable.hasData()) + if (parameter->typeOfTable.object.hasData()) { - if (isSystemRelation(tdbb, transaction, parameter->typeOfTable.c_str())) + if (isSystemRelation(tdbb, transaction, parameter->typeOfTable)) parameter->flags |= FLD_system; } - else if (parameter->typeOfName.hasData()) + else if (parameter->typeOfName.object.hasData()) { - if (isSystemDomain(tdbb, transaction, parameter->typeOfName.c_str())) + if (isSystemDomain(tdbb, transaction, parameter->typeOfName)) parameter->flags |= FLD_system; } - else if (parameter->fieldSource.hasData()) + else if (parameter->fieldSource.object.hasData()) { - if (isSystemDomain(tdbb, transaction, parameter->fieldSource.c_str())) + if (isSystemDomain(tdbb, transaction, parameter->fieldSource)) parameter->flags |= FLD_system; } @@ -1183,21 +1169,14 @@ dsql_prc* METD_get_procedure(jrd_tra* transaction, DsqlCompilerScratch* dsqlScra dbb->dbb_procedures.put(procedure->prc_name, procedure); - if (procedure->prc_private && metaName.package != dsqlScratch->package) - { - status_exception::raise(Arg::Gds(isc_private_procedure) << - Arg::Str(metaName.identifier) << Arg::Str(metaName.package)); - } - - MET_dsql_cache_use(tdbb, SYM_procedure, procedure->prc_name.identifier, - procedure->prc_name.package); + MET_dsql_cache_use(tdbb, SYM_procedure, procedure->prc_name); return procedure; } dsql_rel* METD_get_relation(jrd_tra* transaction, DsqlCompilerScratch* dsqlScratch, - const MetaName& name) + const QualifiedName& name) { /************************************** * @@ -1242,9 +1221,10 @@ dsql_rel* METD_get_relation(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat FOR(REQUEST_HANDLE handle1 TRANSACTION_HANDLE transaction) REL IN RDB$RELATIONS - CROSS RFR IN RDB$RELATION_FIELDS OVER RDB$RELATION_NAME - WITH REL.RDB$RELATION_NAME EQ name.c_str() - AND (REL.RDB$RELATION_ID MISSING OR RFR.RDB$FIELD_ID MISSING) + CROSS RFR IN RDB$RELATION_FIELDS OVER RDB$SCHEMA_NAME, RDB$RELATION_NAME + WITH REL.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + REL.RDB$RELATION_NAME EQ name.object.c_str() AND + (REL.RDB$RELATION_ID MISSING OR RFR.RDB$FIELD_ID MISSING) { permanent = false; } @@ -1259,10 +1239,10 @@ dsql_rel* METD_get_relation(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat AutoCacheRequest handle2(tdbb, irq_relation, IRQ_REQUESTS); FOR(REQUEST_HANDLE handle2 TRANSACTION_HANDLE transaction) - X IN RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ name.c_str() + X IN RDB$RELATIONS + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$RELATION_NAME EQ name.object.c_str() { - fb_utils::exact_name(X.RDB$OWNER_NAME); - // Allocate from default or permanent pool as appropriate if (!X.RDB$RELATION_ID.NULL) @@ -1300,17 +1280,15 @@ dsql_rel* METD_get_relation(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat AutoCacheRequest handle3(tdbb, irq_fields, IRQ_REQUESTS); FOR(REQUEST_HANDLE handle3 TRANSACTION_HANDLE transaction) - FLX IN RDB$FIELDS CROSS - RFR IN RDB$RELATION_FIELDS - WITH FLX.RDB$FIELD_NAME EQ RFR.RDB$FIELD_SOURCE - AND RFR.RDB$RELATION_NAME EQ name.c_str() + FLX IN RDB$FIELDS + CROSS RFR IN RDB$RELATION_FIELDS + WITH RFR.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + RFR.RDB$RELATION_NAME EQ name.object.c_str() AND + FLX.RDB$SCHEMA_NAME EQUIV RFR.RDB$FIELD_SOURCE_SCHEMA_NAME AND + FLX.RDB$FIELD_NAME EQ RFR.RDB$FIELD_SOURCE SORTED BY RFR.RDB$FIELD_POSITION { - // allocate the field block - - fb_utils::exact_name(RFR.RDB$FIELD_NAME); - fb_utils::exact_name(RFR.RDB$FIELD_SOURCE); - + // Allocate the field block // Allocate from default or permanent pool as appropriate dsql_fld* field = NULL; @@ -1331,7 +1309,7 @@ dsql_rel* METD_get_relation(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat // get field information field->fld_name = RFR.RDB$FIELD_NAME; - field->fieldSource = RFR.RDB$FIELD_SOURCE; + field->fieldSource = QualifiedName(RFR.RDB$FIELD_SOURCE, RFR.RDB$FIELD_SOURCE_SCHEMA_NAME); field->length = FLX.RDB$FIELD_LENGTH; field->scale = FLX.RDB$FIELD_SCALE; field->subType = FLX.RDB$FIELD_SUB_TYPE; @@ -1415,8 +1393,9 @@ bool METD_get_type(jrd_tra* transaction, const MetaName& name, const char* field AutoCacheRequest handle(tdbb, irq_type, IRQ_REQUESTS); FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) - X IN RDB$TYPES WITH - X.RDB$FIELD_NAME EQ field AND X.RDB$TYPE_NAME EQ name.c_str(); + X IN RDB$TYPES + WITH X.RDB$FIELD_NAME EQ field AND + X.RDB$TYPE_NAME EQ name.c_str() { found = true; *value = X.RDB$TYPE; @@ -1428,7 +1407,7 @@ bool METD_get_type(jrd_tra* transaction, const MetaName& name, const char* field dsql_rel* METD_get_view_base(jrd_tra* transaction, DsqlCompilerScratch* dsqlScratch, - const char* view_name, MetaNamePairMap& fields) + const QualifiedName& viewName, MetaNamePairMap& fields) { /************************************** * @@ -1449,8 +1428,8 @@ dsql_rel* METD_get_view_base(jrd_tra* transaction, DsqlCompilerScratch* dsqlScra validateTransaction(transaction); - dsql_rel* relation = NULL; - + auto nextViewName = viewName; + dsql_rel* relation = nullptr; bool first = true; bool cont = true; MetaNamePairMap previousAux; @@ -1463,7 +1442,8 @@ dsql_rel* METD_get_view_base(jrd_tra* transaction, DsqlCompilerScratch* dsqlScra FOR(REQUEST_HANDLE handle1 TRANSACTION_HANDLE transaction) X IN RDB$VIEW_RELATIONS - WITH X.RDB$VIEW_NAME EQ view_name + WITH X.RDB$SCHEMA_NAME EQ nextViewName.schema.c_str() AND + X.RDB$VIEW_NAME EQ nextViewName.object.c_str() { // return NULL if there is more than one context if (X.RDB$VIEW_CONTEXT != 1 || X.RDB$CONTEXT_TYPE == VCT_PROCEDURE) @@ -1473,10 +1453,8 @@ dsql_rel* METD_get_view_base(jrd_tra* transaction, DsqlCompilerScratch* dsqlScra break; } - fb_utils::exact_name(X.RDB$CONTEXT_NAME); - fb_utils::exact_name(X.RDB$RELATION_NAME); - - relation = METD_get_relation(transaction, dsqlScratch, X.RDB$RELATION_NAME); + nextViewName = QualifiedName(X.RDB$RELATION_NAME, X.RDB$RELATION_SCHEMA_NAME); + relation = METD_get_relation(transaction, dsqlScratch, nextViewName); Array ambiguities; MetaNamePairMap currentAux; @@ -1491,7 +1469,8 @@ dsql_rel* METD_get_view_base(jrd_tra* transaction, DsqlCompilerScratch* dsqlScra FOR(REQUEST_HANDLE handle2 TRANSACTION_HANDLE transaction) RFL IN RDB$RELATION_FIELDS - WITH RFL.RDB$RELATION_NAME EQ X.RDB$VIEW_NAME + WITH RFL.RDB$SCHEMA_NAME EQUIV X.RDB$SCHEMA_NAME AND + RFL.RDB$RELATION_NAME EQ X.RDB$VIEW_NAME { if (RFL.RDB$BASE_FIELD.NULL || RFL.RDB$FIELD_NAME.NULL) continue; @@ -1534,9 +1513,7 @@ dsql_rel* METD_get_view_base(jrd_tra* transaction, DsqlCompilerScratch* dsqlScra previousAux.takeOwnership(currentAux); - if (relation->rel_flags & REL_view) - view_name = X.RDB$RELATION_NAME; - else + if (!(relation->rel_flags & REL_view)) { cont = false; break; @@ -1555,7 +1532,7 @@ dsql_rel* METD_get_view_base(jrd_tra* transaction, DsqlCompilerScratch* dsqlScra bool METD_get_view_relation(jrd_tra* transaction, DsqlCompilerScratch* dsqlScratch, - const Jrd::MetaName& view_name, const Jrd::MetaName& relation_or_alias, + const Jrd::QualifiedName& view_name, const Jrd::QualifiedName& relation_or_alias, dsql_rel*& relation, dsql_prc*& procedure) { /************************************** @@ -1577,29 +1554,27 @@ bool METD_get_view_relation(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat AutoCacheRequest handle(tdbb, irq_view, IRQ_REQUESTS); FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) - X IN RDB$VIEW_RELATIONS WITH X.RDB$VIEW_NAME EQ view_name.c_str() + X IN RDB$VIEW_RELATIONS + WITH X.RDB$SCHEMA_NAME EQ view_name.schema.c_str() AND + X.RDB$VIEW_NAME EQ view_name.object.c_str() { - fb_utils::exact_name(X.RDB$CONTEXT_NAME); - fb_utils::exact_name(X.RDB$RELATION_NAME); + QualifiedName relationName(X.RDB$RELATION_NAME, X.RDB$RELATION_SCHEMA_NAME); - if (relation_or_alias == X.RDB$RELATION_NAME || - relation_or_alias == X.RDB$CONTEXT_NAME) + if (PASS1_compare_alias(relationName, relation_or_alias) || + (relation_or_alias.schema.isEmpty() && relation_or_alias.object == X.RDB$CONTEXT_NAME)) { - if ( (relation = METD_get_relation(transaction, dsqlScratch, X.RDB$RELATION_NAME)) ) + if ((relation = METD_get_relation(transaction, dsqlScratch, relationName))) return true; - const QualifiedName procName(X.RDB$RELATION_NAME, + const QualifiedName procName(X.RDB$RELATION_NAME, X.RDB$RELATION_SCHEMA_NAME, X.RDB$PACKAGE_NAME.NULL ? nullptr : X.RDB$PACKAGE_NAME); if ( (procedure = METD_get_procedure(transaction, dsqlScratch, procName)) ) return true; } - if (METD_get_view_relation(transaction, dsqlScratch, X.RDB$RELATION_NAME, - relation_or_alias, relation, procedure)) - { + if (METD_get_view_relation(transaction, dsqlScratch, relationName, relation_or_alias, relation, procedure)) return true; - } } END_FOR diff --git a/src/dsql/metd_proto.h b/src/dsql/metd_proto.h index f2130052ec..a6a98db67e 100644 --- a/src/dsql/metd_proto.h +++ b/src/dsql/metd_proto.h @@ -45,29 +45,30 @@ namespace Jrd { class FieldNode; }; -void METD_drop_charset(Jrd::jrd_tra*, const Jrd::MetaName&); -void METD_drop_collation(Jrd::jrd_tra*, const Jrd::MetaName&); +void METD_drop_charset(Jrd::jrd_tra*, const Jrd::QualifiedName&); +void METD_drop_collation(Jrd::jrd_tra*, const Jrd::QualifiedName&); void METD_drop_function(Jrd::jrd_tra*, const Jrd::QualifiedName&); void METD_drop_procedure(Jrd::jrd_tra*, const Jrd::QualifiedName&); -void METD_drop_relation(Jrd::jrd_tra*, const Jrd::MetaName&); +void METD_drop_relation(Jrd::jrd_tra*, const Jrd::QualifiedName&); -Jrd::dsql_intlsym* METD_get_charset(Jrd::jrd_tra*, USHORT, const char* name); +Jrd::dsql_intlsym* METD_get_charset(Jrd::jrd_tra*, const Jrd::QualifiedName& name); USHORT METD_get_charset_bpc(Jrd::jrd_tra*, SSHORT); -Jrd::MetaName METD_get_charset_name(Jrd::jrd_tra*, SSHORT); -Jrd::dsql_intlsym* METD_get_collation(Jrd::jrd_tra*, const Jrd::MetaName&, USHORT charset_id); -Jrd::MetaName METD_get_default_charset(Jrd::jrd_tra*); -bool METD_get_domain(Jrd::jrd_tra*, class Jrd::TypeClause*, const Jrd::MetaName& name); +Jrd::QualifiedName METD_get_charset_name(Jrd::jrd_tra*, SSHORT); +Jrd::dsql_intlsym* METD_get_collation(Jrd::jrd_tra*, const Jrd::QualifiedName&, USHORT charset_id); +Jrd::QualifiedName METD_get_database_charset(Jrd::jrd_tra*); +Jrd::QualifiedName METD_get_schema_charset(Jrd::jrd_tra*, const Jrd::MetaName&); +bool METD_get_domain(Jrd::jrd_tra*, class Jrd::TypeClause*, const Jrd::QualifiedName& name); Jrd::dsql_udf* METD_get_function(Jrd::jrd_tra*, Jrd::DsqlCompilerScratch*, const Jrd::QualifiedName&); -void METD_get_primary_key(Jrd::jrd_tra*, const Jrd::MetaName&, - Firebird::Array >&); +void METD_get_primary_key(Jrd::jrd_tra*, const Jrd::QualifiedName&, + Firebird::Array>&); Jrd::dsql_prc* METD_get_procedure(Jrd::jrd_tra*, Jrd::DsqlCompilerScratch*, const Jrd::QualifiedName&); -Jrd::dsql_rel* METD_get_relation(Jrd::jrd_tra*, Jrd::DsqlCompilerScratch*, const Jrd::MetaName&); +Jrd::dsql_rel* METD_get_relation(Jrd::jrd_tra*, Jrd::DsqlCompilerScratch*, const Jrd::QualifiedName&); bool METD_get_type(Jrd::jrd_tra*, const Jrd::MetaName&, const char*, SSHORT*); -Jrd::dsql_rel* METD_get_view_base(Jrd::jrd_tra*, Jrd::DsqlCompilerScratch*, const char* view_name, +Jrd::dsql_rel* METD_get_view_base(Jrd::jrd_tra*, Jrd::DsqlCompilerScratch*, const Jrd::QualifiedName& viewName, Jrd::MetaNamePairMap& fields); -bool METD_get_view_relation(Jrd::jrd_tra*, Jrd::DsqlCompilerScratch*, const Jrd::MetaName& view_name, - const Jrd::MetaName& relation_or_alias, Jrd::dsql_rel*& relation, Jrd::dsql_prc*& procedure); +bool METD_get_view_relation(Jrd::jrd_tra*, Jrd::DsqlCompilerScratch*, const Jrd::QualifiedName& view_name, + const Jrd::QualifiedName& relation_or_alias, Jrd::dsql_rel*& relation, Jrd::dsql_prc*& procedure); #endif // DSQL_METD_PROTO_H diff --git a/src/dsql/parse-conflicts.txt b/src/dsql/parse-conflicts.txt index 612edc3bcf..03604e577a 100644 --- a/src/dsql/parse-conflicts.txt +++ b/src/dsql/parse-conflicts.txt @@ -1 +1 @@ -117 shift/reduce conflicts, 22 reduce/reduce conflicts. +130 shift/reduce conflicts, 13 reduce/reduce conflicts. diff --git a/src/dsql/parse.y b/src/dsql/parse.y index c44adee3e8..31a7f5caf0 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -704,10 +704,13 @@ using namespace Firebird; %token ANY_VALUE %token BTRIM %token CALL +%token CURRENT_SCHEMA %token FORMAT %token LTRIM %token NAMED_ARG_ASSIGN %token RTRIM +%token SCHEMA +%token SEARCH_PATH // precedence declarations for expression evaluation @@ -762,6 +765,7 @@ using namespace Firebird; Jrd::ReturningClause* returningClause; Jrd::MetaName* metaNamePtr; Firebird::ObjectsArray* metaNameArray; + Firebird::ObjectsArray* qualifiedNameArray; Firebird::PathName* pathNamePtr; Jrd::QualifiedName* qualifiedNamePtr; Firebird::string* stringPtr; @@ -813,6 +817,7 @@ using namespace Firebird; Jrd::CreateFilterNode::NameNumber* filterNameNumber; Jrd::CreateAlterExceptionNode* createAlterExceptionNode; Jrd::CreateAlterSequenceNode* createAlterSequenceNode; + Jrd::CreateAlterSchemaNode* createAlterSchemaNode; Jrd::CreateShadowNode* createShadowNode; Firebird::Array* packageItems; Jrd::ExceptionArray* exceptionArray; @@ -944,6 +949,7 @@ mng_statement | set_time_zone { $$ = $1; } | set_bind { $$ = $1; } | set_optimize { $$ = $1; } + | set_search_path { $$ = $1; } ; @@ -1008,6 +1014,13 @@ grant0($node) $node->grantAdminOption = $7; $node->grantor = $8; } + | usage_privilege(NOTRIAL(&$node->privileges)) ON SCHEMA symbol_schema_name + TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by + { + $node->object = newNode(obj_schema, QualifiedName(*$4)); + $node->grantAdminOption = $7; + $node->grantor = $8; + } /*** | usage_privilege(NOTRIAL(&$node->privileges)) ON DOMAIN symbol_domain_name TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by @@ -1031,7 +1044,15 @@ grant0($node) $node->grantor = $8; } ***/ - | ddl_privileges(NOTRIAL(&$node->privileges)) object + | ddl_privileges(NOTRIAL(&$node->privileges)) schema_object on_schema_opt + TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by + { + $node->object = newNode($2, QualifiedName(getSecurityClassName($2), ($3 ? *$3 : ""))); + $node->grantAdminOption = $6; + $node->grantor = $7; + $node->isDdl = true; + } + | ddl_privileges(NOTRIAL(&$node->privileges)) schemaless_object TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by { $node->object = $2; @@ -1042,7 +1063,7 @@ grant0($node) | db_ddl_privileges(NOTRIAL(&$node->privileges)) DATABASE TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by { - $node->object = newNode(obj_database, getSecurityClassName(obj_database)); + $node->object = newNode(obj_database, QualifiedName(getSecurityClassName(obj_database))); $node->grantAdminOption = $5; $node->grantor = $6; $node->isDdl = true; @@ -1055,34 +1076,35 @@ grant0($node) } ; -%type object -object - : TABLE - { $$ = newNode(obj_relations, getSecurityClassName(obj_relations)); } - | VIEW - { $$ = newNode(obj_views, getSecurityClassName(obj_views)); } - | PROCEDURE - { $$ = newNode(obj_procedures, getSecurityClassName(obj_procedures)); } - | FUNCTION - { $$ = newNode(obj_functions, getSecurityClassName(obj_functions)); } - | PACKAGE - { $$ = newNode(obj_packages, getSecurityClassName(obj_packages)); } - | GENERATOR - { $$ = newNode(obj_generators, getSecurityClassName(obj_generators)); } - | SEQUENCE - { $$ = newNode(obj_generators, getSecurityClassName(obj_generators)); } - | DOMAIN - { $$ = newNode(obj_domains, getSecurityClassName(obj_domains)); } - | EXCEPTION - { $$ = newNode(obj_exceptions, getSecurityClassName(obj_exceptions)); } - | ROLE - { $$ = newNode(obj_roles, getSecurityClassName(obj_roles)); } - | CHARACTER SET - { $$ = newNode(obj_charsets, getSecurityClassName(obj_charsets)); } - | COLLATION - { $$ = newNode(obj_collations, getSecurityClassName(obj_collations)); } +%type on_schema_opt +on_schema_opt + : /* nothing */ { $$ = nullptr; } + | ON SCHEMA symbol_schema_name { $$ = $3; } + ; + +%type schema_object +schema_object + : TABLE { $$ = obj_relations; } + | VIEW { $$ = obj_views; } + | PROCEDURE { $$ = obj_procedures; } + | FUNCTION { $$ = obj_functions; } + | PACKAGE { $$ = obj_packages; } + | GENERATOR { $$ = obj_generators; } + | SEQUENCE { $$ = obj_generators; } + | DOMAIN { $$ = obj_domains; } + | EXCEPTION { $$ = obj_exceptions; } + | CHARACTER SET { $$ = obj_charsets; } + | COLLATION { $$ = obj_collations; } + ; + +%type schemaless_object +schemaless_object + : ROLE + { $$ = newNode(obj_roles, QualifiedName(getSecurityClassName(obj_roles))); } | FILTER - { $$ = newNode(obj_filters, getSecurityClassName(obj_filters)); } + { $$ = newNode(obj_filters, QualifiedName(getSecurityClassName(obj_filters))); } + | SCHEMA + { $$ = newNode(obj_schemas, QualifiedName(getSecurityClassName(obj_schemas))); } ; table_noise @@ -1114,11 +1136,33 @@ usage_privilege($privilegeArray) %type privilege() privilege($privilegeArray) - : SELECT { $privilegeArray->add(PrivilegeClause('S', NULL)); } - | INSERT { $privilegeArray->add(PrivilegeClause('I', NULL)); } - | DELETE { $privilegeArray->add(PrivilegeClause('D', NULL)); } - | UPDATE column_parens_opt { $privilegeArray->add(PrivilegeClause('U', $2)); } - | REFERENCES column_parens_opt { $privilegeArray->add(PrivilegeClause('R', $2)); } + : SELECT { $privilegeArray->add(PrivilegeClause('S', NULL)); } + | INSERT { $privilegeArray->add(PrivilegeClause('I', NULL)); } + | DELETE { $privilegeArray->add(PrivilegeClause('D', NULL)); } + | UPDATE column_name_list_parens_opt { $privilegeArray->add(PrivilegeClause('U', $2)); } + | REFERENCES column_name_list_parens_opt { $privilegeArray->add(PrivilegeClause('R', $2)); } + ; + +%type column_name_list_parens_opt +column_name_list_parens_opt + : /* nothing */ { $$ = nullptr; } + | '(' column_name_list ')' { $$ = $2; } + ; + +%type column_name_list +column_name_list + : symbol_column_name + { + const auto node = newNode>(); + node->add(*$1); + $$ = node; + } + | column_name_list ',' symbol_column_name + { + const auto node = $1; + node->add(*$3); + $$ = node; + } ; %type ddl_privileges() @@ -1222,7 +1266,6 @@ revoke0($node) $node->grantAdminOption = $1; $node->grantor = $8; } - | rev_grant_option execute_privilege(NOTRIAL(&$node->privileges)) ON PROCEDURE symbol_procedure_name FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by { @@ -1265,6 +1308,13 @@ revoke0($node) $node->grantAdminOption = $1; $node->grantor = $8; } + | rev_grant_option usage_privilege(NOTRIAL(&$node->privileges)) ON SCHEMA symbol_schema_name + FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by + { + $node->object = newNode(obj_schema, QualifiedName(*$5)); + $node->grantAdminOption = $1; + $node->grantor = $8; + } /*** | rev_grant_option usage_privilege(NOTRIAL(&$node->privileges)) ON DOMAIN symbol_domain_name FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by @@ -1288,7 +1338,15 @@ revoke0($node) $node->grantor = $8; } ***/ - | rev_grant_option ddl_privileges(NOTRIAL(&$node->privileges)) object + | rev_grant_option ddl_privileges(NOTRIAL(&$node->privileges)) schema_object on_schema_opt + FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by + { + $node->object = newNode($3, QualifiedName(getSecurityClassName($3), ($4 ? *$4 : ""))); + $node->grantAdminOption = $1; + $node->grantor = $7; + $node->isDdl = true; + } + | rev_grant_option ddl_privileges(NOTRIAL(&$node->privileges)) schemaless_object FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by { $node->object = $3; @@ -1299,7 +1357,7 @@ revoke0($node) | rev_grant_option db_ddl_privileges(NOTRIAL(&$node->privileges)) DATABASE FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by { - $node->object = newNode(obj_database, getSecurityClassName(obj_database)); + $node->object = newNode(obj_database, QualifiedName(getSecurityClassName(obj_database))); $node->grantAdminOption = $1; $node->grantor = $6; $node->isDdl = true; @@ -1346,9 +1404,9 @@ grantee($granteeArray) | VIEW symbol_view_name { $granteeArray->add(GranteeClause(obj_view, *$2)); } | ROLE symbol_role_name - { $granteeArray->add(GranteeClause(obj_sql_role, *$2)); } + { $granteeArray->add(GranteeClause(obj_sql_role, QualifiedName(*$2))); } | SYSTEM PRIVILEGE valid_symbol_name - { $granteeArray->add(GranteeClause(obj_privilege, *$3)); } + { $granteeArray->add(GranteeClause(obj_privilege, QualifiedName(*$3))); } ; // CVC: In the future we can deprecate the first implicit form since we'll support @@ -1357,11 +1415,11 @@ grantee($granteeArray) %type user_grantee() user_grantee($granteeArray) : symbol_user_name - { $granteeArray->add(GranteeClause(obj_user_or_role, *$1)); } + { $granteeArray->add(GranteeClause(obj_user_or_role, QualifiedName(*$1))); } | USER symbol_user_name - { $granteeArray->add(GranteeClause(obj_user, *$2)); } + { $granteeArray->add(GranteeClause(obj_user, QualifiedName(*$2))); } | GROUP symbol_user_name - { $granteeArray->add(GranteeClause(obj_user_group, *$2)); } + { $granteeArray->add(GranteeClause(obj_user_group, QualifiedName(*$2))); } ; %type role_name_list() @@ -1374,12 +1432,12 @@ role_name_list($grantRevokeNode) role_name($grantRevokeNode) : symbol_role_name { - $grantRevokeNode->roles.add(GranteeClause(obj_sql_role, *$1)); + $grantRevokeNode->roles.add(GranteeClause(obj_sql_role, QualifiedName(*$1))); $grantRevokeNode->defaultRoles.add(false); } | DEFAULT symbol_role_name { - $grantRevokeNode->roles.add(GranteeClause(obj_sql_role, *$2)); + $grantRevokeNode->roles.add(GranteeClause(obj_sql_role, QualifiedName(*$2))); $grantRevokeNode->defaultRoles.add(true); } ; @@ -1392,9 +1450,9 @@ role_grantee_list($granteeArray) %type role_grantee() role_grantee($granteeArray) - : symbol_user_name { $granteeArray->add(GranteeClause(obj_user_or_role, *$1)); } - | USER symbol_user_name { $granteeArray->add(GranteeClause(obj_user, *$2)); } - | ROLE symbol_user_name { $granteeArray->add(GranteeClause(obj_sql_role, *$2)); } + : symbol_user_name { $granteeArray->add(GranteeClause(obj_user_or_role, QualifiedName(*$1))); } + | USER symbol_user_name { $granteeArray->add(GranteeClause(obj_user, QualifiedName(*$2))); } + | ROLE symbol_user_name { $granteeArray->add(GranteeClause(obj_sql_role, QualifiedName(*$2))); } ; // DECLARE operations @@ -1664,6 +1722,12 @@ create_clause node->createIfNotExistsOnly = $3; $$ = node; } + | SCHEMA if_not_exists_opt schema_clause + { + const auto node = $3; + node->createIfNotExistsOnly = $2; + $$ = node; + } ; @@ -1698,6 +1762,8 @@ recreate_clause { $$ = newNode($2); } | USER create_user_clause { $$ = newNode($2); } + | SCHEMA schema_clause + { $$ = newNode($2); } ; %type create_or_alter @@ -1719,6 +1785,7 @@ replace_clause | USER replace_user_clause { $$ = $2; } | MAPPING replace_map_clause(false) { $$ = $2; } | GLOBAL MAPPING replace_map_clause(true) { $$ = $3; } + | SCHEMA replace_schema_clause { $$ = $2; } ; @@ -1827,11 +1894,9 @@ conditional %type domain_clause domain_clause - : symbol_column_name as_opt data_type domain_default_opt + : symbol_domain_name as_opt data_type domain_default_opt { - $3->fld_name = *$1; - $$ = newNode( - newNode($3, $4)); + $$ = newNode(*$1, $3, $4); } domain_constraints_opt($5) collate_clause { @@ -2494,14 +2559,14 @@ computed_by %type data_type_or_domain data_type_or_domain : data_type - | symbol_column_name + | symbol_domain_name { $$ = newNode(); $$->typeOfName = *$1; } ; -%type collate_clause +%type collate_clause collate_clause : { $$ = NULL; } | COLLATE symbol_collation_name { $$ = $2; } @@ -2511,23 +2576,7 @@ collate_clause %type data_type_descriptor data_type_descriptor : data_type - | TYPE OF symbol_column_name - { - $$ = newNode(); - $$->typeOfName = *$3; - } - | TYPE OF COLUMN symbol_column_name '.' symbol_column_name - { - $$ = newNode(); - $$->typeOfTable = *$4; - $$->typeOfName = *$6; - } - | symbol_column_name - { - $$ = newNode(); - $$->typeOfName = *$1; - $$->fullDomain = true; - } + | domain_type ; @@ -2707,7 +2756,7 @@ table_constraint($relationNode) constraint_index_opt : // nothing { $$ = newNode(); } - | USING order_direction INDEX symbol_index_name + | USING order_direction INDEX valid_symbol_name { RelationNode::IndexConstraintClause* clause = $$ = newNode(); @@ -3155,13 +3204,68 @@ package_body_item { $$ = CreateAlterPackageNode::Item::create($2); } ; - %type replace_package_body_clause replace_package_body_clause : package_body_clause { $$ = newNode($1); } ; + +%type replace_schema_clause +replace_schema_clause + : schema_clause + { + $$ = $1; + $$->alter = true; + } + ; + +%type schema_clause +schema_clause + : symbol_schema_name + { $$ = newNode(*$1); } + schema_clause_options_opt($2) + { $$ = $2; } + ; + +%type schema_clause_options_opt() +schema_clause_options_opt($createAlterSchemaNode) + : // nothing + | schema_clause_options($createAlterSchemaNode) + ; + +%type schema_clause_options() +schema_clause_options($createAlterSchemaNode) + : DEFAULT CHARACTER SET symbol_character_set_name + { setClause($createAlterSchemaNode->setDefaultCharSet, "DEFAULT CHARACTER SET", *$4); } + ; + +%type alter_schema_clause +alter_schema_clause + : symbol_schema_name + { + const auto node = newNode(*$1); + node->create = false; + node->alter = true; + $$ = node; + } + alter_schema_options($2) + { $$ = $2; } + ; + +%type alter_schema_options() +alter_schema_options($alterSchemaNode) + : alter_schema_option($alterSchemaNode) + | alter_schema_options alter_schema_option($alterSchemaNode) + ; + +%type alter_schema_option() +alter_schema_option($alterSchemaNode) + : SET DEFAULT CHARACTER SET symbol_character_set_name + { setClause($alterSchemaNode->setDefaultCharSet, "SET DEFAULT CHARACTER SET", *$5); } + ; + + %type local_declarations_opt local_declarations_opt : local_forward_declarations_opt local_nonforward_declarations_opt @@ -3261,7 +3365,7 @@ local_nonforward_declaration %type local_declaration_subproc_start local_declaration_subproc_start - : DECLARE PROCEDURE symbol_procedure_name + : DECLARE PROCEDURE valid_symbol_name { $$ = newNode(NOTRIAL(*$3)); $$->dsqlBlock = newNode(); @@ -3273,7 +3377,7 @@ local_declaration_subproc_start %type local_declaration_subfunc_start local_declaration_subfunc_start - : DECLARE FUNCTION symbol_UDF_name + : DECLARE FUNCTION valid_symbol_name { $$ = newNode(NOTRIAL(*$3)); $$->dsqlBlock = newNode(); @@ -3809,19 +3913,19 @@ err($exceptionArray) { ExceptionItem& item = $exceptionArray->add(); item.type = ExceptionItem::SQL_STATE; - item.name = $2->getString(); + item.name.object = $2->getString(); } | GDSCODE symbol_gdscode_name { ExceptionItem& item = $exceptionArray->add(); item.type = ExceptionItem::GDS_CODE; - item.name = $2->c_str(); + item.name.object = *$2; } | EXCEPTION symbol_exception_name { ExceptionItem& item = $exceptionArray->add(); item.type = ExceptionItem::XCP_CODE; - item.name = $2->c_str(); + item.name = *$2; } | ANY { @@ -3891,22 +3995,14 @@ fetch_scroll($cursorStmtNode) %type exec_procedure exec_procedure - : EXECUTE PROCEDURE symbol_procedure_name proc_inputs proc_outputs_opt + : EXECUTE PROCEDURE qualified_name proc_inputs proc_outputs_opt { $$ = newNode( - QualifiedName(*$3), + *$3, ($4 ? $4->second : nullptr), $5, ($4 ? $4->first : nullptr)); } - | EXECUTE PROCEDURE symbol_package_name '.' symbol_procedure_name proc_inputs proc_outputs_opt - { - $$ = newNode( - QualifiedName(*$5, *$3), - ($6 ? $6->second : nullptr), - $7, - ($6 ? $6->first : nullptr)); - } ; %type proc_inputs @@ -3927,25 +4023,15 @@ proc_outputs_opt %type call call - : CALL symbol_procedure_name '(' argument_list_opt ')' + : CALL qualified_name '(' argument_list_opt ')' { - auto node = newNode(QualifiedName(*$2), + auto node = newNode(*$2, ($4 ? $4->second : nullptr), nullptr, ($4 ? $4->first : nullptr)); node->dsqlCallSyntax = true; $$ = node; } - | CALL symbol_package_name '.' symbol_procedure_name '(' argument_list_opt ')' - into_variable_list_opt - { - auto node = newNode(QualifiedName(*$4, *$2), - ($6 ? $6->second : nullptr), - nullptr, - ($6 ? $6->first : nullptr)); - node->dsqlCallSyntax = true; - $$ = node; - } ; // EXECUTE BLOCK @@ -4246,16 +4332,23 @@ alter_clause | MAPPING alter_map_clause(false) { $$ = $2; } | GLOBAL MAPPING alter_map_clause(true) { $$ = $3; } | EXTERNAL CONNECTIONS POOL alter_eds_conn_pool_clause { $$ = $4; } + | SCHEMA alter_schema_clause { $$ = $2; } ; %type alter_domain alter_domain - : keyword_or_column + : alter_domain_name { $$ = newNode(*$1); } alter_domain_ops($2) { $$ = $2; } ; +%type alter_domain_name +alter_domain_name + : keyword_or_column { $$ = newNode(*$1); } + | valid_symbol_name '.' keyword_or_column { $$ = newNode(*$3, *$1); } + ; + %type alter_domain_ops() alter_domain_ops($alterDomainNode) : alter_domain_op($alterDomainNode) @@ -4278,14 +4371,14 @@ alter_domain_op($alterDomainNode) { setClause($alterDomainNode->notNullFlag, "{SET | DROP} NOT NULL", false); } | SET NOT NULL { setClause($alterDomainNode->notNullFlag, "{SET | DROP} NOT NULL", true); } - | TO symbol_column_name + | TO valid_symbol_name { setClause($alterDomainNode->renameTo, "DOMAIN NAME", *$2); } | TYPE non_array_type { //// FIXME: ALTER DOMAIN doesn't support collations, and altered domain's //// collation is always lost. dsql_fld* type = $2; - type->collate = ""; + type->collate.clear(); setClause($alterDomainNode->type, "DOMAIN TYPE", type); } ; @@ -4555,6 +4648,7 @@ keyword_or_column | WITHOUT | BTRIM // added in FB 6.0 | CALL + | CURRENT_SCHEMA | LTRIM | RTRIM ; @@ -4567,7 +4661,7 @@ col_opt %type alter_data_type_or_domain alter_data_type_or_domain : non_array_type - | symbol_column_name + | symbol_domain_name { $$ = newNode(); $$->typeOfName = *$1; @@ -4716,6 +4810,7 @@ db_alter_clause($alterDatabaseNode) { $alterDatabaseNode->linger = $4; } | DROP LINGER { $alterDatabaseNode->linger = 0; } + // FIXME: Migrate to schemas? | SET DEFAULT sql_security_clause { $alterDatabaseNode->ssDefiner = $3; } | ENABLE PUBLICATION @@ -4972,6 +5067,12 @@ drop_clause node->silentDrop = $3; $$ = node; } + | SCHEMA if_exists_opt symbol_schema_name + { + const auto node = newNode(*$3); + node->silent = $2; + $$ = node; + } ; %type if_exists_opt @@ -5019,18 +5120,18 @@ domain_or_non_array_type_name %type domain_type domain_type - : TYPE OF symbol_column_name + : TYPE OF symbol_domain_name { $$ = newNode(); $$->typeOfName = *$3; } - | TYPE OF COLUMN symbol_column_name '.' symbol_column_name + | TYPE OF COLUMN symbol_domain_name '.' symbol_column_name { $$ = newNode(); - $$->typeOfName = *$6; + $$->typeOfName = QualifiedName(*$6); $$->typeOfTable = *$4; } - | symbol_column_name + | symbol_domain_name { $$ = newNode(); $$->typeOfName = *$1; @@ -5234,7 +5335,7 @@ blob_subtype($field) { $field->subTypeName = *$2; $field->flags |= FLD_has_sub; } ; -%type charset_clause +%type charset_clause charset_clause : /* nothing */ { $$ = NULL; } | CHARACTER SET symbol_character_set_name { $$ = $3; } @@ -5792,6 +5893,28 @@ set_optimize { $$ = newNode(); } ; +%type set_search_path +set_search_path + : SET SEARCH_PATH TO schema_name_list + { $$ = newNode($4); } + ; + +%type schema_name_list +schema_name_list + : symbol_schema_name + { + const auto node = newNode>(); + node->add(*$1); + $$ = node; + } + | schema_name_list ',' symbol_schema_name + { + const auto node = $1; + node->add(*$3); + $$ = node; + } + ; + %type session_statement session_statement : SET SESSION IDLE TIMEOUT long_integer timepart_sesion_idle_tout @@ -5950,17 +6073,17 @@ table_lock | FOR lock_type lock_mode { $$ = $2 | $3; } ; -%type table_list +%type table_list table_list : symbol_table_name { - ObjectsArray* node = newNode >(); + ObjectsArray* node = newNode>(); node->add(*$1); $$ = node; } | table_list ',' symbol_table_name { - ObjectsArray* node = $1; + ObjectsArray* node = $1; node->add(*$3); $$ = node; } @@ -5976,14 +6099,16 @@ set_statistics %type comment comment : COMMENT ON ddl_type0 IS ddl_desc - { $$ = newNode($3, QualifiedName(""), "", *$5); } - | COMMENT ON ddl_type1 symbol_ddl_name IS ddl_desc + { $$ = newNode($3, QualifiedName(), "", *$5); } + | COMMENT ON ddl_type1_schema symbol_ddl_name IS ddl_desc + { $$ = newNode($3, *$4, "", *$6); } + | COMMENT ON ddl_type1_noschema valid_symbol_name IS ddl_desc { $$ = newNode($3, QualifiedName(*$4), "", *$6); } - | COMMENT ON ddl_type2 symbol_ddl_name ddl_subname IS ddl_desc - { $$ = newNode($3, QualifiedName(*$4), *$5, *$7); } - | COMMENT ON ddl_type3 ddl_qualified_name ddl_subname IS ddl_desc - { $$ = newNode($3, *$4, *$5, *$7); } - | COMMENT ON ddl_type4 ddl_qualified_name IS ddl_desc + | COMMENT ON COLUMN symbol_ddl_name '.' valid_symbol_name IS ddl_desc + { $$ = newNode(obj_relation, *$4, *$6, *$8); } + | COMMENT ON ddl_type3 qualified_name '.' valid_symbol_name IS ddl_desc + { $$ = newNode($3, *$4, *$6, *$8); } + | COMMENT ON ddl_type4 qualified_name IS ddl_desc { $$ = newNode($3, *$4, "", *$6); } | comment_on_user { $$ = $1; } @@ -6016,29 +6141,26 @@ ddl_type0 { $$ = obj_database; } ; -%type ddl_type1 -ddl_type1 +%type ddl_type1_schema +ddl_type1_schema : DOMAIN { $$ = obj_field; } | TABLE { $$ = obj_relation; } | VIEW { $$ = obj_view; } | TRIGGER { $$ = obj_trigger; } - | FILTER { $$ = obj_blob_filter; } | EXCEPTION { $$ = obj_exception; } | GENERATOR { $$ = obj_generator; } | SEQUENCE { $$ = obj_generator; } | INDEX { $$ = obj_index; } - | ROLE { $$ = obj_sql_role; } | CHARACTER SET { $$ = obj_charset; } | COLLATION { $$ = obj_collation; } | PACKAGE { $$ = obj_package_header; } - /*** - | SECURITY CLASS { $$ = ddl_sec_class; } - ***/ ; -%type ddl_type2 -ddl_type2 - : COLUMN { $$ = obj_relation; } +%type ddl_type1_noschema +ddl_type1_noschema + : FILTER { $$ = obj_blob_filter; } + | ROLE { $$ = obj_sql_role; } + | SCHEMA { $$ = obj_schema; } ; %type ddl_type3 @@ -6055,15 +6177,14 @@ ddl_type4 | FUNCTION { $$ = obj_udf; } ; -%type ddl_subname -ddl_subname - : '.' symbol_ddl_name { $$ = $2; } - ; - -%type ddl_qualified_name -ddl_qualified_name - : symbol_ddl_name { $$ = newNode(*$1); } - | symbol_ddl_name '.' symbol_ddl_name { $$ = newNode(*$3, *$1); } +%type qualified_name +qualified_name + : valid_symbol_name + { $$ = newNode(*$1); } + | valid_symbol_name '.' valid_symbol_name + { $$ = newNode(*$3, *$1); } + | valid_symbol_name '.' valid_symbol_name '.' valid_symbol_name + { $$ = newNode(*$5, *$1, *$3); } ; %type ddl_desc @@ -6189,7 +6310,7 @@ with_list %type with_item with_item - : symbol_table_alias_name derived_column_list AS '(' select_expr ')' + : valid_symbol_name derived_column_list AS '(' select_expr ')' { $$ = $5; $$->dsqlFlags |= RecordSourceNode::DFLAG_DERIVED; @@ -6428,9 +6549,9 @@ lateral_derived_table %type correlation_name_opt correlation_name_opt - : /* nothing */ { $$ = nullptr; } - | symbol_table_alias_name - | AS symbol_table_alias_name { $$ = $2; } + : /* nothing */ { $$ = nullptr; } + | valid_symbol_name + | AS valid_symbol_name { $$ = $2; } ; %type derived_column_list @@ -6443,7 +6564,7 @@ derived_column_list alias_list : symbol_item_alias_name { - ObjectsArray* node = newNode >(); + ObjectsArray* node = newNode>(); node->add(*$1); $$ = node; } @@ -6523,36 +6644,13 @@ named_columns_join %type table_proc table_proc - : symbol_procedure_name table_proc_inputs as_noise symbol_table_alias_name + : qualified_name table_proc_inputs correlation_name_opt { - const auto node = newNode(QualifiedName(*$1)); + const auto node = newNode(*$1); node->inputSources = $2 ? $2->second : nullptr; node->dsqlInputArgNames = $2 ? $2->first : nullptr; - node->alias = $4->c_str(); - $$ = node; - } - | symbol_procedure_name table_proc_inputs - { - const auto node = newNode(QualifiedName(*$1)); - node->inputSources = $2 ? $2->second : nullptr; - node->dsqlInputArgNames = $2 ? $2->first : nullptr; - $$ = node; - } - | symbol_package_name '.' symbol_procedure_name table_proc_inputs as_noise symbol_table_alias_name - { - const auto node = newNode( - QualifiedName(*$3, *$1)); - node->inputSources = $4 ? $4->second : nullptr; - node->dsqlInputArgNames = $4 ? $4->first : nullptr; - node->alias = $6->c_str(); - $$ = node; - } - | symbol_package_name '.' symbol_procedure_name table_proc_inputs - { - const auto node = newNode( - QualifiedName(*$3, *$1)); - node->inputSources = $4 ? $4->second : nullptr; - node->dsqlInputArgNames = $4 ? $4->first : nullptr; + if ($3) + node->alias = $3->c_str(); $$ = node; } ; @@ -6565,11 +6663,11 @@ table_proc_inputs %type table_name table_name - : simple_table_name - | symbol_table_name as_noise symbol_table_alias_name + : symbol_table_name correlation_name_opt { RelationSourceNode* node = newNode(*$1); - node->alias = $3->c_str(); + if ($2) + node->alias = $2->c_str(); $$ = node; } ; @@ -6706,17 +6804,17 @@ plan_item | plan_expression ; -%type table_or_alias_list +%type table_or_alias_list table_or_alias_list : symbol_table_name { - ObjectsArray* node = newNode >(); + const auto node = newNode>(); node->add(*$1); $$ = node; } | table_or_alias_list symbol_table_name { - ObjectsArray* node = $1; + const auto node = $1; node->add(*$2); $$ = node; } @@ -6969,7 +7067,7 @@ by_target_noise | BY TARGET ; -%type merge_update_specification(, ) +%type merge_update_specification(, ) merge_update_specification($mergeMatchedClause, $relationName) : THEN UPDATE SET update_assignments(NOTRIAL($relationName)) { $mergeMatchedClause->assignments = $4; } @@ -7156,7 +7254,7 @@ assignment } ; -%type update_assignments() +%type update_assignments() update_assignments($relationName) : update_assignment($relationName) { @@ -7170,7 +7268,7 @@ update_assignments($relationName) } ; -%type update_assignment() +%type update_assignment() update_assignment($relationName) : update_column_name '=' value { @@ -7886,6 +7984,8 @@ nonparenthesized_value { $$ = $1; } | current_role { $$ = $1; } + | current_schema + { $$ = $1; } | internal_info { $$ = $1; } | recordKeyType @@ -8113,6 +8213,11 @@ current_role : CURRENT_ROLE { $$ = newNode(); } ; +%type current_schema +current_schema + : CURRENT_SCHEMA { $$ = newNode(); } + ; + %type internal_info internal_info : CURRENT_CONNECTION @@ -8144,18 +8249,18 @@ error_context %type sql_string sql_string : STRING // string in current charset - | INTRODUCER + | INTRODUCER qualified_name [ // feedback for lexer - introducerCharSetName = $1; + introducerCharSetName = $2; ] STRING // string in specific charset [ introducerCharSetName = nullptr; ] { - $$ = $3; - $$->setCharSet(*$1); + $$ = $4; + $$->setCharSet(*$2); - StrMark* mark = strMarks.get($3); + StrMark* mark = strMarks.get($4); if (mark) // hex string is not in strMarks mark->introduced = true; @@ -8889,9 +8994,17 @@ rtrim_function %type udf udf : symbol_UDF_call_name '(' argument_list_opt ')' - { $$ = newNode(QualifiedName(*$1, ""), $3->second, $3->first); } - | symbol_package_name '.' symbol_UDF_name '(' argument_list_opt ')' - { $$ = newNode(QualifiedName(*$3, *$1), $5->second, $5->first); } + { $$ = newNode(*$1, $3->second, $3->first); } + ; + +%type symbol_UDF_call_name +symbol_UDF_call_name + : SYMBOL + { $$ = newNode(*$1); } + | valid_symbol_name '.' valid_symbol_name + { $$ = newNode(*$3, *$1); } + | valid_symbol_name '.' valid_symbol_name '.' valid_symbol_name + { $$ = newNode(*$5, *$1, *$3); } ; %type argument_list_opt @@ -9243,14 +9356,9 @@ null_value // Performs special mapping of keywords into symbols -%type symbol_UDF_call_name -symbol_UDF_call_name - : SYMBOL - ; - -%type symbol_UDF_name +%type symbol_UDF_name symbol_UDF_name - : valid_symbol_name + : schema_opt_qualified_name ; %type symbol_blob_subtype_name @@ -9259,15 +9367,15 @@ symbol_blob_subtype_name | BINARY ; -%type symbol_character_set_name +%type symbol_character_set_name symbol_character_set_name - : valid_symbol_name - | BINARY + : schema_opt_qualified_name + | BINARY { $$ = newNode(*$1, SYSTEM_SCHEMA); } ; -%type symbol_collation_name +%type symbol_collation_name symbol_collation_name - : valid_symbol_name + : schema_opt_qualified_name ; %type symbol_column_name @@ -9285,14 +9393,14 @@ symbol_cursor_name : valid_symbol_name ; -%type symbol_domain_name +%type symbol_domain_name symbol_domain_name - : valid_symbol_name + : schema_opt_qualified_name ; -%type symbol_exception_name +%type symbol_exception_name symbol_exception_name - : valid_symbol_name + : schema_opt_qualified_name ; %type symbol_filter_name @@ -9305,14 +9413,14 @@ symbol_gdscode_name : valid_symbol_name ; -%type symbol_generator_name +%type symbol_generator_name symbol_generator_name - : valid_symbol_name + : schema_opt_qualified_name ; -%type symbol_index_name +%type symbol_index_name symbol_index_name - : valid_symbol_name + : schema_opt_qualified_name ; %type symbol_item_alias_name @@ -9325,14 +9433,14 @@ symbol_label_name : valid_symbol_name ; -%type symbol_ddl_name +%type symbol_ddl_name symbol_ddl_name - : valid_symbol_name + : schema_opt_qualified_name ; -%type symbol_procedure_name +%type symbol_procedure_name symbol_procedure_name - : valid_symbol_name + : schema_opt_qualified_name ; %type symbol_role_name @@ -9340,19 +9448,19 @@ symbol_role_name : valid_symbol_name ; -%type symbol_table_alias_name +%type symbol_table_alias_name symbol_table_alias_name - : valid_symbol_name + : schema_opt_qualified_name ; -%type symbol_table_name +%type symbol_table_name symbol_table_name - : valid_symbol_name + : schema_opt_qualified_name ; -%type symbol_trigger_name +%type symbol_trigger_name symbol_trigger_name - : valid_symbol_name + : schema_opt_qualified_name ; %type symbol_user_name @@ -9365,9 +9473,9 @@ symbol_variable_name : valid_symbol_name ; -%type symbol_view_name +%type symbol_view_name symbol_view_name - : valid_symbol_name + : schema_opt_qualified_name ; %type symbol_savepoint_name @@ -9375,8 +9483,13 @@ symbol_savepoint_name : valid_symbol_name ; -%type symbol_package_name +%type symbol_package_name symbol_package_name + : schema_opt_qualified_name + ; + +%type symbol_schema_name +symbol_schema_name : valid_symbol_name ; @@ -9387,6 +9500,12 @@ symbol_window_name // symbols +%type schema_opt_qualified_name +schema_opt_qualified_name + : valid_symbol_name { $$ = newNode(*$1); } + | valid_symbol_name '.' valid_symbol_name { $$ = newNode(*$3, *$1); } + ; + %type valid_symbol_name valid_symbol_name : SYMBOL @@ -9690,6 +9809,8 @@ non_reserved_word | ANY_VALUE | FORMAT | OWNER + | SEARCH_PATH + | SCHEMA ; %% diff --git a/src/dsql/pass1.cpp b/src/dsql/pass1.cpp index ac7812eb4d..2bf6b02019 100644 --- a/src/dsql/pass1.cpp +++ b/src/dsql/pass1.cpp @@ -1,3 +1,26 @@ +/* FIXME: quote vs no quote in plans: +create schema s1; +create schema s2; +create table s1.t1 (n1 integer); +create table s2.t2 (n2 integer); +insert into s1.t1 values (1); +insert into s2.t2 values (2); +commit; + +set planonly; +select * from s1.t1, s2.t2; + +PLAN JOIN (T1 NATURAL, T2 NATURAL) + +select * from s1.t1 a, s1.t1 b; + +PLAN JOIN ("A" NATURAL, "B" NATURAL) +*/ + +/* FIXME: explained plan: +Table ""S1"."T1"" as ""X"" Full Scan +*/ + /* * PROGRAM: Dynamic SQL runtime support * MODULE: pass1.cpp @@ -139,6 +162,7 @@ */ #include "firebird.h" +#include #include #include #include "ibase.h" @@ -165,6 +189,7 @@ #include "../common/dsc_proto.h" #include "../jrd/intl_proto.h" #include "../jrd/jrd_proto.h" +#include "../jrd/met_proto.h" #include "../yvalve/why_proto.h" #include "../jrd/SysFunction.h" #include "../common/classes/array.h" @@ -177,7 +202,6 @@ using namespace Jrd; using namespace Firebird; -static string pass1_alias_concat(const string&, const string&); static ValueListNode* pass1_group_by_list(DsqlCompilerScratch*, ValueListNode*, ValueListNode*); static ValueExprNode* pass1_make_derived_field(thread_db*, DsqlCompilerScratch*, ValueExprNode*); static RseNode* pass1_rse(DsqlCompilerScratch*, RecordSourceNode*, ValueListNode*, RowsClause*, bool, bool, USHORT); @@ -346,84 +370,117 @@ dsql_ctx* PASS1_make_context(DsqlCompilerScratch* dsqlScratch, RecordSourceNode* thread_db* const tdbb = JRD_get_thread_data(); - dsql_rel* relation = NULL; - dsql_prc* procedure = NULL; - // figure out whether this is a relation or a procedure // and give an error if it is neither - MetaName relation_name; + QualifiedName name; ProcedureSourceNode* procNode = NULL; RelationSourceNode* relNode = NULL; SelectExprNode* selNode = NULL; if ((procNode = nodeAs(relationNode))) - relation_name = procNode->dsqlName.identifier; + name = procNode->dsqlName; else if ((relNode = nodeAs(relationNode))) - relation_name = relNode->dsqlName; + name = relNode->dsqlName; //// TODO: LocalTableSourceNode else if ((selNode = nodeAs(relationNode))) - relation_name = selNode->alias.c_str(); + name.object = selNode->alias; SelectExprNode* cte = NULL; + dsql_rel* relation = NULL; + dsql_prc* procedure = NULL; if (selNode) { // No processing needed here for derived tables. } - else if (procNode && (procNode->dsqlName.package.hasData() || procNode->inputSources)) + else if (!((procNode && procNode->inputSources) || name.schema.hasData() || name.package.hasData()) && + (cte = dsqlScratch->findCTE(name.object))) { - if (procNode->dsqlName.package.isEmpty()) - { - const auto subProcedure = dsqlScratch->getSubProcedure(procNode->dsqlName.identifier); - procedure = subProcedure ? subProcedure->dsqlProcedure : NULL; - } - - if (!procedure) - procedure = METD_get_procedure(dsqlScratch->getTransaction(), dsqlScratch, procNode->dsqlName); - - if (!procedure) - { - ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) << - Arg::Gds(isc_dsql_procedure_err) << - Arg::Gds(isc_random) << - Arg::Str(procNode->dsqlName.toString()) << - Arg::Gds(isc_dsql_line_col_error) << Arg::Num(relationNode->line) << - Arg::Num(relationNode->column)); - } - } - else if ((cte = dsqlScratch->findCTE(relation_name))) relationNode = cte; + } else { - if (procNode && procNode->dsqlName.package.isEmpty()) + auto qualifiedName = name; + + if (name.package.isEmpty()) { - const auto subProcedure = dsqlScratch->getSubProcedure(procNode->dsqlName.identifier); - procedure = subProcedure ? subProcedure->dsqlProcedure : NULL; + if (name.schema.isEmpty()) + { + if (const auto subProcedure = dsqlScratch->getSubProcedure(name.object)) + procedure = subProcedure->dsqlProcedure; + else if (dsqlScratch->package.object.hasData()) + { + const QualifiedName packagedName(name.object, + dsqlScratch->package.schema, dsqlScratch->package.object); + + if ((procedure = METD_get_procedure(dsqlScratch->getTransaction(), dsqlScratch, packagedName))) + qualifiedName = packagedName; + } + + if (!procedure) + dsqlScratch->qualifyExistingName(qualifiedName, obj_procedure); + } + else + { + QualifiedName packageName(name.schema); + dsqlScratch->qualifyExistingName(packageName, obj_package_header); + + if (MET_check_package_exists(tdbb, packageName)) + { + qualifiedName.schema = packageName.schema; + qualifiedName.package = packageName.object; + } + } } if (!procedure) - relation = METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch, relation_name); + procedure = METD_get_procedure(dsqlScratch->getTransaction(), dsqlScratch, qualifiedName); - if (!relation && !procedure && procNode) - procedure = METD_get_procedure(dsqlScratch->getTransaction(), dsqlScratch, procNode->dsqlName); - - if (!relation && !procedure) + if (!procedure && !(name.package.hasData() || (procNode && procNode->inputSources))) { - ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) << - Arg::Gds(isc_dsql_relation_err) << - Arg::Gds(isc_random) << Arg::Str(relation_name) << - Arg::Gds(isc_dsql_line_col_error) << Arg::Num(relationNode->line) << - Arg::Num(relationNode->column)); + qualifiedName = name; + dsqlScratch->qualifyExistingName(qualifiedName, obj_relation); + relation = METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch, qualifiedName); } - } - if (procedure && !procedure->prc_out_count) - { - ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-84) << - Arg::Gds(isc_dsql_procedure_use_err) << Arg::Str(procedure->prc_name.toString()) << - Arg::Gds(isc_dsql_line_col_error) << Arg::Num(relationNode->line) << - Arg::Num(relationNode->column)); + if (!procedure && !relation) + { + const auto errorCode = name.package.hasData() || (procNode && procNode->inputSources) ? + isc_dsql_procedure_err : isc_dsql_relation_err; + + ERRD_post( + Arg::Gds(isc_sqlerr) << Arg::Num(-204) << + Arg::Gds(errorCode) << + Arg::Gds(isc_random) << name.toQuotedString() << + Arg::Gds(isc_dsql_line_col_error) << Arg::Num(relationNode->line) << Arg::Num(relationNode->column)); + } + + name = qualifiedName; + + if (procedure) + { + if (procedure->prc_private && name.getSchemaAndPackage() != dsqlScratch->package) + { + status_exception::raise( + Arg::Gds(isc_private_procedure) << + name.object << + name.getSchemaAndPackage().toQuotedString()); + } + + if (!procedure->prc_out_count) + { + ERRD_post( + Arg::Gds(isc_sqlerr) << Arg::Num(-84) << + Arg::Gds(isc_dsql_procedure_use_err) << name.toQuotedString() << + Arg::Gds(isc_dsql_line_col_error) << + Arg::Num(relationNode->line) << Arg::Num(relationNode->column)); + } + + procNode->dsqlName = name; + } + else if (relNode) + relNode->dsqlName = name; } // Set up context block. @@ -469,20 +526,16 @@ dsql_ctx* PASS1_make_context(DsqlCompilerScratch* dsqlScratch, RecordSourceNode* } if (str.hasData()) - context->ctx_internal_alias = str; + context->ctx_internal_alias = QualifiedName(str); if (dsqlScratch->aliasRelationPrefix.hasData() && !selNode) - { - if (str.hasData()) - str = pass1_alias_concat(dsqlScratch->aliasRelationPrefix, str); - else - str = pass1_alias_concat(dsqlScratch->aliasRelationPrefix, relation_name.c_str()); - } + context->ctx_alias = dsqlScratch->aliasRelationPrefix; if (str.hasData()) - { - context->ctx_alias = str; + context->ctx_alias.push(QualifiedName(str)); + if (context->ctx_alias.hasData()) + { // check to make sure the context is not already used at this same // query level (if there are no subqueries, this checks that the // alias is not used twice in the dsqlScratch). @@ -493,34 +546,45 @@ dsql_ctx* PASS1_make_context(DsqlCompilerScratch* dsqlScratch, RecordSourceNode* if (conflict->ctx_scope_level != context->ctx_scope_level) continue; - const TEXT* conflict_name; + ObjectsArray conflictNames; ISC_STATUS error_code; if (conflict->ctx_alias.hasData()) { - conflict_name = conflict->ctx_alias.c_str(); + conflictNames = conflict->ctx_alias; error_code = isc_alias_conflict_err; // alias %s conflicts with an alias in the same dsqlScratch. } else if (conflict->ctx_procedure) { - conflict_name = conflict->ctx_procedure->prc_name.identifier.c_str(); + conflictNames.add(conflict->ctx_procedure->prc_name); error_code = isc_procedure_conflict_error; // alias %s conflicts with a procedure in the same dsqlScratch. } else if (conflict->ctx_relation) { - conflict_name = conflict->ctx_relation->rel_name.c_str(); + conflictNames.add(conflict->ctx_relation->rel_name); error_code = isc_relation_conflict_err; // alias %s conflicts with a relation in the same dsqlScratch. } else continue; - if (context->ctx_alias == conflict_name) + if (PASS1_compare_alias(context->ctx_alias, conflictNames)) { + fb_assert(conflictNames.hasData()); + + const auto conflictStr = std::accumulate( + std::next(conflictNames.begin()), + conflictNames.end(), + conflictNames[0].toQuotedString(), + [](const auto& a, const auto& b) { + return a + " " + b.toQuotedString(); + } + ); + ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) << - Arg::Gds(error_code) << Arg::Str(conflict_name)); + Arg::Gds(error_code) << conflictStr); } } } @@ -529,7 +593,7 @@ dsql_ctx* PASS1_make_context(DsqlCompilerScratch* dsqlScratch, RecordSourceNode* { USHORT count = 0; - if (procNode->inputSources) + if (procNode && procNode->inputSources) { context->ctx_proc_inputs = Node::doDsqlPass(dsqlScratch, procNode->inputSources, false); count = context->ctx_proc_inputs->items.getCount(); @@ -538,7 +602,7 @@ dsql_ctx* PASS1_make_context(DsqlCompilerScratch* dsqlScratch, RecordSourceNode* if (count > procedure->prc_in_count || count < procedure->prc_in_count - procedure->prc_def_count) { - ERRD_post(Arg::Gds(isc_prcmismat) << procNode->dsqlName.toString()); + ERRD_post(Arg::Gds(isc_prcmismat) << procNode->dsqlName.toQuotedString()); } if (count) @@ -595,7 +659,7 @@ dsql_ctx* PASS1_make_context(DsqlCompilerScratch* dsqlScratch, RecordSourceNode* } if (mismatchStatus.hasData()) - status_exception::raise(Arg::Gds(isc_prcmismat) << procNode->dsqlName.toString() << mismatchStatus); + status_exception::raise(Arg::Gds(isc_prcmismat) << procNode->dsqlName.toQuotedString() << mismatchStatus); } } } @@ -641,70 +705,89 @@ void PASS1_ambiguity_check(DsqlCompilerScratch* dsqlScratch, if (ambiguous_contexts.getCount() < 2) return; - TEXT buffer[1024]; - USHORT loop = 0; - - buffer[0] = 0; - TEXT* b = buffer; - TEXT* p = NULL; + string buffers[2]; + string* bufferPtr = &buffers[0]; for (DsqlContextStack::const_iterator stack(ambiguous_contexts); stack.hasData(); ++stack) { + string& buffer = *bufferPtr; const dsql_ctx* context = stack.object(); const dsql_rel* relation = context->ctx_relation; const dsql_prc* procedure = context->ctx_procedure; - if (strlen(b) > (sizeof(buffer) - 50)) - { - // Buffer full - break; - } + // if this is the second loop add "and " before relation. - if (++loop > 2) - strcat(buffer, "and "); + if (buffer.hasData()) + buffer += " and "; + // Process relation when present. if (relation) { if (!(relation->rel_flags & REL_view)) - strcat(buffer, "table "); + buffer += "table "; else - strcat(buffer, "view "); - strcat(buffer, relation->rel_name.c_str()); + buffer += "view "; + + buffer += relation->rel_name.toQuotedString(); } else if (procedure) { // Process procedure when present. - strcat(b, "procedure "); - strcat(b, procedure->prc_name.toString().c_str()); + buffer += "procedure "; + buffer += procedure->prc_name.toQuotedString(); } else { - // When there's no relation and no procedure it's a derived table. - strcat(b, "derived table "); - if (context->ctx_alias.hasData()) - strcat(b, context->ctx_alias.c_str()); - } - strcat(buffer, " "); - if (!p) - p = b + strlen(b); - } + const auto contextAliases = context->getConcatenatedAlias(); - if (p) - *--p = 0; + // When there's no relation and no procedure it's a derived table. + buffer += "derived table "; + if (context->ctx_alias.hasData()) + buffer += contextAliases; + } + + if (bufferPtr == &buffers[0]) + ++bufferPtr; + } if (dsqlScratch->clientDialect >= SQL_DIALECT_V6) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) << - Arg::Gds(isc_dsql_ambiguous_field_name) << Arg::Str(buffer) << Arg::Str(++p) << + Arg::Gds(isc_dsql_ambiguous_field_name) << buffers[0] << buffers[1] << Arg::Gds(isc_random) << name); } ERRD_post_warning(Arg::Warning(isc_sqlwarn) << Arg::Num(204) << - Arg::Warning(isc_dsql_ambiguous_field_name) << Arg::Str(buffer) << - Arg::Str(++p) << + Arg::Warning(isc_dsql_ambiguous_field_name) << buffers[0] << buffers[1] << Arg::Warning(isc_random) << name); } +bool PASS1_compare_alias(const QualifiedName& contextAlias, const QualifiedName& lookupAlias) +{ + return lookupAlias == contextAlias || lookupAlias.schema.isEmpty() && lookupAlias.object == contextAlias.object; +} + + +bool PASS1_compare_alias(const ObjectsArray& contextAlias, + const ObjectsArray& lookupAlias) +{ + if (contextAlias.getCount() != lookupAlias.getCount()) + return false; + + auto contextAliasIt = contextAlias.begin(); + + for (const auto& lookupAliasIt : lookupAlias) + { + if (!PASS1_compare_alias(*contextAliasIt, lookupAliasIt)) + return false; + + ++contextAliasIt; + } + + return true; +} + + // Compose two booleans. BoolExprNode* PASS1_compose(BoolExprNode* expr1, BoolExprNode* expr2, UCHAR blrOp) { @@ -727,13 +810,12 @@ BoolExprNode* PASS1_compose(BoolExprNode* expr1, BoolExprNode* expr2, UCHAR blrO void PASS1_field_unknown(const TEXT* qualifier_name, const TEXT* field_name, const ExprNode* flawed_node) { - TEXT field_buffer[MAX_SQL_IDENTIFIER_SIZE * 2]; + string buffer; if (qualifier_name) { - sprintf(field_buffer, "%.*s.%.*s", (int) MAX_SQL_IDENTIFIER_LEN, qualifier_name, - (int) MAX_SQL_IDENTIFIER_LEN, field_name ? field_name : "*"); - field_name = field_buffer; + buffer.printf("%s.%s", qualifier_name, (field_name ? field_name : "*")); + field_name = buffer.c_str(); } if (flawed_node) @@ -941,13 +1023,13 @@ DeclareCursorNode* PASS1_cursor_name(DsqlCompilerScratch* dsqlScratch, const Met { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-504) << Arg::Gds(isc_dsql_cursor_err) << - Arg::Gds(isc_dsql_cursor_not_found) << name); + Arg::Gds(isc_dsql_cursor_not_found) << name.toQuotedString()); } else if (cursor && !existence_flag) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-502) << Arg::Gds(isc_dsql_decl_err) << - Arg::Gds(isc_dsql_cursor_exists) << name); + Arg::Gds(isc_dsql_cursor_exists) << name.toQuotedString()); } return cursor; @@ -983,14 +1065,14 @@ RseNode* PASS1_derived_table(DsqlCompilerScratch* dsqlScratch, SelectExprNode* i thread_db* tdbb = JRD_get_thread_data(); MemoryPool& pool = *tdbb->getDefaultPool(); - const string& alias = input->alias; + const auto& alias = input->alias; // Create the context now, because we need to know it for the tables inside. dsql_ctx* const context = PASS1_make_context(dsqlScratch, input); // Save some values to restore after rse process. DsqlContextStack* const req_base = dsqlScratch->context; - const string aliasRelationPrefix = dsqlScratch->aliasRelationPrefix; + const auto aliasRelationPrefix = dsqlScratch->aliasRelationPrefix; // Change context, because the derived table cannot reference other streams // at the same scope_level (unless this is a lateral derived table). @@ -1014,7 +1096,9 @@ RseNode* PASS1_derived_table(DsqlCompilerScratch* dsqlScratch, SelectExprNode* i baseContext = temp.object(); dsqlScratch->context = &temp; - dsqlScratch->aliasRelationPrefix = pass1_alias_concat(aliasRelationPrefix, alias); + + if (alias.hasData()) + dsqlScratch->aliasRelationPrefix.add(QualifiedName(alias)); RecordSourceNode* query = input->querySpec; UnionSourceNode* unionQuery = nodeAs(query); @@ -1101,20 +1185,10 @@ RseNode* PASS1_derived_table(DsqlCompilerScratch* dsqlScratch, SelectExprNode* i // CVC: prepare a truncated alias for the derived table here // because we need it several times. - TEXT aliasbuffer[100] = ""; - const TEXT* aliasname = aliasbuffer; + string aliasname; + if (alias.hasData()) - { - int length = alias.length(); - if (length > 99) - { - length = 99; - memcpy(aliasbuffer, alias.c_str(), length); - aliasbuffer[length] = 0; - } - else - aliasname = alias.c_str(); - } + aliasname = alias; else aliasname = ""; @@ -1236,7 +1310,7 @@ RseNode* PASS1_derived_table(DsqlCompilerScratch* dsqlScratch, SelectExprNode* i const string* const saveCteAlias = dsqlScratch->currCteAlias ? *dsqlScratch->currCteAlias : NULL; - dsqlScratch->resetCTEAlias(alias); + dsqlScratch->resetCTEAlias(alias.c_str()); rse = PASS1_rse(dsqlScratch, input, select); @@ -1260,7 +1334,10 @@ RseNode* PASS1_derived_table(DsqlCompilerScratch* dsqlScratch, SelectExprNode* i context->ctx_rse = rse; if (cte_alias) - context->ctx_alias = cte_alias; + { + context->ctx_alias.clear(); + context->ctx_alias.push(QualifiedName(cte_alias)); + } dsqlScratch->context = req_base; @@ -1481,7 +1558,7 @@ static ValueListNode* pass1_group_by_list(DsqlCompilerScratch* dsqlScratch, Valu if ((field = nodeAs(sub))) { // check for alias or field node - if (selectList && field->dsqlQualifier.isEmpty() && field->dsqlName.hasData()) + if (selectList && field->dsqlQualifier.object.isEmpty() && field->dsqlName.hasData()) { // AB: Check first against the select list for matching column. // When no matches at all are found we go on with our @@ -1735,31 +1812,11 @@ RecordSourceNode* PASS1_relation(DsqlCompilerScratch* dsqlScratch, RecordSourceN } -// Concatenate 2 input strings together for a new alias string -// Note: Both input params can be empty. -static string pass1_alias_concat(const string& input1, const string& input2) -{ - string output; - - if (input1.hasData()) - output.append(input1); - - if (input2.hasData()) - { - if (output.hasData()) - output.append(" "); - output.append(input2); - } - - return output; -} - - // Wrapper for pass1_rse_impl. Substitute recursive CTE alias (if needed) and call pass1_rse_impl. static RseNode* pass1_rse(DsqlCompilerScratch* dsqlScratch, RecordSourceNode* input, ValueListNode* order, RowsClause* rows, bool updateLock, bool skipLocked, USHORT flags) { - string save_alias; + ObjectsArray save_alias; RseNode* rseNode = nodeAs(input); const bool isRecursive = rseNode && (rseNode->dsqlFlags & RecordSourceNode::DFLAG_RECURSIVE); AutoSetRestore autoScopeLevel(&dsqlScratch->scopeLevel, dsqlScratch->scopeLevel); @@ -1769,7 +1826,8 @@ static RseNode* pass1_rse(DsqlCompilerScratch* dsqlScratch, RecordSourceNode* in fb_assert(dsqlScratch->recursiveCtx); save_alias = dsqlScratch->recursiveCtx->ctx_alias; - dsqlScratch->recursiveCtx->ctx_alias = *dsqlScratch->getNextCTEAlias(); + dsqlScratch->recursiveCtx->ctx_alias.clear(); + dsqlScratch->recursiveCtx->ctx_alias.add(QualifiedName(*dsqlScratch->getNextCTEAlias())); // ASF: We need to reset the scope level to the same value found in the non-recursive // part of the query, to verify usage of aggregate functions correctly. See CORE-4322. @@ -2373,7 +2431,7 @@ ValueListNode* PASS1_sort(DsqlCompilerScratch* dsqlScratch, ValueListNode* input ValueExprNode* aliasNode = NULL; // check for alias or field node - if (selectList && field->dsqlQualifier.isEmpty() && field->dsqlName.hasData()) + if (selectList && field->dsqlQualifier.object.isEmpty() && field->dsqlName.hasData()) { // AB: Check first against the select list for matching column. // When no matches at all are found we go on with our @@ -2608,9 +2666,9 @@ static RseNode* pass1_union(DsqlCompilerScratch* dsqlScratch, UnionSourceNode* i ptr != end; ++ptr, ++uptr) { - OrderNode* order1 = nodeAs(*ptr); - const ValueExprNode* position = order1->value; - const CollateNode* collateNode = nodeAs(position); + const auto order1 = nodeAs(*ptr); + auto position = order1->value; + const auto collateNode = nodeAs(position); if (collateNode) position = collateNode->arg; diff --git a/src/dsql/pass1_proto.h b/src/dsql/pass1_proto.h index 361e5ccaae..4eb7e99fe5 100644 --- a/src/dsql/pass1_proto.h +++ b/src/dsql/pass1_proto.h @@ -39,6 +39,9 @@ namespace Jrd } void PASS1_ambiguity_check(Jrd::DsqlCompilerScratch*, const Jrd::MetaName&, const Jrd::DsqlContextStack&); +bool PASS1_compare_alias(const Jrd::QualifiedName& contextAlias, const Jrd::QualifiedName& lookupAlias); +bool PASS1_compare_alias(const Firebird::ObjectsArray& contextAlias, + const Firebird::ObjectsArray& lookupAlias); Jrd::BoolExprNode* PASS1_compose(Jrd::BoolExprNode*, Jrd::BoolExprNode*, UCHAR); Jrd::DeclareCursorNode* PASS1_cursor_name(Jrd::DsqlCompilerScratch*, const Jrd::MetaName&, USHORT, bool); Jrd::RseNode* PASS1_derived_table(Jrd::DsqlCompilerScratch*, Jrd::SelectExprNode*, const char*, diff --git a/src/gpre/sql.cpp b/src/gpre/sql.cpp index 5f73dc7eba..fe818ac228 100644 --- a/src/gpre/sql.cpp +++ b/src/gpre/sql.cpp @@ -816,7 +816,7 @@ void SQL_par_field_dtype(gpre_req* request, gpre_fld* field, bool is_udf) if (field->fld_flags & FLD_national) { - gpre_sym* symbol = MSC_find_symbol(HSH_lookup(DEFAULT_CHARACTER_SET_NAME), SYM_charset); + gpre_sym* symbol = MSC_find_symbol(HSH_lookup(NATIONAL_CHARACTER_SET), SYM_charset); if (!symbol) { PAR_error("NATIONAL character set missing"); diff --git a/src/gpre/std/gpre_meta.epp b/src/gpre/std/gpre_meta.epp index 52586c5999..b9749b4222 100644 --- a/src/gpre/std/gpre_meta.epp +++ b/src/gpre/std/gpre_meta.epp @@ -173,6 +173,8 @@ bool MET_database(gpre_dbb* database, bool print_version) } #endif + dpb.insertString(isc_dpb_search_path, SYSTEM_SCHEMA, fb_strlen(SYSTEM_SCHEMA)); + if (isc_attach_database(gds_status, 0, database->dbb_filename, &DB, dpb.getBufferLength(), reinterpret_cast(dpb.getBuffer()))) diff --git a/src/include/firebird/FirebirdInterface.idl b/src/include/firebird/FirebirdInterface.idl index 8a0a1ad2c1..2c2c0e761b 100644 --- a/src/include/firebird/FirebirdInterface.idl +++ b/src/include/firebird/FirebirdInterface.idl @@ -408,6 +408,9 @@ interface MessageMetadata : ReferenceCounted version: // 3.0 => 4.0 uint getAlignment(Status status); uint getAlignedLength(Status status); + +version: // 5.0 => 6.0 Alpha1 + const string getSchema(Status status, uint index); } interface MetadataBuilder : ReferenceCounted @@ -430,6 +433,9 @@ version: // 3.0 => 4.0 void setRelation(Status status, uint index, const string relation); void setOwner(Status status, uint index, const string owner); void setAlias(Status status, uint index, const string alias); + +version: // 5.0 => 6.0 Alpha1 + void setSchema(Status status, uint index, const string schema); } interface ResultSet : ReferenceCounted @@ -1132,6 +1138,9 @@ interface RoutineMetadata : Versioned MessageMetadata getTriggerMetadata(Status status) const; const string getTriggerTable(Status status) const; uint getTriggerType(Status status) const; + +version: // 5.0 => 6.0 Alpha1 + const string getSchema(Status status) const; } @@ -1228,6 +1237,12 @@ version: // 4.0 Beta1 => 4.0 Beta2 uint* fractions, uint timeZoneBufferLength, string timeZoneBuffer); void decodeTimeStampTzEx(Status status, const ISC_TIMESTAMP_TZ_EX* timeStampTz, uint* year, uint* month, uint* day, uint* hours, uint* minutes, uint* seconds, uint* fractions, uint timeZoneBufferLength, string timeZoneBuffer); + +version: // 5.0 => 6.0 Alpha1 + Attachment executeCreateDatabase2(Status status, + uint stmtLength, const string creatDBstatement, uint dialect, + uint dpbLength, const uchar* dpb, + boolean* stmtIsCreateDb); } interface OffsetsCallback : Versioned @@ -1742,16 +1757,24 @@ interface ReplicatedTransaction : Disposable void rollbackSavepoint(Status status); // ReplicatedRecords parameters point to local objects, do not ever store the pointer. - void insertRecord(Status status, const string name, - ReplicatedRecord record); - void updateRecord(Status status, const string name, - ReplicatedRecord orgRecord, - ReplicatedRecord newRecord); - void deleteRecord(Status status, const string name, - ReplicatedRecord record); + void deprecatedInsertRecord(Status status, const string name, ReplicatedRecord record); + void deprecatedUpdateRecord(Status status, const string name, + ReplicatedRecord orgRecord, ReplicatedRecord newRecord); + void deprecatedDeleteRecord(Status status, const string name, ReplicatedRecord record); - void executeSql(Status status, const string sql); - void executeSqlIntl(Status status, uint charset, const string sql); + void deprecatedExecuteSql(Status status, const string sql); + void deprecatedExecuteSqlIntl(Status status, uint charset, const string sql); + +version: // 5.0 => 6.0 Alpha1 + // ReplicatedRecords parameters point to local objects, do not ever store the pointer. + void insertRecord2(Status status, const string schemaName, const string tableName, + ReplicatedRecord record); + void updateRecord2(Status status, const string schemaName, const string tableName, + ReplicatedRecord orgRecord, ReplicatedRecord newRecord); + void deleteRecord2(Status status, const string schemaName, const string tableName, + ReplicatedRecord record); + + void executeSqlIntl2(Status status, uint charset, const string schemaSearchPath, const string sql); } interface ReplicatedSession : PluginBase @@ -1761,7 +1784,10 @@ interface ReplicatedSession : PluginBase ReplicatedTransaction startTransaction(Status status, Transaction transaction, int64 number); void cleanupTransaction(Status status, int64 number); - void setSequence(Status status, const string name, int64 value); + void deprecatedSetSequence(Status status, const string name, int64 value); + +version: // 5.0 => 6.0 Alpha1 + void setSequence2(Status status, const string schemaName, const string genName, int64 value); } // Profiler interfaces @@ -1789,7 +1815,7 @@ interface ProfilerSession : Disposable void finish(Status status, ISC_TIMESTAMP_TZ timestamp); - void defineStatement(Status status, int64 statementId, int64 parentStatementId, + void deprecatedDefineStatement(Status status, int64 statementId, int64 parentStatementId, const string type, const string packageName, const string routineName, const string sqlText); void defineCursor(int64 statementId, uint cursorId, const string name, uint line, uint column); @@ -1813,6 +1839,13 @@ interface ProfilerSession : Disposable void beforeRecordSourceGetRecord(int64 statementId, int64 requestId, uint cursorId, uint recSourceId); void afterRecordSourceGetRecord(int64 statementId, int64 requestId, uint cursorId, uint recSourceId, ProfilerStats stats); + +version: // 5.0 => 6.0 Alpha1 + [notImplementedAction call deprecatedDefineStatement(status, statementId, parentStatementId, + type, packageName, routineName, sqlText)] + void defineStatement2(Status status, int64 statementId, int64 parentStatementId, + const string type, const string schemaName, const string packageName, const string routineName, + const string sqlText); } interface ProfilerStats : Versioned diff --git a/src/include/firebird/IdlFbInterfaces.h b/src/include/firebird/IdlFbInterfaces.h index 11e294944e..1d4d7da92f 100644 --- a/src/include/firebird/IdlFbInterfaces.h +++ b/src/include/firebird/IdlFbInterfaces.h @@ -1365,7 +1365,7 @@ namespace Firebird } }; -#define FIREBIRD_IMESSAGE_METADATA_VERSION 4u +#define FIREBIRD_IMESSAGE_METADATA_VERSION 5u class IMessageMetadata : public IReferenceCounted { @@ -1389,6 +1389,7 @@ namespace Firebird unsigned (CLOOP_CARG *getMessageLength)(IMessageMetadata* self, IStatus* status) CLOOP_NOEXCEPT; unsigned (CLOOP_CARG *getAlignment)(IMessageMetadata* self, IStatus* status) CLOOP_NOEXCEPT; unsigned (CLOOP_CARG *getAlignedLength)(IMessageMetadata* self, IStatus* status) CLOOP_NOEXCEPT; + const char* (CLOOP_CARG *getSchema)(IMessageMetadata* self, IStatus* status, unsigned index) CLOOP_NOEXCEPT; }; protected: @@ -1551,9 +1552,23 @@ namespace Firebird StatusType::checkException(status); return ret; } + + template const char* getSchema(StatusType* status, unsigned index) + { + if (cloopVTable->version < 5) + { + StatusType::setVersionError(status, "IMessageMetadata", cloopVTable->version, 5); + StatusType::checkException(status); + return 0; + } + StatusType::clearException(status); + const char* ret = static_cast(this->cloopVTable)->getSchema(this, status, index); + StatusType::checkException(status); + return ret; + } }; -#define FIREBIRD_IMETADATA_BUILDER_VERSION 4u +#define FIREBIRD_IMETADATA_BUILDER_VERSION 5u class IMetadataBuilder : public IReferenceCounted { @@ -1574,6 +1589,7 @@ namespace Firebird void (CLOOP_CARG *setRelation)(IMetadataBuilder* self, IStatus* status, unsigned index, const char* relation) CLOOP_NOEXCEPT; void (CLOOP_CARG *setOwner)(IMetadataBuilder* self, IStatus* status, unsigned index, const char* owner) CLOOP_NOEXCEPT; void (CLOOP_CARG *setAlias)(IMetadataBuilder* self, IStatus* status, unsigned index, const char* alias) CLOOP_NOEXCEPT; + void (CLOOP_CARG *setSchema)(IMetadataBuilder* self, IStatus* status, unsigned index, const char* schema) CLOOP_NOEXCEPT; }; protected: @@ -1712,6 +1728,19 @@ namespace Firebird static_cast(this->cloopVTable)->setAlias(this, status, index, alias); StatusType::checkException(status); } + + template void setSchema(StatusType* status, unsigned index, const char* schema) + { + if (cloopVTable->version < 5) + { + StatusType::setVersionError(status, "IMetadataBuilder", cloopVTable->version, 5); + StatusType::checkException(status); + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->setSchema(this, status, index, schema); + StatusType::checkException(status); + } }; #define FIREBIRD_IRESULT_SET_VERSION 5u @@ -4376,7 +4405,7 @@ namespace Firebird } }; -#define FIREBIRD_IROUTINE_METADATA_VERSION 2u +#define FIREBIRD_IROUTINE_METADATA_VERSION 3u class IRoutineMetadata : public IVersioned { @@ -4392,6 +4421,7 @@ namespace Firebird IMessageMetadata* (CLOOP_CARG *getTriggerMetadata)(const IRoutineMetadata* self, IStatus* status) CLOOP_NOEXCEPT; const char* (CLOOP_CARG *getTriggerTable)(const IRoutineMetadata* self, IStatus* status) CLOOP_NOEXCEPT; unsigned (CLOOP_CARG *getTriggerType)(const IRoutineMetadata* self, IStatus* status) CLOOP_NOEXCEPT; + const char* (CLOOP_CARG *getSchema)(const IRoutineMetadata* self, IStatus* status) CLOOP_NOEXCEPT; }; protected: @@ -4478,6 +4508,20 @@ namespace Firebird StatusType::checkException(status); return ret; } + + template const char* getSchema(StatusType* status) const + { + if (cloopVTable->version < 3) + { + StatusType::setVersionError(status, "IRoutineMetadata", cloopVTable->version, 3); + StatusType::checkException(status); + return 0; + } + StatusType::clearException(status); + const char* ret = static_cast(this->cloopVTable)->getSchema(this, status); + StatusType::checkException(status); + return ret; + } }; #define FIREBIRD_IEXTERNAL_ENGINE_VERSION 4u @@ -4653,7 +4697,7 @@ namespace Firebird } }; -#define FIREBIRD_IUTIL_VERSION 4u +#define FIREBIRD_IUTIL_VERSION 5u class IUtil : public IVersioned { @@ -4682,6 +4726,7 @@ namespace Firebird IInt128* (CLOOP_CARG *getInt128)(IUtil* self, IStatus* status) CLOOP_NOEXCEPT; void (CLOOP_CARG *decodeTimeTzEx)(IUtil* self, IStatus* status, const ISC_TIME_TZ_EX* timeTz, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer) CLOOP_NOEXCEPT; void (CLOOP_CARG *decodeTimeStampTzEx)(IUtil* self, IStatus* status, const ISC_TIMESTAMP_TZ_EX* timeStampTz, unsigned* year, unsigned* month, unsigned* day, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer) CLOOP_NOEXCEPT; + IAttachment* (CLOOP_CARG *executeCreateDatabase2)(IUtil* self, IStatus* status, unsigned stmtLength, const char* creatDBstatement, unsigned dialect, unsigned dpbLength, const unsigned char* dpb, FB_BOOLEAN* stmtIsCreateDb) CLOOP_NOEXCEPT; }; protected: @@ -4902,6 +4947,20 @@ namespace Firebird static_cast(this->cloopVTable)->decodeTimeStampTzEx(this, status, timeStampTz, year, month, day, hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer); StatusType::checkException(status); } + + template IAttachment* executeCreateDatabase2(StatusType* status, unsigned stmtLength, const char* creatDBstatement, unsigned dialect, unsigned dpbLength, const unsigned char* dpb, FB_BOOLEAN* stmtIsCreateDb) + { + if (cloopVTable->version < 5) + { + StatusType::setVersionError(status, "IUtil", cloopVTable->version, 5); + StatusType::checkException(status); + return 0; + } + StatusType::clearException(status); + IAttachment* ret = static_cast(this->cloopVTable)->executeCreateDatabase2(this, status, stmtLength, creatDBstatement, dialect, dpbLength, dpb, stmtIsCreateDb); + StatusType::checkException(status); + return ret; + } }; #define FIREBIRD_IOFFSETS_CALLBACK_VERSION 2u @@ -6890,7 +6949,7 @@ namespace Firebird } }; -#define FIREBIRD_IREPLICATED_TRANSACTION_VERSION 3u +#define FIREBIRD_IREPLICATED_TRANSACTION_VERSION 4u class IReplicatedTransaction : public IDisposable { @@ -6903,11 +6962,15 @@ namespace Firebird void (CLOOP_CARG *startSavepoint)(IReplicatedTransaction* self, IStatus* status) CLOOP_NOEXCEPT; void (CLOOP_CARG *releaseSavepoint)(IReplicatedTransaction* self, IStatus* status) CLOOP_NOEXCEPT; void (CLOOP_CARG *rollbackSavepoint)(IReplicatedTransaction* self, IStatus* status) CLOOP_NOEXCEPT; - void (CLOOP_CARG *insertRecord)(IReplicatedTransaction* self, IStatus* status, const char* name, IReplicatedRecord* record) CLOOP_NOEXCEPT; - void (CLOOP_CARG *updateRecord)(IReplicatedTransaction* self, IStatus* status, const char* name, IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) CLOOP_NOEXCEPT; - void (CLOOP_CARG *deleteRecord)(IReplicatedTransaction* self, IStatus* status, const char* name, IReplicatedRecord* record) CLOOP_NOEXCEPT; - void (CLOOP_CARG *executeSql)(IReplicatedTransaction* self, IStatus* status, const char* sql) CLOOP_NOEXCEPT; - void (CLOOP_CARG *executeSqlIntl)(IReplicatedTransaction* self, IStatus* status, unsigned charset, const char* sql) CLOOP_NOEXCEPT; + void (CLOOP_CARG *deprecatedInsertRecord)(IReplicatedTransaction* self, IStatus* status, const char* name, IReplicatedRecord* record) CLOOP_NOEXCEPT; + void (CLOOP_CARG *deprecatedUpdateRecord)(IReplicatedTransaction* self, IStatus* status, const char* name, IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) CLOOP_NOEXCEPT; + void (CLOOP_CARG *deprecatedDeleteRecord)(IReplicatedTransaction* self, IStatus* status, const char* name, IReplicatedRecord* record) CLOOP_NOEXCEPT; + void (CLOOP_CARG *deprecatedExecuteSql)(IReplicatedTransaction* self, IStatus* status, const char* sql) CLOOP_NOEXCEPT; + void (CLOOP_CARG *deprecatedExecuteSqlIntl)(IReplicatedTransaction* self, IStatus* status, unsigned charset, const char* sql) CLOOP_NOEXCEPT; + void (CLOOP_CARG *insertRecord2)(IReplicatedTransaction* self, IStatus* status, const char* schemaName, const char* tableName, IReplicatedRecord* record) CLOOP_NOEXCEPT; + void (CLOOP_CARG *updateRecord2)(IReplicatedTransaction* self, IStatus* status, const char* schemaName, const char* tableName, IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) CLOOP_NOEXCEPT; + void (CLOOP_CARG *deleteRecord2)(IReplicatedTransaction* self, IStatus* status, const char* schemaName, const char* tableName, IReplicatedRecord* record) CLOOP_NOEXCEPT; + void (CLOOP_CARG *executeSqlIntl2)(IReplicatedTransaction* self, IStatus* status, unsigned charset, const char* schemaSearchPath, const char* sql) CLOOP_NOEXCEPT; }; protected: @@ -6965,43 +7028,95 @@ namespace Firebird StatusType::checkException(status); } - template void insertRecord(StatusType* status, const char* name, IReplicatedRecord* record) + template void deprecatedInsertRecord(StatusType* status, const char* name, IReplicatedRecord* record) { StatusType::clearException(status); - static_cast(this->cloopVTable)->insertRecord(this, status, name, record); + static_cast(this->cloopVTable)->deprecatedInsertRecord(this, status, name, record); StatusType::checkException(status); } - template void updateRecord(StatusType* status, const char* name, IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) + template void deprecatedUpdateRecord(StatusType* status, const char* name, IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) { StatusType::clearException(status); - static_cast(this->cloopVTable)->updateRecord(this, status, name, orgRecord, newRecord); + static_cast(this->cloopVTable)->deprecatedUpdateRecord(this, status, name, orgRecord, newRecord); StatusType::checkException(status); } - template void deleteRecord(StatusType* status, const char* name, IReplicatedRecord* record) + template void deprecatedDeleteRecord(StatusType* status, const char* name, IReplicatedRecord* record) { StatusType::clearException(status); - static_cast(this->cloopVTable)->deleteRecord(this, status, name, record); + static_cast(this->cloopVTable)->deprecatedDeleteRecord(this, status, name, record); StatusType::checkException(status); } - template void executeSql(StatusType* status, const char* sql) + template void deprecatedExecuteSql(StatusType* status, const char* sql) { StatusType::clearException(status); - static_cast(this->cloopVTable)->executeSql(this, status, sql); + static_cast(this->cloopVTable)->deprecatedExecuteSql(this, status, sql); StatusType::checkException(status); } - template void executeSqlIntl(StatusType* status, unsigned charset, const char* sql) + template void deprecatedExecuteSqlIntl(StatusType* status, unsigned charset, const char* sql) { StatusType::clearException(status); - static_cast(this->cloopVTable)->executeSqlIntl(this, status, charset, sql); + static_cast(this->cloopVTable)->deprecatedExecuteSqlIntl(this, status, charset, sql); + StatusType::checkException(status); + } + + template void insertRecord2(StatusType* status, const char* schemaName, const char* tableName, IReplicatedRecord* record) + { + if (cloopVTable->version < 4) + { + StatusType::setVersionError(status, "IReplicatedTransaction", cloopVTable->version, 4); + StatusType::checkException(status); + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->insertRecord2(this, status, schemaName, tableName, record); + StatusType::checkException(status); + } + + template void updateRecord2(StatusType* status, const char* schemaName, const char* tableName, IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) + { + if (cloopVTable->version < 4) + { + StatusType::setVersionError(status, "IReplicatedTransaction", cloopVTable->version, 4); + StatusType::checkException(status); + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->updateRecord2(this, status, schemaName, tableName, orgRecord, newRecord); + StatusType::checkException(status); + } + + template void deleteRecord2(StatusType* status, const char* schemaName, const char* tableName, IReplicatedRecord* record) + { + if (cloopVTable->version < 4) + { + StatusType::setVersionError(status, "IReplicatedTransaction", cloopVTable->version, 4); + StatusType::checkException(status); + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->deleteRecord2(this, status, schemaName, tableName, record); + StatusType::checkException(status); + } + + template void executeSqlIntl2(StatusType* status, unsigned charset, const char* schemaSearchPath, const char* sql) + { + if (cloopVTable->version < 4) + { + StatusType::setVersionError(status, "IReplicatedTransaction", cloopVTable->version, 4); + StatusType::checkException(status); + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->executeSqlIntl2(this, status, charset, schemaSearchPath, sql); StatusType::checkException(status); } }; -#define FIREBIRD_IREPLICATED_SESSION_VERSION 4u +#define FIREBIRD_IREPLICATED_SESSION_VERSION 5u class IReplicatedSession : public IPluginBase { @@ -7011,7 +7126,8 @@ namespace Firebird FB_BOOLEAN (CLOOP_CARG *init)(IReplicatedSession* self, IStatus* status, IAttachment* attachment) CLOOP_NOEXCEPT; IReplicatedTransaction* (CLOOP_CARG *startTransaction)(IReplicatedSession* self, IStatus* status, ITransaction* transaction, ISC_INT64 number) CLOOP_NOEXCEPT; void (CLOOP_CARG *cleanupTransaction)(IReplicatedSession* self, IStatus* status, ISC_INT64 number) CLOOP_NOEXCEPT; - void (CLOOP_CARG *setSequence)(IReplicatedSession* self, IStatus* status, const char* name, ISC_INT64 value) CLOOP_NOEXCEPT; + void (CLOOP_CARG *deprecatedSetSequence)(IReplicatedSession* self, IStatus* status, const char* name, ISC_INT64 value) CLOOP_NOEXCEPT; + void (CLOOP_CARG *setSequence2)(IReplicatedSession* self, IStatus* status, const char* schemaName, const char* genName, ISC_INT64 value) CLOOP_NOEXCEPT; }; protected: @@ -7050,10 +7166,23 @@ namespace Firebird StatusType::checkException(status); } - template void setSequence(StatusType* status, const char* name, ISC_INT64 value) + template void deprecatedSetSequence(StatusType* status, const char* name, ISC_INT64 value) { StatusType::clearException(status); - static_cast(this->cloopVTable)->setSequence(this, status, name, value); + static_cast(this->cloopVTable)->deprecatedSetSequence(this, status, name, value); + StatusType::checkException(status); + } + + template void setSequence2(StatusType* status, const char* schemaName, const char* genName, ISC_INT64 value) + { + if (cloopVTable->version < 5) + { + StatusType::setVersionError(status, "IReplicatedSession", cloopVTable->version, 5); + StatusType::checkException(status); + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->setSequence2(this, status, schemaName, genName, value); StatusType::checkException(status); } }; @@ -7106,7 +7235,7 @@ namespace Firebird } }; -#define FIREBIRD_IPROFILER_SESSION_VERSION 3u +#define FIREBIRD_IPROFILER_SESSION_VERSION 4u class IProfilerSession : public IDisposable { @@ -7117,7 +7246,7 @@ namespace Firebird unsigned (CLOOP_CARG *getFlags)(IProfilerSession* self) CLOOP_NOEXCEPT; void (CLOOP_CARG *cancel)(IProfilerSession* self, IStatus* status) CLOOP_NOEXCEPT; void (CLOOP_CARG *finish)(IProfilerSession* self, IStatus* status, ISC_TIMESTAMP_TZ timestamp) CLOOP_NOEXCEPT; - void (CLOOP_CARG *defineStatement)(IProfilerSession* self, IStatus* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) CLOOP_NOEXCEPT; + void (CLOOP_CARG *deprecatedDefineStatement)(IProfilerSession* self, IStatus* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) CLOOP_NOEXCEPT; void (CLOOP_CARG *defineCursor)(IProfilerSession* self, ISC_INT64 statementId, unsigned cursorId, const char* name, unsigned line, unsigned column) CLOOP_NOEXCEPT; void (CLOOP_CARG *defineRecordSource)(IProfilerSession* self, ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, unsigned level, const char* accessPath, unsigned parentRecSourceId) CLOOP_NOEXCEPT; void (CLOOP_CARG *onRequestStart)(IProfilerSession* self, IStatus* status, ISC_INT64 statementId, ISC_INT64 requestId, ISC_INT64 callerStatementId, ISC_INT64 callerRequestId, ISC_TIMESTAMP_TZ timestamp) CLOOP_NOEXCEPT; @@ -7128,6 +7257,7 @@ namespace Firebird void (CLOOP_CARG *afterRecordSourceOpen)(IProfilerSession* self, ISC_INT64 statementId, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) CLOOP_NOEXCEPT; void (CLOOP_CARG *beforeRecordSourceGetRecord)(IProfilerSession* self, ISC_INT64 statementId, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId) CLOOP_NOEXCEPT; void (CLOOP_CARG *afterRecordSourceGetRecord)(IProfilerSession* self, ISC_INT64 statementId, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) CLOOP_NOEXCEPT; + void (CLOOP_CARG *defineStatement2)(IProfilerSession* self, IStatus* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* schemaName, const char* packageName, const char* routineName, const char* sqlText) CLOOP_NOEXCEPT; }; protected: @@ -7172,10 +7302,10 @@ namespace Firebird StatusType::checkException(status); } - template void defineStatement(StatusType* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) + template void deprecatedDefineStatement(StatusType* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) { StatusType::clearException(status); - static_cast(this->cloopVTable)->defineStatement(this, status, statementId, parentStatementId, type, packageName, routineName, sqlText); + static_cast(this->cloopVTable)->deprecatedDefineStatement(this, status, statementId, parentStatementId, type, packageName, routineName, sqlText); StatusType::checkException(status); } @@ -7232,6 +7362,18 @@ namespace Firebird { static_cast(this->cloopVTable)->afterRecordSourceGetRecord(this, statementId, requestId, cursorId, recSourceId, stats); } + + template void defineStatement2(StatusType* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* schemaName, const char* packageName, const char* routineName, const char* sqlText) + { + if (cloopVTable->version < 4) + { + deprecatedDefineStatement(status, statementId, parentStatementId, type, packageName, routineName, sqlText); + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->defineStatement2(this, status, statementId, parentStatementId, type, schemaName, packageName, routineName, sqlText); + StatusType::checkException(status); + } }; #define FIREBIRD_IPROFILER_STATS_VERSION 2u @@ -9609,6 +9751,7 @@ namespace Firebird this->getMessageLength = &Name::cloopgetMessageLengthDispatcher; this->getAlignment = &Name::cloopgetAlignmentDispatcher; this->getAlignedLength = &Name::cloopgetAlignedLengthDispatcher; + this->getSchema = &Name::cloopgetSchemaDispatcher; } } vTable; @@ -9870,6 +10013,21 @@ namespace Firebird } } + static const char* CLOOP_CARG cloopgetSchemaDispatcher(IMessageMetadata* self, IStatus* status, unsigned index) CLOOP_NOEXCEPT + { + StatusType status2(status); + + try + { + return static_cast(self)->Name::getSchema(&status2, index); + } + catch (...) + { + StatusType::catchException(&status2); + return static_cast(0); + } + } + static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) CLOOP_NOEXCEPT { try @@ -9926,6 +10084,7 @@ namespace Firebird virtual unsigned getMessageLength(StatusType* status) = 0; virtual unsigned getAlignment(StatusType* status) = 0; virtual unsigned getAlignedLength(StatusType* status) = 0; + virtual const char* getSchema(StatusType* status, unsigned index) = 0; }; template @@ -9957,6 +10116,7 @@ namespace Firebird this->setRelation = &Name::cloopsetRelationDispatcher; this->setOwner = &Name::cloopsetOwnerDispatcher; this->setAlias = &Name::cloopsetAliasDispatcher; + this->setSchema = &Name::cloopsetSchemaDispatcher; } } vTable; @@ -10161,6 +10321,20 @@ namespace Firebird } } + static void CLOOP_CARG cloopsetSchemaDispatcher(IMetadataBuilder* self, IStatus* status, unsigned index, const char* schema) CLOOP_NOEXCEPT + { + StatusType status2(status); + + try + { + static_cast(self)->Name::setSchema(&status2, index, schema); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) CLOOP_NOEXCEPT { try @@ -10214,6 +10388,7 @@ namespace Firebird virtual void setRelation(StatusType* status, unsigned index, const char* relation) = 0; virtual void setOwner(StatusType* status, unsigned index, const char* owner) = 0; virtual void setAlias(StatusType* status, unsigned index, const char* alias) = 0; + virtual void setSchema(StatusType* status, unsigned index, const char* schema) = 0; }; template @@ -15404,6 +15579,7 @@ namespace Firebird this->getTriggerMetadata = &Name::cloopgetTriggerMetadataDispatcher; this->getTriggerTable = &Name::cloopgetTriggerTableDispatcher; this->getTriggerType = &Name::cloopgetTriggerTypeDispatcher; + this->getSchema = &Name::cloopgetSchemaDispatcher; } } vTable; @@ -15544,6 +15720,21 @@ namespace Firebird return static_cast(0); } } + + static const char* CLOOP_CARG cloopgetSchemaDispatcher(const IRoutineMetadata* self, IStatus* status) CLOOP_NOEXCEPT + { + StatusType status2(status); + + try + { + return static_cast(self)->Name::getSchema(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + return static_cast(0); + } + } }; template > > @@ -15568,6 +15759,7 @@ namespace Firebird virtual IMessageMetadata* getTriggerMetadata(StatusType* status) const = 0; virtual const char* getTriggerTable(StatusType* status) const = 0; virtual unsigned getTriggerType(StatusType* status) const = 0; + virtual const char* getSchema(StatusType* status) const = 0; }; template @@ -15987,6 +16179,7 @@ namespace Firebird this->getInt128 = &Name::cloopgetInt128Dispatcher; this->decodeTimeTzEx = &Name::cloopdecodeTimeTzExDispatcher; this->decodeTimeStampTzEx = &Name::cloopdecodeTimeStampTzExDispatcher; + this->executeCreateDatabase2 = &Name::cloopexecuteCreateDatabase2Dispatcher; } } vTable; @@ -16298,6 +16491,21 @@ namespace Firebird StatusType::catchException(&status2); } } + + static IAttachment* CLOOP_CARG cloopexecuteCreateDatabase2Dispatcher(IUtil* self, IStatus* status, unsigned stmtLength, const char* creatDBstatement, unsigned dialect, unsigned dpbLength, const unsigned char* dpb, FB_BOOLEAN* stmtIsCreateDb) CLOOP_NOEXCEPT + { + StatusType status2(status); + + try + { + return static_cast(self)->Name::executeCreateDatabase2(&status2, stmtLength, creatDBstatement, dialect, dpbLength, dpb, stmtIsCreateDb); + } + catch (...) + { + StatusType::catchException(&status2); + return static_cast(0); + } + } }; template > > @@ -16335,6 +16543,7 @@ namespace Firebird virtual IInt128* getInt128(StatusType* status) = 0; virtual void decodeTimeTzEx(StatusType* status, const ISC_TIME_TZ_EX* timeTz, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer) = 0; virtual void decodeTimeStampTzEx(StatusType* status, const ISC_TIMESTAMP_TZ_EX* timeStampTz, unsigned* year, unsigned* month, unsigned* day, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer) = 0; + virtual IAttachment* executeCreateDatabase2(StatusType* status, unsigned stmtLength, const char* creatDBstatement, unsigned dialect, unsigned dpbLength, const unsigned char* dpb, FB_BOOLEAN* stmtIsCreateDb) = 0; }; template @@ -20297,11 +20506,15 @@ namespace Firebird this->startSavepoint = &Name::cloopstartSavepointDispatcher; this->releaseSavepoint = &Name::cloopreleaseSavepointDispatcher; this->rollbackSavepoint = &Name::clooprollbackSavepointDispatcher; - this->insertRecord = &Name::cloopinsertRecordDispatcher; - this->updateRecord = &Name::cloopupdateRecordDispatcher; - this->deleteRecord = &Name::cloopdeleteRecordDispatcher; - this->executeSql = &Name::cloopexecuteSqlDispatcher; - this->executeSqlIntl = &Name::cloopexecuteSqlIntlDispatcher; + this->deprecatedInsertRecord = &Name::cloopdeprecatedInsertRecordDispatcher; + this->deprecatedUpdateRecord = &Name::cloopdeprecatedUpdateRecordDispatcher; + this->deprecatedDeleteRecord = &Name::cloopdeprecatedDeleteRecordDispatcher; + this->deprecatedExecuteSql = &Name::cloopdeprecatedExecuteSqlDispatcher; + this->deprecatedExecuteSqlIntl = &Name::cloopdeprecatedExecuteSqlIntlDispatcher; + this->insertRecord2 = &Name::cloopinsertRecord2Dispatcher; + this->updateRecord2 = &Name::cloopupdateRecord2Dispatcher; + this->deleteRecord2 = &Name::cloopdeleteRecord2Dispatcher; + this->executeSqlIntl2 = &Name::cloopexecuteSqlIntl2Dispatcher; } } vTable; @@ -20392,13 +20605,13 @@ namespace Firebird } } - static void CLOOP_CARG cloopinsertRecordDispatcher(IReplicatedTransaction* self, IStatus* status, const char* name, IReplicatedRecord* record) CLOOP_NOEXCEPT + static void CLOOP_CARG cloopdeprecatedInsertRecordDispatcher(IReplicatedTransaction* self, IStatus* status, const char* name, IReplicatedRecord* record) CLOOP_NOEXCEPT { StatusType status2(status); try { - static_cast(self)->Name::insertRecord(&status2, name, record); + static_cast(self)->Name::deprecatedInsertRecord(&status2, name, record); } catch (...) { @@ -20406,13 +20619,13 @@ namespace Firebird } } - static void CLOOP_CARG cloopupdateRecordDispatcher(IReplicatedTransaction* self, IStatus* status, const char* name, IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) CLOOP_NOEXCEPT + static void CLOOP_CARG cloopdeprecatedUpdateRecordDispatcher(IReplicatedTransaction* self, IStatus* status, const char* name, IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) CLOOP_NOEXCEPT { StatusType status2(status); try { - static_cast(self)->Name::updateRecord(&status2, name, orgRecord, newRecord); + static_cast(self)->Name::deprecatedUpdateRecord(&status2, name, orgRecord, newRecord); } catch (...) { @@ -20420,13 +20633,13 @@ namespace Firebird } } - static void CLOOP_CARG cloopdeleteRecordDispatcher(IReplicatedTransaction* self, IStatus* status, const char* name, IReplicatedRecord* record) CLOOP_NOEXCEPT + static void CLOOP_CARG cloopdeprecatedDeleteRecordDispatcher(IReplicatedTransaction* self, IStatus* status, const char* name, IReplicatedRecord* record) CLOOP_NOEXCEPT { StatusType status2(status); try { - static_cast(self)->Name::deleteRecord(&status2, name, record); + static_cast(self)->Name::deprecatedDeleteRecord(&status2, name, record); } catch (...) { @@ -20434,13 +20647,13 @@ namespace Firebird } } - static void CLOOP_CARG cloopexecuteSqlDispatcher(IReplicatedTransaction* self, IStatus* status, const char* sql) CLOOP_NOEXCEPT + static void CLOOP_CARG cloopdeprecatedExecuteSqlDispatcher(IReplicatedTransaction* self, IStatus* status, const char* sql) CLOOP_NOEXCEPT { StatusType status2(status); try { - static_cast(self)->Name::executeSql(&status2, sql); + static_cast(self)->Name::deprecatedExecuteSql(&status2, sql); } catch (...) { @@ -20448,13 +20661,69 @@ namespace Firebird } } - static void CLOOP_CARG cloopexecuteSqlIntlDispatcher(IReplicatedTransaction* self, IStatus* status, unsigned charset, const char* sql) CLOOP_NOEXCEPT + static void CLOOP_CARG cloopdeprecatedExecuteSqlIntlDispatcher(IReplicatedTransaction* self, IStatus* status, unsigned charset, const char* sql) CLOOP_NOEXCEPT { StatusType status2(status); try { - static_cast(self)->Name::executeSqlIntl(&status2, charset, sql); + static_cast(self)->Name::deprecatedExecuteSqlIntl(&status2, charset, sql); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + + static void CLOOP_CARG cloopinsertRecord2Dispatcher(IReplicatedTransaction* self, IStatus* status, const char* schemaName, const char* tableName, IReplicatedRecord* record) CLOOP_NOEXCEPT + { + StatusType status2(status); + + try + { + static_cast(self)->Name::insertRecord2(&status2, schemaName, tableName, record); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + + static void CLOOP_CARG cloopupdateRecord2Dispatcher(IReplicatedTransaction* self, IStatus* status, const char* schemaName, const char* tableName, IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) CLOOP_NOEXCEPT + { + StatusType status2(status); + + try + { + static_cast(self)->Name::updateRecord2(&status2, schemaName, tableName, orgRecord, newRecord); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + + static void CLOOP_CARG cloopdeleteRecord2Dispatcher(IReplicatedTransaction* self, IStatus* status, const char* schemaName, const char* tableName, IReplicatedRecord* record) CLOOP_NOEXCEPT + { + StatusType status2(status); + + try + { + static_cast(self)->Name::deleteRecord2(&status2, schemaName, tableName, record); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + + static void CLOOP_CARG cloopexecuteSqlIntl2Dispatcher(IReplicatedTransaction* self, IStatus* status, unsigned charset, const char* schemaSearchPath, const char* sql) CLOOP_NOEXCEPT + { + StatusType status2(status); + + try + { + static_cast(self)->Name::executeSqlIntl2(&status2, charset, schemaSearchPath, sql); } catch (...) { @@ -20494,11 +20763,15 @@ namespace Firebird virtual void startSavepoint(StatusType* status) = 0; virtual void releaseSavepoint(StatusType* status) = 0; virtual void rollbackSavepoint(StatusType* status) = 0; - virtual void insertRecord(StatusType* status, const char* name, IReplicatedRecord* record) = 0; - virtual void updateRecord(StatusType* status, const char* name, IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) = 0; - virtual void deleteRecord(StatusType* status, const char* name, IReplicatedRecord* record) = 0; - virtual void executeSql(StatusType* status, const char* sql) = 0; - virtual void executeSqlIntl(StatusType* status, unsigned charset, const char* sql) = 0; + virtual void deprecatedInsertRecord(StatusType* status, const char* name, IReplicatedRecord* record) = 0; + virtual void deprecatedUpdateRecord(StatusType* status, const char* name, IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) = 0; + virtual void deprecatedDeleteRecord(StatusType* status, const char* name, IReplicatedRecord* record) = 0; + virtual void deprecatedExecuteSql(StatusType* status, const char* sql) = 0; + virtual void deprecatedExecuteSqlIntl(StatusType* status, unsigned charset, const char* sql) = 0; + virtual void insertRecord2(StatusType* status, const char* schemaName, const char* tableName, IReplicatedRecord* record) = 0; + virtual void updateRecord2(StatusType* status, const char* schemaName, const char* tableName, IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) = 0; + virtual void deleteRecord2(StatusType* status, const char* schemaName, const char* tableName, IReplicatedRecord* record) = 0; + virtual void executeSqlIntl2(StatusType* status, unsigned charset, const char* schemaSearchPath, const char* sql) = 0; }; template @@ -20521,7 +20794,8 @@ namespace Firebird this->init = &Name::cloopinitDispatcher; this->startTransaction = &Name::cloopstartTransactionDispatcher; this->cleanupTransaction = &Name::cloopcleanupTransactionDispatcher; - this->setSequence = &Name::cloopsetSequenceDispatcher; + this->deprecatedSetSequence = &Name::cloopdeprecatedSetSequenceDispatcher; + this->setSequence2 = &Name::cloopsetSequence2Dispatcher; } } vTable; @@ -20572,13 +20846,27 @@ namespace Firebird } } - static void CLOOP_CARG cloopsetSequenceDispatcher(IReplicatedSession* self, IStatus* status, const char* name, ISC_INT64 value) CLOOP_NOEXCEPT + static void CLOOP_CARG cloopdeprecatedSetSequenceDispatcher(IReplicatedSession* self, IStatus* status, const char* name, ISC_INT64 value) CLOOP_NOEXCEPT { StatusType status2(status); try { - static_cast(self)->Name::setSequence(&status2, name, value); + static_cast(self)->Name::deprecatedSetSequence(&status2, name, value); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + + static void CLOOP_CARG cloopsetSequence2Dispatcher(IReplicatedSession* self, IStatus* status, const char* schemaName, const char* genName, ISC_INT64 value) CLOOP_NOEXCEPT + { + StatusType status2(status); + + try + { + static_cast(self)->Name::setSequence2(&status2, schemaName, genName, value); } catch (...) { @@ -20653,7 +20941,8 @@ namespace Firebird virtual FB_BOOLEAN init(StatusType* status, IAttachment* attachment) = 0; virtual IReplicatedTransaction* startTransaction(StatusType* status, ITransaction* transaction, ISC_INT64 number) = 0; virtual void cleanupTransaction(StatusType* status, ISC_INT64 number) = 0; - virtual void setSequence(StatusType* status, const char* name, ISC_INT64 value) = 0; + virtual void deprecatedSetSequence(StatusType* status, const char* name, ISC_INT64 value) = 0; + virtual void setSequence2(StatusType* status, const char* schemaName, const char* genName, ISC_INT64 value) = 0; }; template @@ -20812,7 +21101,7 @@ namespace Firebird this->getFlags = &Name::cloopgetFlagsDispatcher; this->cancel = &Name::cloopcancelDispatcher; this->finish = &Name::cloopfinishDispatcher; - this->defineStatement = &Name::cloopdefineStatementDispatcher; + this->deprecatedDefineStatement = &Name::cloopdeprecatedDefineStatementDispatcher; this->defineCursor = &Name::cloopdefineCursorDispatcher; this->defineRecordSource = &Name::cloopdefineRecordSourceDispatcher; this->onRequestStart = &Name::clooponRequestStartDispatcher; @@ -20823,6 +21112,7 @@ namespace Firebird this->afterRecordSourceOpen = &Name::cloopafterRecordSourceOpenDispatcher; this->beforeRecordSourceGetRecord = &Name::cloopbeforeRecordSourceGetRecordDispatcher; this->afterRecordSourceGetRecord = &Name::cloopafterRecordSourceGetRecordDispatcher; + this->defineStatement2 = &Name::cloopdefineStatement2Dispatcher; } } vTable; @@ -20883,13 +21173,13 @@ namespace Firebird } } - static void CLOOP_CARG cloopdefineStatementDispatcher(IProfilerSession* self, IStatus* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) CLOOP_NOEXCEPT + static void CLOOP_CARG cloopdeprecatedDefineStatementDispatcher(IProfilerSession* self, IStatus* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) CLOOP_NOEXCEPT { StatusType status2(status); try { - static_cast(self)->Name::defineStatement(&status2, statementId, parentStatementId, type, packageName, routineName, sqlText); + static_cast(self)->Name::deprecatedDefineStatement(&status2, statementId, parentStatementId, type, packageName, routineName, sqlText); } catch (...) { @@ -21021,6 +21311,20 @@ namespace Firebird } } + static void CLOOP_CARG cloopdefineStatement2Dispatcher(IProfilerSession* self, IStatus* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* schemaName, const char* packageName, const char* routineName, const char* sqlText) CLOOP_NOEXCEPT + { + StatusType status2(status); + + try + { + static_cast(self)->Name::defineStatement2(&status2, statementId, parentStatementId, type, schemaName, packageName, routineName, sqlText); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + static void CLOOP_CARG cloopdisposeDispatcher(IDisposable* self) CLOOP_NOEXCEPT { try @@ -21051,7 +21355,7 @@ namespace Firebird virtual unsigned getFlags() = 0; virtual void cancel(StatusType* status) = 0; virtual void finish(StatusType* status, ISC_TIMESTAMP_TZ timestamp) = 0; - virtual void defineStatement(StatusType* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) = 0; + virtual void deprecatedDefineStatement(StatusType* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) = 0; virtual void defineCursor(ISC_INT64 statementId, unsigned cursorId, const char* name, unsigned line, unsigned column) = 0; virtual void defineRecordSource(ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, unsigned level, const char* accessPath, unsigned parentRecSourceId) = 0; virtual void onRequestStart(StatusType* status, ISC_INT64 statementId, ISC_INT64 requestId, ISC_INT64 callerStatementId, ISC_INT64 callerRequestId, ISC_TIMESTAMP_TZ timestamp) = 0; @@ -21062,6 +21366,7 @@ namespace Firebird virtual void afterRecordSourceOpen(ISC_INT64 statementId, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) = 0; virtual void beforeRecordSourceGetRecord(ISC_INT64 statementId, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId) = 0; virtual void afterRecordSourceGetRecord(ISC_INT64 statementId, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) = 0; + virtual void defineStatement2(StatusType* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* schemaName, const char* packageName, const char* routineName, const char* sqlText) = 0; }; template diff --git a/src/include/firebird/impl/blr.h b/src/include/firebird/impl/blr.h index ecad7bb11a..eaf867f215 100644 --- a/src/include/firebird/impl/blr.h +++ b/src/include/firebird/impl/blr.h @@ -74,8 +74,10 @@ #define blr_timestamp_tz (unsigned char)29 #define blr_ex_time_tz (unsigned char)30 #define blr_ex_timestamp_tz (unsigned char)31 +#define blr_domain_name3 (unsigned char)32 +#define blr_column_name3 (unsigned char)33 -// first sub parameter for blr_domain_name[2] +// first sub parameter for blr_column_name* and blr_domain_name* #define blr_domain_type_of (unsigned char)0 #define blr_domain_full (unsigned char)1 @@ -96,6 +98,8 @@ #define blr_exception_msg (unsigned char)6 #define blr_exception_params (unsigned char)7 #define blr_sql_state (unsigned char)8 +#define blr_exception2 (unsigned char)9 +#define blr_exception3 (unsigned char)10 #define blr_version4 (unsigned char)4 #define blr_version5 (unsigned char)5 @@ -257,6 +261,7 @@ #define blr_relation2 (unsigned char)146 #define blr_rid2 (unsigned char)147 +#define blr_relation3 (unsigned char)148 // unused codes: 148..149 @@ -470,10 +475,11 @@ // FB 6.0 specific BLR #define blr_invoke_function (unsigned char) 224 -#define blr_invoke_function_type (unsigned char) 1 -#define blr_invoke_function_type_standalone (unsigned char) 1 -#define blr_invoke_function_type_packaged (unsigned char) 2 -#define blr_invoke_function_type_sub (unsigned char) 3 +#define blr_invoke_function_id (unsigned char) 1 +#define blr_invoke_function_id_schema (unsigned char) 1 +#define blr_invoke_function_id_package (unsigned char) 2 +#define blr_invoke_function_id_name (unsigned char) 3 +#define blr_invoke_function_id_sub (unsigned char) 4 #define blr_invoke_function_arg_names (unsigned char) 2 #define blr_invoke_function_args (unsigned char) 3 @@ -481,10 +487,11 @@ #define blr_select_procedure (unsigned char) 226 // subcodes of blr_invoke_procedure and blr_select_procedure -#define blr_invsel_procedure_type (unsigned char) 1 -#define blr_invsel_procedure_type_standalone (unsigned char) 1 -#define blr_invsel_procedure_type_packaged (unsigned char) 2 -#define blr_invsel_procedure_type_sub (unsigned char) 3 +#define blr_invsel_procedure_id (unsigned char) 1 +#define blr_invsel_procedure_id_schema (unsigned char) 1 +#define blr_invsel_procedure_id_package (unsigned char) 2 +#define blr_invsel_procedure_id_name (unsigned char) 3 +#define blr_invsel_procedure_id_sub (unsigned char) 4 #define blr_invsel_procedure_in_arg_names (unsigned char) 2 #define blr_invsel_procedure_in_args (unsigned char) 3 #define blr_invsel_procedure_out_arg_names (unsigned char) 4 @@ -498,4 +505,12 @@ #define blr_cast_format (unsigned char) 228 +#define blr_gen_id3 (unsigned char) 229 +#define blr_default2 (unsigned char) 230 +#define blr_current_schema (unsigned char) 231 +#define blr_flags (unsigned char) 232 + +// subcodes of blr_flags +#define blr_flags_search_system_schema (unsigned char) 1 + #endif // FIREBIRD_IMPL_BLR_H diff --git a/src/include/firebird/impl/consts_pub.h b/src/include/firebird/impl/consts_pub.h index d7702aac71..d5d3ad24a2 100644 --- a/src/include/firebird/impl/consts_pub.h +++ b/src/include/firebird/impl/consts_pub.h @@ -133,6 +133,9 @@ #define isc_dpb_parallel_workers 100 #define isc_dpb_worker_attach 101 #define isc_dpb_owner 102 +#define isc_dpb_search_path 103 +#define isc_dpb_blr_request_search_path 104 +#define isc_dpb_gbak_restore_has_schema 105 /**************************************************/ @@ -426,6 +429,8 @@ #define isc_spb_bkp_crypt 18 #define isc_spb_bkp_include_data 19 #define isc_spb_bkp_parallel_workers 21 +#define isc_spb_bkp_skip_schema_data 22 +#define isc_spb_bkp_include_schema_data 23 #define isc_spb_bkp_ignore_checksums 0x01 #define isc_spb_bkp_ignore_limbo 0x02 #define isc_spb_bkp_metadata_only 0x04 @@ -552,6 +557,8 @@ #define isc_spb_res_access_mode 12 #define isc_spb_res_fix_fss_data 13 #define isc_spb_res_fix_fss_metadata 14 +#define isc_spb_res_skip_schema_data isc_spb_bkp_skip_schema_data +#define isc_spb_res_include_schema_data isc_spb_bkp_include_schema_data #define isc_spb_res_keyholder isc_spb_bkp_keyholder #define isc_spb_res_keyname isc_spb_bkp_keyname #define isc_spb_res_crypt isc_spb_bkp_crypt @@ -577,6 +584,8 @@ #define isc_spb_val_idx_incl 3 // regexp of indices to validate #define isc_spb_val_idx_excl 4 // regexp of indices to NOT validate #define isc_spb_val_lock_timeout 5 // how long to wait for table lock +#define isc_spb_val_sch_incl 6 // include schema filter based on regular expression +#define isc_spb_val_sch_excl 7 // exclude schema filter based on regular expression /****************************************** * Parameters for isc_spb_res_access_mode * @@ -686,6 +695,7 @@ #define isc_sdl_do2 34 #define isc_sdl_do1 35 #define isc_sdl_element 36 +#define isc_sdl_schema 37 /********************************************/ /* International text interpretation values */ diff --git a/src/include/firebird/impl/inf_pub.h b/src/include/firebird/impl/inf_pub.h index 9f77591fdc..9e4d5674f0 100644 --- a/src/include/firebird/impl/inf_pub.h +++ b/src/include/firebird/impl/inf_pub.h @@ -500,6 +500,7 @@ enum info_db_provider #define isc_info_sql_stmt_blob_align 30 #define isc_info_sql_exec_path_blr_bytes 31 #define isc_info_sql_exec_path_blr_text 32 +#define isc_info_sql_relation_schema 33 /*********************************/ /* SQL information return values */ diff --git a/src/include/firebird/impl/msg/dsql.h b/src/include/firebird/impl/msg/dsql.h index 54a5339418..21ac4ecd32 100644 --- a/src/include/firebird/impl/msg/dsql.h +++ b/src/include/firebird/impl/msg/dsql.h @@ -20,7 +20,7 @@ FB_IMPL_MSG(DSQL, 20, dsql_cursor_exists, -502, "24", "000", "Cursor @1 already FB_IMPL_MSG(DSQL, 21, dsql_cursor_rel_ambiguous, -502, "34", "000", "Relation @1 is ambiguous in cursor @2") FB_IMPL_MSG(DSQL, 22, dsql_cursor_rel_not_found, -502, "34", "000", "Relation @1 is not found in cursor @2") FB_IMPL_MSG(DSQL, 23, dsql_cursor_not_open, -504, "24", "000", "Cursor is not open") -FB_IMPL_MSG(DSQL, 24, dsql_type_not_supp_ext_tab, -607, "HY", "004", "Data type @1 is not supported for EXTERNAL TABLES. Relation '@2', field '@3'") +FB_IMPL_MSG(DSQL, 24, dsql_type_not_supp_ext_tab, -607, "HY", "004", "Data type @1 is not supported for EXTERNAL TABLES. Relation @2, field @3") FB_IMPL_MSG(DSQL, 25, dsql_feature_not_supported_ods, -804, "0A", "000", "Feature not supported on ODS version older than @1.@2") FB_IMPL_MSG(DSQL, 26, primary_key_required, -660, "22", "000", "Primary key required on table @1") FB_IMPL_MSG(DSQL, 27, upd_ins_doesnt_match_pk, -313, "42", "000", "UPDATE OR INSERT field list does not match primary key of table @1") diff --git a/src/include/firebird/impl/msg/dyn.h b/src/include/firebird/impl/msg/dyn.h index 5ebc4ad4e5..5c5224eddf 100644 --- a/src/include/firebird/impl/msg/dyn.h +++ b/src/include/firebird/impl/msg/dyn.h @@ -303,3 +303,11 @@ FB_IMPL_MSG_SYMBOL(DYN, 310, dyn_dup_trigger, "Trigger @1 already exists") FB_IMPL_MSG_SYMBOL(DYN, 311, dyn_dup_domain, "Domain @1 already exists") FB_IMPL_MSG_SYMBOL(DYN, 312, dyn_dup_collation, "Collation @1 already exists") FB_IMPL_MSG_SYMBOL(DYN, 313, dyn_dup_package, "Package @1 already exists") +FB_IMPL_MSG(DYN, 314, dyn_index_schema_must_match_table, -901, "42", "000", "Index schema (@1) must match table schema (@2)") +FB_IMPL_MSG(DYN, 315, dyn_trig_schema_must_match_table, -901, "42", "000", "Trigger schema (@1) must match table schema (@2)") +FB_IMPL_MSG_SYMBOL(DYN, 316, dyn_dup_schema, "Schema @1 already exists") +FB_IMPL_MSG(DYN, 317, dyn_cannot_mod_system_schema, -607, "HY", "000", "Cannot ALTER or DROP SYSTEM schema") +FB_IMPL_MSG(DYN, 318, dyn_cannot_drop_non_emptyschema, -607, "HY", "000", "Cannot DROP schema @1 because it has objects") +FB_IMPL_MSG(DYN, 319, dyn_cannot_mod_obj_sys_schema, -607, "HY", "000", "Cannot CREATE/ALTER/DROP @1 in SYSTEM schema") +FB_IMPL_MSG(DYN, 320, dyn_cannot_create_reserved_schema, -607, "HY", "000", "Schema name @1 is reserved and cannot be created") +FB_IMPL_MSG(DYN, 321, dyn_cannot_infer_schema, -901, "42", "000", "Cannot infer schema name as there is no valid schema in the search path") diff --git a/src/include/firebird/impl/msg/gbak.h b/src/include/firebird/impl/msg/gbak.h index ea6291af67..acebf15c52 100644 --- a/src/include/firebird/impl/msg/gbak.h +++ b/src/include/firebird/impl/msg/gbak.h @@ -406,3 +406,13 @@ FB_IMPL_MSG_SYMBOL(GBAK, 407, gbak_missing_prl_wrks, "parallel workers parameter FB_IMPL_MSG_SYMBOL(GBAK, 408, gbak_inv_prl_wrks, "expected parallel workers, encountered \"@1\"") FB_IMPL_MSG_NO_SYMBOL(GBAK, 409, " @1D(IRECT_IO) direct IO for backup file(s)") FB_IMPL_MSG_NO_SYMBOL(GBAK, 410, "use up to @1 parallel workers") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 411, "writing schema @1") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 412, "writing schemas") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 413, "restoring schema @1") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 414, "schema") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 415, " @1SKIP_SCHEMA_D(ATA) skip data for schema") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 416, " @1INCLUDE_SCHEMA_D(ATA) backup data of schema(s)") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 417, "missing regular expression to skip schemas") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 418, "missing regular expression to include schemas") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 419, "regular expression to skip schemas was already set") +FB_IMPL_MSG_NO_SYMBOL(GBAK, 420, "regular expression to include schemas was already set") diff --git a/src/include/firebird/impl/msg/isql.h b/src/include/firebird/impl/msg/isql.h index 234c9587f5..dc569a7640 100644 --- a/src/include/firebird/impl/msg/isql.h +++ b/src/include/firebird/impl/msg/isql.h @@ -206,3 +206,4 @@ FB_IMPL_MSG_SYMBOL(ISQL, 206, USAGE_AUTOTERM, " -autot(erm) use auto FB_IMPL_MSG_SYMBOL(ISQL, 207, AUTOTERM_NOT_SUPPORTED, "SET AUTOTERM ON is not supported in engine/server and has been disabled") FB_IMPL_MSG_SYMBOL(ISQL, 208, HLP_SETAUTOTERM, " SET AUTOTERM -- toggle auto statement terminator") FB_IMPL_MSG_SYMBOL(ISQL, 209, HLP_SETWIRESTATS, " SET WIRE_stats -- toggle display of wire (network) statistics") +FB_IMPL_MSG_SYMBOL(ISQL, 210, USAGE_SEARCH_PATH, " -(se)arch_path set schema search path") diff --git a/src/include/firebird/impl/msg/jrd.h b/src/include/firebird/impl/msg/jrd.h index 84055568c2..f40a1ae888 100644 --- a/src/include/firebird/impl/msg/jrd.h +++ b/src/include/firebird/impl/msg/jrd.h @@ -27,7 +27,7 @@ FB_IMPL_MSG(JRD, 25, lock_conflict, -901, "40", "001", "lock conflict on no wait FB_IMPL_MSG(JRD, 26, metadata_corrupt, -902, "XX", "001", "corrupt system table") FB_IMPL_MSG(JRD, 27, not_valid, -625, "23", "000", "validation error for column @1, value \"@2\"") FB_IMPL_MSG(JRD, 28, no_cur_rec, -508, "22", "000", "no current record for fetch operation") -FB_IMPL_MSG(JRD, 29, no_dup, -803, "23", "000", "attempt to store duplicate value (visible to active transactions) in unique index \"@1\"") +FB_IMPL_MSG(JRD, 29, no_dup, -803, "23", "000", "attempt to store duplicate value (visible to active transactions) in unique index @1") FB_IMPL_MSG(JRD, 30, no_finish, -901, "HY", "000", "program attempted to exit without finishing database") FB_IMPL_MSG(JRD, 31, no_meta_update, -607, "42", "000", "unsuccessful metadata update") FB_IMPL_MSG(JRD, 32, no_priv, -551, "28", "000", "no permission for @1 access to @2 @3") @@ -144,7 +144,7 @@ FB_IMPL_MSG(JRD, 142, cant_start_journal, -923, "HY", "000", "secondary server a FB_IMPL_MSG(JRD, 143, gennotdef, -204, "42", "000", "generator @1 is not defined") FB_IMPL_MSG(JRD, 144, cant_start_logging, -923, "HY", "000", "secondary server attachments cannot start logging") FB_IMPL_MSG(JRD, 145, bad_segstr_type, -685, "42", "000", "invalid BLOB type for operation") -FB_IMPL_MSG(JRD, 146, foreign_key, -530, "23", "000", "violation of FOREIGN KEY constraint \"@1\" on table \"@2\"") +FB_IMPL_MSG(JRD, 146, foreign_key, -530, "23", "000", "violation of FOREIGN KEY constraint @1 on table @2") FB_IMPL_MSG(JRD, 147, high_minor, -820, "HY", "000", "minor version too high found @1 expected @2") FB_IMPL_MSG(JRD, 148, tra_state, -901, "00", "000", "transaction @1 is @2") FB_IMPL_MSG(JRD, 149, trans_invalid, -532, "25", "000", "transaction marked invalid and cannot be committed") @@ -275,7 +275,7 @@ FB_IMPL_MSG(JRD, 273, dsql_max_arr_dim_exceeded, -604, "54", "000", "Array decla FB_IMPL_MSG(JRD, 274, dsql_arr_range_error, -604, "42", "000", "Illegal array dimension range") FB_IMPL_MSG(JRD, 275, dsql_trigger_err, -204, "HY", "000", "Trigger unknown") FB_IMPL_MSG(JRD, 276, dsql_subselect_err, -206, "42", "000", "Subselect illegal in this context") -FB_IMPL_MSG(JRD, 277, dsql_crdb_prepare_err, -531, "42", "000", "Cannot prepare a CREATE DATABASE/SCHEMA statement") +FB_IMPL_MSG(JRD, 277, dsql_crdb_prepare_err, -531, "42", "000", "Cannot prepare a CREATE DATABASE statement") FB_IMPL_MSG(JRD, 278, specify_field_err, -157, "42", "000", "must specify column name for view select expression") FB_IMPL_MSG(JRD, 279, num_field_err, -158, "07", "002", "number of columns does not match select list") FB_IMPL_MSG(JRD, 280, col_name_err, -806, "42", "000", "Only simple column names permitted for VIEW WITH CHECK OPTION") @@ -343,7 +343,7 @@ FB_IMPL_MSG(JRD, 341, index_root_page_full, -904, "54", "000", "cannot add index FB_IMPL_MSG(JRD, 342, dsql_blob_type_unknown, -204, "42", "000", "BLOB SUB_TYPE @1 is not defined") FB_IMPL_MSG(JRD, 343, req_max_clones_exceeded, -693, "54", "001", "Too many concurrent executions of the same request") FB_IMPL_MSG(JRD, 344, dsql_duplicate_spec, -637, "42", "000", "duplicate specification of @1 - not supported") -FB_IMPL_MSG(JRD, 345, unique_key_violation, -803, "23", "000", "violation of PRIMARY or UNIQUE KEY constraint \"@1\" on table \"@2\"") +FB_IMPL_MSG(JRD, 345, unique_key_violation, -803, "23", "000", "violation of PRIMARY or UNIQUE KEY constraint @1 on table @2") FB_IMPL_MSG(JRD, 346, srvr_version_too_old, -901, "HY", "000", "server version too old to support all CREATE DATABASE options") FB_IMPL_MSG(JRD, 347, drdb_completed_with_errs, -909, "HY", "000", "drop database completed with errors") FB_IMPL_MSG(JRD, 348, dsql_procedure_use_err, -84, "42", "000", "procedure @1 does not return any values") @@ -987,3 +987,5 @@ FB_IMPL_MSG(JRD, 984, incompatible_format_patterns, -901, "HY", "000", "@1 incom FB_IMPL_MSG(JRD, 985, only_one_pattern_can_be_used, -901, "HY", "000", "Can use only one of these patterns @1") FB_IMPL_MSG(JRD, 986, can_not_use_same_pattern_twice, -901, "HY", "000", "Cannot use the same pattern twice: @1") FB_IMPL_MSG(JRD, 987, sysf_invalid_gen_uuid_version, -833, "42", "000", "Invalid GEN_UUID version (@1). Must be 4 or 7") +FB_IMPL_MSG(JRD, 988, invalid_name, -901, "HY", "000", "Invalid name: @1") +FB_IMPL_MSG(JRD, 989, invalid_unqualified_name_list, -901, "HY", "000", "Invalid list of unqualified names: @1") diff --git a/src/include/firebird/impl/msg/sqlerr.h b/src/include/firebird/impl/msg/sqlerr.h index 25a7014b0c..1fc4a44faf 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_schema_failed, -901, "42", "000", "CREATE SCHEMA @1 failed") +FB_IMPL_MSG(SQLERR, 1048, dsql_drop_schema_failed, -901, "42", "000", "DROP SCHEMA @1 failed") +FB_IMPL_MSG(SQLERR, 1049, dsql_recreate_schema_failed, -901, "42", "000", "RECREATE SCHEMA @1 failed") +FB_IMPL_MSG(SQLERR, 1050, dsql_alter_schema_failed, -901, "42", "000", "ALTER SCHEMA @1 failed") +FB_IMPL_MSG(SQLERR, 1051, dsql_create_alter_schema_failed, -901, "42", "000", "CREATE OR ALTER SCHEMA @1 failed") diff --git a/src/include/gen/Firebird.pas b/src/include/gen/Firebird.pas index e446fc37a0..4cc7ef2b80 100644 --- a/src/include/gen/Firebird.pas +++ b/src/include/gen/Firebird.pas @@ -316,6 +316,7 @@ type IMessageMetadata_getMessageLengthPtr = function(this: IMessageMetadata; status: IStatus): Cardinal; cdecl; IMessageMetadata_getAlignmentPtr = function(this: IMessageMetadata; status: IStatus): Cardinal; cdecl; IMessageMetadata_getAlignedLengthPtr = function(this: IMessageMetadata; status: IStatus): Cardinal; cdecl; + IMessageMetadata_getSchemaPtr = function(this: IMessageMetadata; status: IStatus; index: Cardinal): PAnsiChar; cdecl; IMetadataBuilder_setTypePtr = procedure(this: IMetadataBuilder; status: IStatus; index: Cardinal; type_: Cardinal); cdecl; IMetadataBuilder_setSubTypePtr = procedure(this: IMetadataBuilder; status: IStatus; index: Cardinal; subType: Integer); cdecl; IMetadataBuilder_setLengthPtr = procedure(this: IMetadataBuilder; status: IStatus; index: Cardinal; length: Cardinal); cdecl; @@ -330,6 +331,7 @@ type IMetadataBuilder_setRelationPtr = procedure(this: IMetadataBuilder; status: IStatus; index: Cardinal; relation: PAnsiChar); cdecl; IMetadataBuilder_setOwnerPtr = procedure(this: IMetadataBuilder; status: IStatus; index: Cardinal; owner: PAnsiChar); cdecl; IMetadataBuilder_setAliasPtr = procedure(this: IMetadataBuilder; status: IStatus; index: Cardinal; alias: PAnsiChar); cdecl; + IMetadataBuilder_setSchemaPtr = procedure(this: IMetadataBuilder; status: IStatus; index: Cardinal; schema: PAnsiChar); cdecl; IResultSet_fetchNextPtr = function(this: IResultSet; status: IStatus; message: Pointer): Integer; cdecl; IResultSet_fetchPriorPtr = function(this: IResultSet; status: IStatus; message: Pointer): Integer; cdecl; IResultSet_fetchFirstPtr = function(this: IResultSet; status: IStatus; message: Pointer): Integer; cdecl; @@ -527,6 +529,7 @@ type IRoutineMetadata_getTriggerMetadataPtr = function(this: IRoutineMetadata; status: IStatus): IMessageMetadata; cdecl; IRoutineMetadata_getTriggerTablePtr = function(this: IRoutineMetadata; status: IStatus): PAnsiChar; cdecl; IRoutineMetadata_getTriggerTypePtr = function(this: IRoutineMetadata; status: IStatus): Cardinal; cdecl; + IRoutineMetadata_getSchemaPtr = function(this: IRoutineMetadata; status: IStatus): PAnsiChar; cdecl; IExternalEngine_openPtr = procedure(this: IExternalEngine; status: IStatus; context: IExternalContext; charSet: PAnsiChar; charSetSize: Cardinal); cdecl; IExternalEngine_openAttachmentPtr = procedure(this: IExternalEngine; status: IStatus; context: IExternalContext); cdecl; IExternalEngine_closeAttachmentPtr = procedure(this: IExternalEngine; status: IStatus; context: IExternalContext); cdecl; @@ -559,6 +562,7 @@ type IUtil_getInt128Ptr = function(this: IUtil; status: IStatus): IInt128; cdecl; IUtil_decodeTimeTzExPtr = procedure(this: IUtil; status: IStatus; timeTz: ISC_TIME_TZ_EXPtr; hours: CardinalPtr; minutes: CardinalPtr; seconds: CardinalPtr; fractions: CardinalPtr; timeZoneBufferLength: Cardinal; timeZoneBuffer: PAnsiChar); cdecl; IUtil_decodeTimeStampTzExPtr = procedure(this: IUtil; status: IStatus; timeStampTz: ISC_TIMESTAMP_TZ_EXPtr; year: CardinalPtr; month: CardinalPtr; day: CardinalPtr; hours: CardinalPtr; minutes: CardinalPtr; seconds: CardinalPtr; fractions: CardinalPtr; timeZoneBufferLength: Cardinal; timeZoneBuffer: PAnsiChar); cdecl; + IUtil_executeCreateDatabase2Ptr = function(this: IUtil; status: IStatus; stmtLength: Cardinal; creatDBstatement: PAnsiChar; dialect: Cardinal; dpbLength: Cardinal; dpb: BytePtr; stmtIsCreateDb: BooleanPtr): IAttachment; cdecl; IOffsetsCallback_setOffsetPtr = procedure(this: IOffsetsCallback; status: IStatus; index: Cardinal; offset: Cardinal; nullOffset: Cardinal); cdecl; IXpbBuilder_clearPtr = procedure(this: IXpbBuilder; status: IStatus); cdecl; IXpbBuilder_removeCurrentPtr = procedure(this: IXpbBuilder; status: IStatus); cdecl; @@ -723,15 +727,20 @@ type IReplicatedTransaction_startSavepointPtr = procedure(this: IReplicatedTransaction; status: IStatus); cdecl; IReplicatedTransaction_releaseSavepointPtr = procedure(this: IReplicatedTransaction; status: IStatus); cdecl; IReplicatedTransaction_rollbackSavepointPtr = procedure(this: IReplicatedTransaction; status: IStatus); cdecl; - IReplicatedTransaction_insertRecordPtr = procedure(this: IReplicatedTransaction; status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); cdecl; - IReplicatedTransaction_updateRecordPtr = procedure(this: IReplicatedTransaction; status: IStatus; name: PAnsiChar; orgRecord: IReplicatedRecord; newRecord: IReplicatedRecord); cdecl; - IReplicatedTransaction_deleteRecordPtr = procedure(this: IReplicatedTransaction; status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); cdecl; - IReplicatedTransaction_executeSqlPtr = procedure(this: IReplicatedTransaction; status: IStatus; sql: PAnsiChar); cdecl; - IReplicatedTransaction_executeSqlIntlPtr = procedure(this: IReplicatedTransaction; status: IStatus; charset: Cardinal; sql: PAnsiChar); cdecl; + IReplicatedTransaction_deprecatedInsertRecordPtr = procedure(this: IReplicatedTransaction; status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); cdecl; + IReplicatedTransaction_deprecatedUpdateRecordPtr = procedure(this: IReplicatedTransaction; status: IStatus; name: PAnsiChar; orgRecord: IReplicatedRecord; newRecord: IReplicatedRecord); cdecl; + IReplicatedTransaction_deprecatedDeleteRecordPtr = procedure(this: IReplicatedTransaction; status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); cdecl; + IReplicatedTransaction_deprecatedExecuteSqlPtr = procedure(this: IReplicatedTransaction; status: IStatus; sql: PAnsiChar); cdecl; + IReplicatedTransaction_deprecatedExecuteSqlIntlPtr = procedure(this: IReplicatedTransaction; status: IStatus; charset: Cardinal; sql: PAnsiChar); cdecl; + IReplicatedTransaction_insertRecord2Ptr = procedure(this: IReplicatedTransaction; status: IStatus; schemaName: PAnsiChar; tableName: PAnsiChar; record_: IReplicatedRecord); cdecl; + IReplicatedTransaction_updateRecord2Ptr = procedure(this: IReplicatedTransaction; status: IStatus; schemaName: PAnsiChar; tableName: PAnsiChar; orgRecord: IReplicatedRecord; newRecord: IReplicatedRecord); cdecl; + IReplicatedTransaction_deleteRecord2Ptr = procedure(this: IReplicatedTransaction; status: IStatus; schemaName: PAnsiChar; tableName: PAnsiChar; record_: IReplicatedRecord); cdecl; + IReplicatedTransaction_executeSqlIntl2Ptr = procedure(this: IReplicatedTransaction; status: IStatus; charset: Cardinal; schemaSearchPath: PAnsiChar; sql: PAnsiChar); cdecl; IReplicatedSession_initPtr = function(this: IReplicatedSession; status: IStatus; attachment: IAttachment): Boolean; cdecl; IReplicatedSession_startTransactionPtr = function(this: IReplicatedSession; status: IStatus; transaction: ITransaction; number: Int64): IReplicatedTransaction; cdecl; IReplicatedSession_cleanupTransactionPtr = procedure(this: IReplicatedSession; status: IStatus; number: Int64); cdecl; - IReplicatedSession_setSequencePtr = procedure(this: IReplicatedSession; status: IStatus; name: PAnsiChar; value: Int64); cdecl; + IReplicatedSession_deprecatedSetSequencePtr = procedure(this: IReplicatedSession; status: IStatus; name: PAnsiChar; value: Int64); cdecl; + IReplicatedSession_setSequence2Ptr = procedure(this: IReplicatedSession; status: IStatus; schemaName: PAnsiChar; genName: PAnsiChar; value: Int64); cdecl; IProfilerPlugin_initPtr = procedure(this: IProfilerPlugin; status: IStatus; attachment: IAttachment; ticksFrequency: QWord); cdecl; IProfilerPlugin_startSessionPtr = function(this: IProfilerPlugin; status: IStatus; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; cdecl; IProfilerPlugin_flushPtr = procedure(this: IProfilerPlugin; status: IStatus); cdecl; @@ -739,7 +748,7 @@ type IProfilerSession_getFlagsPtr = function(this: IProfilerSession): Cardinal; cdecl; IProfilerSession_cancelPtr = procedure(this: IProfilerSession; status: IStatus); cdecl; IProfilerSession_finishPtr = procedure(this: IProfilerSession; status: IStatus; timestamp: ISC_TIMESTAMP_TZ); cdecl; - IProfilerSession_defineStatementPtr = procedure(this: IProfilerSession; status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); cdecl; + IProfilerSession_deprecatedDefineStatementPtr = procedure(this: IProfilerSession; status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); cdecl; IProfilerSession_defineCursorPtr = procedure(this: IProfilerSession; statementId: Int64; cursorId: Cardinal; name: PAnsiChar; line: Cardinal; column: Cardinal); cdecl; IProfilerSession_defineRecordSourcePtr = procedure(this: IProfilerSession; statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; level: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); cdecl; IProfilerSession_onRequestStartPtr = procedure(this: IProfilerSession; status: IStatus; statementId: Int64; requestId: Int64; callerStatementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ); cdecl; @@ -750,6 +759,7 @@ type IProfilerSession_afterRecordSourceOpenPtr = procedure(this: IProfilerSession; statementId: Int64; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); cdecl; IProfilerSession_beforeRecordSourceGetRecordPtr = procedure(this: IProfilerSession; statementId: Int64; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); cdecl; IProfilerSession_afterRecordSourceGetRecordPtr = procedure(this: IProfilerSession; statementId: Int64; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); cdecl; + IProfilerSession_defineStatement2Ptr = procedure(this: IProfilerSession; status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; schemaName: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); cdecl; IProfilerStats_getElapsedTicksPtr = function(this: IProfilerStats): QWord; cdecl; VersionedVTable = class @@ -1347,10 +1357,11 @@ type getMessageLength: IMessageMetadata_getMessageLengthPtr; getAlignment: IMessageMetadata_getAlignmentPtr; getAlignedLength: IMessageMetadata_getAlignedLengthPtr; + getSchema: IMessageMetadata_getSchemaPtr; end; IMessageMetadata = class(IReferenceCounted) - const VERSION = 4; + const VERSION = 5; function getCount(status: IStatus): Cardinal; function getField(status: IStatus; index: Cardinal): PAnsiChar; @@ -1369,6 +1380,7 @@ type function getMessageLength(status: IStatus): Cardinal; function getAlignment(status: IStatus): Cardinal; function getAlignedLength(status: IStatus): Cardinal; + function getSchema(status: IStatus; index: Cardinal): PAnsiChar; end; IMessageMetadataImpl = class(IMessageMetadata) @@ -1393,6 +1405,7 @@ type function getMessageLength(status: IStatus): Cardinal; virtual; abstract; function getAlignment(status: IStatus): Cardinal; virtual; abstract; function getAlignedLength(status: IStatus): Cardinal; virtual; abstract; + function getSchema(status: IStatus; index: Cardinal): PAnsiChar; virtual; abstract; end; MetadataBuilderVTable = class(ReferenceCountedVTable) @@ -1410,10 +1423,11 @@ type setRelation: IMetadataBuilder_setRelationPtr; setOwner: IMetadataBuilder_setOwnerPtr; setAlias: IMetadataBuilder_setAliasPtr; + setSchema: IMetadataBuilder_setSchemaPtr; end; IMetadataBuilder = class(IReferenceCounted) - const VERSION = 4; + const VERSION = 5; procedure setType(status: IStatus; index: Cardinal; type_: Cardinal); procedure setSubType(status: IStatus; index: Cardinal; subType: Integer); @@ -1429,6 +1443,7 @@ type procedure setRelation(status: IStatus; index: Cardinal; relation: PAnsiChar); procedure setOwner(status: IStatus; index: Cardinal; owner: PAnsiChar); procedure setAlias(status: IStatus; index: Cardinal; alias: PAnsiChar); + procedure setSchema(status: IStatus; index: Cardinal; schema: PAnsiChar); end; IMetadataBuilderImpl = class(IMetadataBuilder) @@ -1450,6 +1465,7 @@ type procedure setRelation(status: IStatus; index: Cardinal; relation: PAnsiChar); virtual; abstract; procedure setOwner(status: IStatus; index: Cardinal; owner: PAnsiChar); virtual; abstract; procedure setAlias(status: IStatus; index: Cardinal; alias: PAnsiChar); virtual; abstract; + procedure setSchema(status: IStatus; index: Cardinal; schema: PAnsiChar); virtual; abstract; end; ResultSetVTable = class(ReferenceCountedVTable) @@ -2618,10 +2634,11 @@ type getTriggerMetadata: IRoutineMetadata_getTriggerMetadataPtr; getTriggerTable: IRoutineMetadata_getTriggerTablePtr; getTriggerType: IRoutineMetadata_getTriggerTypePtr; + getSchema: IRoutineMetadata_getSchemaPtr; end; IRoutineMetadata = class(IVersioned) - const VERSION = 2; + const VERSION = 3; function getPackage(status: IStatus): PAnsiChar; function getName(status: IStatus): PAnsiChar; @@ -2632,6 +2649,7 @@ type function getTriggerMetadata(status: IStatus): IMessageMetadata; function getTriggerTable(status: IStatus): PAnsiChar; function getTriggerType(status: IStatus): Cardinal; + function getSchema(status: IStatus): PAnsiChar; end; IRoutineMetadataImpl = class(IRoutineMetadata) @@ -2646,6 +2664,7 @@ type function getTriggerMetadata(status: IStatus): IMessageMetadata; virtual; abstract; function getTriggerTable(status: IStatus): PAnsiChar; virtual; abstract; function getTriggerType(status: IStatus): Cardinal; virtual; abstract; + function getSchema(status: IStatus): PAnsiChar; virtual; abstract; end; ExternalEngineVTable = class(PluginBaseVTable) @@ -2759,10 +2778,11 @@ type getInt128: IUtil_getInt128Ptr; decodeTimeTzEx: IUtil_decodeTimeTzExPtr; decodeTimeStampTzEx: IUtil_decodeTimeStampTzExPtr; + executeCreateDatabase2: IUtil_executeCreateDatabase2Ptr; end; IUtil = class(IVersioned) - const VERSION = 4; + const VERSION = 5; procedure getFbVersion(status: IStatus; att: IAttachment; callback: IVersionCallback); procedure loadBlob(status: IStatus; blobId: ISC_QUADPtr; att: IAttachment; tra: ITransaction; file_: PAnsiChar; txt: Boolean); @@ -2786,6 +2806,7 @@ type function getInt128(status: IStatus): IInt128; procedure decodeTimeTzEx(status: IStatus; timeTz: ISC_TIME_TZ_EXPtr; hours: CardinalPtr; minutes: CardinalPtr; seconds: CardinalPtr; fractions: CardinalPtr; timeZoneBufferLength: Cardinal; timeZoneBuffer: PAnsiChar); procedure decodeTimeStampTzEx(status: IStatus; timeStampTz: ISC_TIMESTAMP_TZ_EXPtr; year: CardinalPtr; month: CardinalPtr; day: CardinalPtr; hours: CardinalPtr; minutes: CardinalPtr; seconds: CardinalPtr; fractions: CardinalPtr; timeZoneBufferLength: Cardinal; timeZoneBuffer: PAnsiChar); + function executeCreateDatabase2(status: IStatus; stmtLength: Cardinal; creatDBstatement: PAnsiChar; dialect: Cardinal; dpbLength: Cardinal; dpb: BytePtr; stmtIsCreateDb: BooleanPtr): IAttachment; end; IUtilImpl = class(IUtil) @@ -2813,6 +2834,7 @@ type function getInt128(status: IStatus): IInt128; virtual; abstract; procedure decodeTimeTzEx(status: IStatus; timeTz: ISC_TIME_TZ_EXPtr; hours: CardinalPtr; minutes: CardinalPtr; seconds: CardinalPtr; fractions: CardinalPtr; timeZoneBufferLength: Cardinal; timeZoneBuffer: PAnsiChar); virtual; abstract; procedure decodeTimeStampTzEx(status: IStatus; timeStampTz: ISC_TIMESTAMP_TZ_EXPtr; year: CardinalPtr; month: CardinalPtr; day: CardinalPtr; hours: CardinalPtr; minutes: CardinalPtr; seconds: CardinalPtr; fractions: CardinalPtr; timeZoneBufferLength: Cardinal; timeZoneBuffer: PAnsiChar); virtual; abstract; + function executeCreateDatabase2(status: IStatus; stmtLength: Cardinal; creatDBstatement: PAnsiChar; dialect: Cardinal; dpbLength: Cardinal; dpb: BytePtr; stmtIsCreateDb: BooleanPtr): IAttachment; virtual; abstract; end; OffsetsCallbackVTable = class(VersionedVTable) @@ -3777,15 +3799,19 @@ type startSavepoint: IReplicatedTransaction_startSavepointPtr; releaseSavepoint: IReplicatedTransaction_releaseSavepointPtr; rollbackSavepoint: IReplicatedTransaction_rollbackSavepointPtr; - insertRecord: IReplicatedTransaction_insertRecordPtr; - updateRecord: IReplicatedTransaction_updateRecordPtr; - deleteRecord: IReplicatedTransaction_deleteRecordPtr; - executeSql: IReplicatedTransaction_executeSqlPtr; - executeSqlIntl: IReplicatedTransaction_executeSqlIntlPtr; + deprecatedInsertRecord: IReplicatedTransaction_deprecatedInsertRecordPtr; + deprecatedUpdateRecord: IReplicatedTransaction_deprecatedUpdateRecordPtr; + deprecatedDeleteRecord: IReplicatedTransaction_deprecatedDeleteRecordPtr; + deprecatedExecuteSql: IReplicatedTransaction_deprecatedExecuteSqlPtr; + deprecatedExecuteSqlIntl: IReplicatedTransaction_deprecatedExecuteSqlIntlPtr; + insertRecord2: IReplicatedTransaction_insertRecord2Ptr; + updateRecord2: IReplicatedTransaction_updateRecord2Ptr; + deleteRecord2: IReplicatedTransaction_deleteRecord2Ptr; + executeSqlIntl2: IReplicatedTransaction_executeSqlIntl2Ptr; end; IReplicatedTransaction = class(IDisposable) - const VERSION = 3; + const VERSION = 4; procedure prepare(status: IStatus); procedure commit(status: IStatus); @@ -3793,11 +3819,15 @@ type procedure startSavepoint(status: IStatus); procedure releaseSavepoint(status: IStatus); procedure rollbackSavepoint(status: IStatus); - procedure insertRecord(status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); - procedure updateRecord(status: IStatus; name: PAnsiChar; orgRecord: IReplicatedRecord; newRecord: IReplicatedRecord); - procedure deleteRecord(status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); - procedure executeSql(status: IStatus; sql: PAnsiChar); - procedure executeSqlIntl(status: IStatus; charset: Cardinal; sql: PAnsiChar); + procedure deprecatedInsertRecord(status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); + procedure deprecatedUpdateRecord(status: IStatus; name: PAnsiChar; orgRecord: IReplicatedRecord; newRecord: IReplicatedRecord); + procedure deprecatedDeleteRecord(status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); + procedure deprecatedExecuteSql(status: IStatus; sql: PAnsiChar); + procedure deprecatedExecuteSqlIntl(status: IStatus; charset: Cardinal; sql: PAnsiChar); + procedure insertRecord2(status: IStatus; schemaName: PAnsiChar; tableName: PAnsiChar; record_: IReplicatedRecord); + procedure updateRecord2(status: IStatus; schemaName: PAnsiChar; tableName: PAnsiChar; orgRecord: IReplicatedRecord; newRecord: IReplicatedRecord); + procedure deleteRecord2(status: IStatus; schemaName: PAnsiChar; tableName: PAnsiChar; record_: IReplicatedRecord); + procedure executeSqlIntl2(status: IStatus; charset: Cardinal; schemaSearchPath: PAnsiChar; sql: PAnsiChar); end; IReplicatedTransactionImpl = class(IReplicatedTransaction) @@ -3810,27 +3840,33 @@ type procedure startSavepoint(status: IStatus); virtual; abstract; procedure releaseSavepoint(status: IStatus); virtual; abstract; procedure rollbackSavepoint(status: IStatus); virtual; abstract; - procedure insertRecord(status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); virtual; abstract; - procedure updateRecord(status: IStatus; name: PAnsiChar; orgRecord: IReplicatedRecord; newRecord: IReplicatedRecord); virtual; abstract; - procedure deleteRecord(status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); virtual; abstract; - procedure executeSql(status: IStatus; sql: PAnsiChar); virtual; abstract; - procedure executeSqlIntl(status: IStatus; charset: Cardinal; sql: PAnsiChar); virtual; abstract; + procedure deprecatedInsertRecord(status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); virtual; abstract; + procedure deprecatedUpdateRecord(status: IStatus; name: PAnsiChar; orgRecord: IReplicatedRecord; newRecord: IReplicatedRecord); virtual; abstract; + procedure deprecatedDeleteRecord(status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); virtual; abstract; + procedure deprecatedExecuteSql(status: IStatus; sql: PAnsiChar); virtual; abstract; + procedure deprecatedExecuteSqlIntl(status: IStatus; charset: Cardinal; sql: PAnsiChar); virtual; abstract; + procedure insertRecord2(status: IStatus; schemaName: PAnsiChar; tableName: PAnsiChar; record_: IReplicatedRecord); virtual; abstract; + procedure updateRecord2(status: IStatus; schemaName: PAnsiChar; tableName: PAnsiChar; orgRecord: IReplicatedRecord; newRecord: IReplicatedRecord); virtual; abstract; + procedure deleteRecord2(status: IStatus; schemaName: PAnsiChar; tableName: PAnsiChar; record_: IReplicatedRecord); virtual; abstract; + procedure executeSqlIntl2(status: IStatus; charset: Cardinal; schemaSearchPath: PAnsiChar; sql: PAnsiChar); virtual; abstract; end; ReplicatedSessionVTable = class(PluginBaseVTable) init: IReplicatedSession_initPtr; startTransaction: IReplicatedSession_startTransactionPtr; cleanupTransaction: IReplicatedSession_cleanupTransactionPtr; - setSequence: IReplicatedSession_setSequencePtr; + deprecatedSetSequence: IReplicatedSession_deprecatedSetSequencePtr; + setSequence2: IReplicatedSession_setSequence2Ptr; end; IReplicatedSession = class(IPluginBase) - const VERSION = 4; + const VERSION = 5; function init(status: IStatus; attachment: IAttachment): Boolean; function startTransaction(status: IStatus; transaction: ITransaction; number: Int64): IReplicatedTransaction; procedure cleanupTransaction(status: IStatus; number: Int64); - procedure setSequence(status: IStatus; name: PAnsiChar; value: Int64); + procedure deprecatedSetSequence(status: IStatus; name: PAnsiChar; value: Int64); + procedure setSequence2(status: IStatus; schemaName: PAnsiChar; genName: PAnsiChar; value: Int64); end; IReplicatedSessionImpl = class(IReplicatedSession) @@ -3843,7 +3879,8 @@ type function init(status: IStatus; attachment: IAttachment): Boolean; virtual; abstract; function startTransaction(status: IStatus; transaction: ITransaction; number: Int64): IReplicatedTransaction; virtual; abstract; procedure cleanupTransaction(status: IStatus; number: Int64); virtual; abstract; - procedure setSequence(status: IStatus; name: PAnsiChar; value: Int64); virtual; abstract; + procedure deprecatedSetSequence(status: IStatus; name: PAnsiChar; value: Int64); virtual; abstract; + procedure setSequence2(status: IStatus; schemaName: PAnsiChar; genName: PAnsiChar; value: Int64); virtual; abstract; end; ProfilerPluginVTable = class(PluginBaseVTable) @@ -3877,7 +3914,7 @@ type getFlags: IProfilerSession_getFlagsPtr; cancel: IProfilerSession_cancelPtr; finish: IProfilerSession_finishPtr; - defineStatement: IProfilerSession_defineStatementPtr; + deprecatedDefineStatement: IProfilerSession_deprecatedDefineStatementPtr; defineCursor: IProfilerSession_defineCursorPtr; defineRecordSource: IProfilerSession_defineRecordSourcePtr; onRequestStart: IProfilerSession_onRequestStartPtr; @@ -3888,10 +3925,11 @@ type afterRecordSourceOpen: IProfilerSession_afterRecordSourceOpenPtr; beforeRecordSourceGetRecord: IProfilerSession_beforeRecordSourceGetRecordPtr; afterRecordSourceGetRecord: IProfilerSession_afterRecordSourceGetRecordPtr; + defineStatement2: IProfilerSession_defineStatement2Ptr; end; IProfilerSession = class(IDisposable) - const VERSION = 3; + const VERSION = 4; const FLAG_BEFORE_EVENTS = Cardinal($1); const FLAG_AFTER_EVENTS = Cardinal($2); @@ -3899,7 +3937,7 @@ type function getFlags(): Cardinal; procedure cancel(status: IStatus); procedure finish(status: IStatus; timestamp: ISC_TIMESTAMP_TZ); - procedure defineStatement(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); + procedure deprecatedDefineStatement(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); procedure defineCursor(statementId: Int64; cursorId: Cardinal; name: PAnsiChar; line: Cardinal; column: Cardinal); procedure defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; level: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); procedure onRequestStart(status: IStatus; statementId: Int64; requestId: Int64; callerStatementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ); @@ -3910,6 +3948,7 @@ type procedure afterRecordSourceOpen(statementId: Int64; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); procedure beforeRecordSourceGetRecord(statementId: Int64; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); procedure afterRecordSourceGetRecord(statementId: Int64; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); + procedure defineStatement2(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; schemaName: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); end; IProfilerSessionImpl = class(IProfilerSession) @@ -3920,7 +3959,7 @@ type function getFlags(): Cardinal; virtual; abstract; procedure cancel(status: IStatus); virtual; abstract; procedure finish(status: IStatus; timestamp: ISC_TIMESTAMP_TZ); virtual; abstract; - procedure defineStatement(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); virtual; abstract; + procedure deprecatedDefineStatement(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); virtual; abstract; procedure defineCursor(statementId: Int64; cursorId: Cardinal; name: PAnsiChar; line: Cardinal; column: Cardinal); virtual; abstract; procedure defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; level: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); virtual; abstract; procedure onRequestStart(status: IStatus; statementId: Int64; requestId: Int64; callerStatementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ); virtual; abstract; @@ -3931,6 +3970,7 @@ type procedure afterRecordSourceOpen(statementId: Int64; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); virtual; abstract; procedure beforeRecordSourceGetRecord(statementId: Int64; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); virtual; abstract; procedure afterRecordSourceGetRecord(statementId: Int64; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); virtual; abstract; + procedure defineStatement2(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; schemaName: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); virtual; abstract; end; ProfilerStatsVTable = class(VersionedVTable) @@ -4057,6 +4097,9 @@ const isc_dpb_parallel_workers = byte(100); isc_dpb_worker_attach = byte(101); isc_dpb_owner = byte(102); + isc_dpb_search_path = byte(103); + isc_dpb_blr_request_search_path = byte(104); + isc_dpb_gbak_restore_has_schema = byte(105); isc_dpb_address = byte(1); isc_dpb_addr_protocol = byte(1); isc_dpb_addr_endpoint = byte(2); @@ -4215,6 +4258,8 @@ const isc_spb_bkp_crypt = byte(18); isc_spb_bkp_include_data = byte(19); isc_spb_bkp_parallel_workers = byte(21); + isc_spb_bkp_skip_schema_data = byte(22); + isc_spb_bkp_include_schema_data = byte(23); isc_spb_bkp_ignore_checksums = $01; isc_spb_bkp_ignore_limbo = $02; isc_spb_bkp_metadata_only = $04; @@ -4311,6 +4356,8 @@ const isc_spb_val_idx_incl = byte(3); isc_spb_val_idx_excl = byte(4); isc_spb_val_lock_timeout = byte(5); + isc_spb_val_sch_incl = byte(6); + isc_spb_val_sch_excl = byte(7); isc_spb_num_att = byte(5); isc_spb_num_db = byte(6); isc_spb_sts_table = byte(64); @@ -4358,6 +4405,7 @@ const isc_sdl_do2 = byte(34); isc_sdl_do1 = byte(35); isc_sdl_element = byte(36); + isc_sdl_schema = byte(37); isc_blob_untyped = byte(0); isc_blob_text = byte(1); isc_blob_blr = byte(2); @@ -4727,6 +4775,7 @@ const isc_info_sql_stmt_blob_align = byte(30); isc_info_sql_exec_path_blr_bytes = byte(31); isc_info_sql_exec_path_blr_text = byte(32); + isc_info_sql_relation_schema = byte(33); isc_info_sql_stmt_select = byte(1); isc_info_sql_stmt_insert = byte(2); isc_info_sql_stmt_update = byte(3); @@ -5741,6 +5790,8 @@ const isc_only_one_pattern_can_be_used = 335545305; isc_can_not_use_same_pattern_twice = 335545306; isc_sysf_invalid_gen_uuid_version = 335545307; + isc_invalid_name = 335545308; + isc_invalid_unqualified_name_list = 335545309; isc_gfix_db_name = 335740929; isc_gfix_invalid_sw = 335740930; isc_gfix_incmp_sw = 335740932; @@ -5897,6 +5948,13 @@ const isc_dyn_exc_not_exist = 336068915; isc_dyn_gen_not_exist = 336068916; isc_dyn_fld_not_exist = 336068917; + isc_dyn_index_schema_must_match_table = 336068922; + isc_dyn_trig_schema_must_match_table = 336068923; + isc_dyn_cannot_mod_system_schema = 336068925; + isc_dyn_cannot_drop_non_emptyschema = 336068926; + isc_dyn_cannot_mod_obj_sys_schema = 336068927; + isc_dyn_cannot_create_reserved_schema = 336068928; + isc_dyn_cannot_infer_schema = 336068929; isc_gbak_unknown_switch = 336330753; isc_gbak_page_size_missing = 336330754; isc_gbak_page_size_toobig = 336330755; @@ -6125,6 +6183,11 @@ const isc_dsql_string_char_length = 336397332; isc_dsql_max_nesting = 336397333; isc_dsql_recreate_user_failed = 336397334; + isc_dsql_create_schema_failed = 336397335; + isc_dsql_drop_schema_failed = 336397336; + isc_dsql_recreate_schema_failed = 336397337; + isc_dsql_alter_schema_failed = 336397338; + isc_dsql_create_alter_schema_failed = 336397339; isc_gsec_cant_open_db = 336723983; isc_gsec_switches_error = 336723984; isc_gsec_no_op_spec = 336723985; @@ -6907,6 +6970,18 @@ begin FbException.checkException(status); end; +function IMessageMetadata.getSchema(status: IStatus; index: Cardinal): PAnsiChar; +begin + if (vTable.version < 5) then begin + FbException.setVersionError(status, 'IMessageMetadata', vTable.version, 5); + Result := nil; + end + else begin + Result := MessageMetadataVTable(vTable).getSchema(Self, status, index); + end; + FbException.checkException(status); +end; + procedure IMetadataBuilder.setType(status: IStatus; index: Cardinal; type_: Cardinal); begin MetadataBuilderVTable(vTable).setType(Self, status, index, type_); @@ -7011,6 +7086,17 @@ begin FbException.checkException(status); end; +procedure IMetadataBuilder.setSchema(status: IStatus; index: Cardinal; schema: PAnsiChar); +begin + if (vTable.version < 5) then begin + FbException.setVersionError(status, 'IMetadataBuilder', vTable.version, 5); + end + else begin + MetadataBuilderVTable(vTable).setSchema(Self, status, index, schema); + end; + FbException.checkException(status); +end; + function IResultSet.fetchNext(status: IStatus; message: Pointer): Integer; begin Result := ResultSetVTable(vTable).fetchNext(Self, status, message); @@ -8371,6 +8457,18 @@ begin FbException.checkException(status); end; +function IRoutineMetadata.getSchema(status: IStatus): PAnsiChar; +begin + if (vTable.version < 3) then begin + FbException.setVersionError(status, 'IRoutineMetadata', vTable.version, 3); + Result := nil; + end + else begin + Result := RoutineMetadataVTable(vTable).getSchema(Self, status); + end; + FbException.checkException(status); +end; + procedure IExternalEngine.open(status: IStatus; context: IExternalContext; charSet: PAnsiChar; charSetSize: Cardinal); begin ExternalEngineVTable(vTable).open(Self, status, context, charSet, charSetSize); @@ -8604,6 +8702,18 @@ begin FbException.checkException(status); end; +function IUtil.executeCreateDatabase2(status: IStatus; stmtLength: Cardinal; creatDBstatement: PAnsiChar; dialect: Cardinal; dpbLength: Cardinal; dpb: BytePtr; stmtIsCreateDb: BooleanPtr): IAttachment; +begin + if (vTable.version < 5) then begin + FbException.setVersionError(status, 'IUtil', vTable.version, 5); + Result := nil; + end + else begin + Result := UtilVTable(vTable).executeCreateDatabase2(Self, status, stmtLength, creatDBstatement, dialect, dpbLength, dpb, stmtIsCreateDb); + end; + FbException.checkException(status); +end; + procedure IOffsetsCallback.setOffset(status: IStatus; index: Cardinal; offset: Cardinal; nullOffset: Cardinal); begin OffsetsCallbackVTable(vTable).setOffset(Self, status, index, offset, nullOffset); @@ -9556,33 +9666,77 @@ begin FbException.checkException(status); end; -procedure IReplicatedTransaction.insertRecord(status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); +procedure IReplicatedTransaction.deprecatedInsertRecord(status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); begin - ReplicatedTransactionVTable(vTable).insertRecord(Self, status, name, record_); + ReplicatedTransactionVTable(vTable).deprecatedInsertRecord(Self, status, name, record_); FbException.checkException(status); end; -procedure IReplicatedTransaction.updateRecord(status: IStatus; name: PAnsiChar; orgRecord: IReplicatedRecord; newRecord: IReplicatedRecord); +procedure IReplicatedTransaction.deprecatedUpdateRecord(status: IStatus; name: PAnsiChar; orgRecord: IReplicatedRecord; newRecord: IReplicatedRecord); begin - ReplicatedTransactionVTable(vTable).updateRecord(Self, status, name, orgRecord, newRecord); + ReplicatedTransactionVTable(vTable).deprecatedUpdateRecord(Self, status, name, orgRecord, newRecord); FbException.checkException(status); end; -procedure IReplicatedTransaction.deleteRecord(status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); +procedure IReplicatedTransaction.deprecatedDeleteRecord(status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); begin - ReplicatedTransactionVTable(vTable).deleteRecord(Self, status, name, record_); + ReplicatedTransactionVTable(vTable).deprecatedDeleteRecord(Self, status, name, record_); FbException.checkException(status); end; -procedure IReplicatedTransaction.executeSql(status: IStatus; sql: PAnsiChar); +procedure IReplicatedTransaction.deprecatedExecuteSql(status: IStatus; sql: PAnsiChar); begin - ReplicatedTransactionVTable(vTable).executeSql(Self, status, sql); + ReplicatedTransactionVTable(vTable).deprecatedExecuteSql(Self, status, sql); FbException.checkException(status); end; -procedure IReplicatedTransaction.executeSqlIntl(status: IStatus; charset: Cardinal; sql: PAnsiChar); +procedure IReplicatedTransaction.deprecatedExecuteSqlIntl(status: IStatus; charset: Cardinal; sql: PAnsiChar); begin - ReplicatedTransactionVTable(vTable).executeSqlIntl(Self, status, charset, sql); + ReplicatedTransactionVTable(vTable).deprecatedExecuteSqlIntl(Self, status, charset, sql); + FbException.checkException(status); +end; + +procedure IReplicatedTransaction.insertRecord2(status: IStatus; schemaName: PAnsiChar; tableName: PAnsiChar; record_: IReplicatedRecord); +begin + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IReplicatedTransaction', vTable.version, 4); + end + else begin + ReplicatedTransactionVTable(vTable).insertRecord2(Self, status, schemaName, tableName, record_); + end; + FbException.checkException(status); +end; + +procedure IReplicatedTransaction.updateRecord2(status: IStatus; schemaName: PAnsiChar; tableName: PAnsiChar; orgRecord: IReplicatedRecord; newRecord: IReplicatedRecord); +begin + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IReplicatedTransaction', vTable.version, 4); + end + else begin + ReplicatedTransactionVTable(vTable).updateRecord2(Self, status, schemaName, tableName, orgRecord, newRecord); + end; + FbException.checkException(status); +end; + +procedure IReplicatedTransaction.deleteRecord2(status: IStatus; schemaName: PAnsiChar; tableName: PAnsiChar; record_: IReplicatedRecord); +begin + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IReplicatedTransaction', vTable.version, 4); + end + else begin + ReplicatedTransactionVTable(vTable).deleteRecord2(Self, status, schemaName, tableName, record_); + end; + FbException.checkException(status); +end; + +procedure IReplicatedTransaction.executeSqlIntl2(status: IStatus; charset: Cardinal; schemaSearchPath: PAnsiChar; sql: PAnsiChar); +begin + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IReplicatedTransaction', vTable.version, 4); + end + else begin + ReplicatedTransactionVTable(vTable).executeSqlIntl2(Self, status, charset, schemaSearchPath, sql); + end; FbException.checkException(status); end; @@ -9604,9 +9758,20 @@ begin FbException.checkException(status); end; -procedure IReplicatedSession.setSequence(status: IStatus; name: PAnsiChar; value: Int64); +procedure IReplicatedSession.deprecatedSetSequence(status: IStatus; name: PAnsiChar; value: Int64); begin - ReplicatedSessionVTable(vTable).setSequence(Self, status, name, value); + ReplicatedSessionVTable(vTable).deprecatedSetSequence(Self, status, name, value); + FbException.checkException(status); +end; + +procedure IReplicatedSession.setSequence2(status: IStatus; schemaName: PAnsiChar; genName: PAnsiChar; value: Int64); +begin + if (vTable.version < 5) then begin + FbException.setVersionError(status, 'IReplicatedSession', vTable.version, 5); + end + else begin + ReplicatedSessionVTable(vTable).setSequence2(Self, status, schemaName, genName, value); + end; FbException.checkException(status); end; @@ -9650,9 +9815,9 @@ begin FbException.checkException(status); end; -procedure IProfilerSession.defineStatement(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); +procedure IProfilerSession.deprecatedDefineStatement(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); begin - ProfilerSessionVTable(vTable).defineStatement(Self, status, statementId, parentStatementId, type_, packageName, routineName, sqlText); + ProfilerSessionVTable(vTable).deprecatedDefineStatement(Self, status, statementId, parentStatementId, type_, packageName, routineName, sqlText); FbException.checkException(status); end; @@ -9708,6 +9873,17 @@ begin ProfilerSessionVTable(vTable).afterRecordSourceGetRecord(Self, statementId, requestId, cursorId, recSourceId, stats); end; +procedure IProfilerSession.defineStatement2(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; schemaName: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); +begin + if (vTable.version < 4) then begin + deprecatedDefineStatement(status, statementId, parentStatementId, type, packageName, routineName, sqlText); + end + else begin + ProfilerSessionVTable(vTable).defineStatement2(Self, status, statementId, parentStatementId, type_, schemaName, packageName, routineName, sqlText); + end; + FbException.checkException(status); +end; + function IProfilerStats.getElapsedTicks(): QWord; begin Result := ProfilerStatsVTable(vTable).getElapsedTicks(Self); @@ -11098,6 +11274,16 @@ begin end end; +function IMessageMetadataImpl_getSchemaDispatcher(this: IMessageMetadata; status: IStatus; index: Cardinal): PAnsiChar; cdecl; +begin + Result := nil; + try + Result := IMessageMetadataImpl(this).getSchema(status, index); + except + on e: Exception do FbException.catchException(status, e); + end +end; + var IMessageMetadataImpl_vTable: MessageMetadataVTable; @@ -11253,6 +11439,15 @@ begin end end; +procedure IMetadataBuilderImpl_setSchemaDispatcher(this: IMetadataBuilder; status: IStatus; index: Cardinal; schema: PAnsiChar); cdecl; +begin + try + IMetadataBuilderImpl(this).setSchema(status, index, schema); + except + on e: Exception do FbException.catchException(status, e); + end +end; + var IMetadataBuilderImpl_vTable: MetadataBuilderVTable; @@ -14051,6 +14246,16 @@ begin end end; +function IRoutineMetadataImpl_getSchemaDispatcher(this: IRoutineMetadata; status: IStatus): PAnsiChar; cdecl; +begin + Result := nil; + try + Result := IRoutineMetadataImpl(this).getSchema(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + var IRoutineMetadataImpl_vTable: RoutineMetadataVTable; @@ -14449,6 +14654,16 @@ begin end end; +function IUtilImpl_executeCreateDatabase2Dispatcher(this: IUtil; status: IStatus; stmtLength: Cardinal; creatDBstatement: PAnsiChar; dialect: Cardinal; dpbLength: Cardinal; dpb: BytePtr; stmtIsCreateDb: BooleanPtr): IAttachment; cdecl; +begin + Result := nil; + try + Result := IUtilImpl(this).executeCreateDatabase2(status, stmtLength, creatDBstatement, dialect, dpbLength, dpb, stmtIsCreateDb); + except + on e: Exception do FbException.catchException(status, e); + end +end; + var IUtilImpl_vTable: UtilVTable; @@ -16646,46 +16861,82 @@ begin end end; -procedure IReplicatedTransactionImpl_insertRecordDispatcher(this: IReplicatedTransaction; status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); cdecl; +procedure IReplicatedTransactionImpl_deprecatedInsertRecordDispatcher(this: IReplicatedTransaction; status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); cdecl; begin try - IReplicatedTransactionImpl(this).insertRecord(status, name, record_); + IReplicatedTransactionImpl(this).deprecatedInsertRecord(status, name, record_); except on e: Exception do FbException.catchException(status, e); end end; -procedure IReplicatedTransactionImpl_updateRecordDispatcher(this: IReplicatedTransaction; status: IStatus; name: PAnsiChar; orgRecord: IReplicatedRecord; newRecord: IReplicatedRecord); cdecl; +procedure IReplicatedTransactionImpl_deprecatedUpdateRecordDispatcher(this: IReplicatedTransaction; status: IStatus; name: PAnsiChar; orgRecord: IReplicatedRecord; newRecord: IReplicatedRecord); cdecl; begin try - IReplicatedTransactionImpl(this).updateRecord(status, name, orgRecord, newRecord); + IReplicatedTransactionImpl(this).deprecatedUpdateRecord(status, name, orgRecord, newRecord); except on e: Exception do FbException.catchException(status, e); end end; -procedure IReplicatedTransactionImpl_deleteRecordDispatcher(this: IReplicatedTransaction; status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); cdecl; +procedure IReplicatedTransactionImpl_deprecatedDeleteRecordDispatcher(this: IReplicatedTransaction; status: IStatus; name: PAnsiChar; record_: IReplicatedRecord); cdecl; begin try - IReplicatedTransactionImpl(this).deleteRecord(status, name, record_); + IReplicatedTransactionImpl(this).deprecatedDeleteRecord(status, name, record_); except on e: Exception do FbException.catchException(status, e); end end; -procedure IReplicatedTransactionImpl_executeSqlDispatcher(this: IReplicatedTransaction; status: IStatus; sql: PAnsiChar); cdecl; +procedure IReplicatedTransactionImpl_deprecatedExecuteSqlDispatcher(this: IReplicatedTransaction; status: IStatus; sql: PAnsiChar); cdecl; begin try - IReplicatedTransactionImpl(this).executeSql(status, sql); + IReplicatedTransactionImpl(this).deprecatedExecuteSql(status, sql); except on e: Exception do FbException.catchException(status, e); end end; -procedure IReplicatedTransactionImpl_executeSqlIntlDispatcher(this: IReplicatedTransaction; status: IStatus; charset: Cardinal; sql: PAnsiChar); cdecl; +procedure IReplicatedTransactionImpl_deprecatedExecuteSqlIntlDispatcher(this: IReplicatedTransaction; status: IStatus; charset: Cardinal; sql: PAnsiChar); cdecl; begin try - IReplicatedTransactionImpl(this).executeSqlIntl(status, charset, sql); + IReplicatedTransactionImpl(this).deprecatedExecuteSqlIntl(status, charset, sql); + except + on e: Exception do FbException.catchException(status, e); + end +end; + +procedure IReplicatedTransactionImpl_insertRecord2Dispatcher(this: IReplicatedTransaction; status: IStatus; schemaName: PAnsiChar; tableName: PAnsiChar; record_: IReplicatedRecord); cdecl; +begin + try + IReplicatedTransactionImpl(this).insertRecord2(status, schemaName, tableName, record_); + except + on e: Exception do FbException.catchException(status, e); + end +end; + +procedure IReplicatedTransactionImpl_updateRecord2Dispatcher(this: IReplicatedTransaction; status: IStatus; schemaName: PAnsiChar; tableName: PAnsiChar; orgRecord: IReplicatedRecord; newRecord: IReplicatedRecord); cdecl; +begin + try + IReplicatedTransactionImpl(this).updateRecord2(status, schemaName, tableName, orgRecord, newRecord); + except + on e: Exception do FbException.catchException(status, e); + end +end; + +procedure IReplicatedTransactionImpl_deleteRecord2Dispatcher(this: IReplicatedTransaction; status: IStatus; schemaName: PAnsiChar; tableName: PAnsiChar; record_: IReplicatedRecord); cdecl; +begin + try + IReplicatedTransactionImpl(this).deleteRecord2(status, schemaName, tableName, record_); + except + on e: Exception do FbException.catchException(status, e); + end +end; + +procedure IReplicatedTransactionImpl_executeSqlIntl2Dispatcher(this: IReplicatedTransaction; status: IStatus; charset: Cardinal; schemaSearchPath: PAnsiChar; sql: PAnsiChar); cdecl; +begin + try + IReplicatedTransactionImpl(this).executeSqlIntl2(status, charset, schemaSearchPath, sql); except on e: Exception do FbException.catchException(status, e); end @@ -16766,10 +17017,19 @@ begin end end; -procedure IReplicatedSessionImpl_setSequenceDispatcher(this: IReplicatedSession; status: IStatus; name: PAnsiChar; value: Int64); cdecl; +procedure IReplicatedSessionImpl_deprecatedSetSequenceDispatcher(this: IReplicatedSession; status: IStatus; name: PAnsiChar; value: Int64); cdecl; begin try - IReplicatedSessionImpl(this).setSequence(status, name, value); + IReplicatedSessionImpl(this).deprecatedSetSequence(status, name, value); + except + on e: Exception do FbException.catchException(status, e); + end +end; + +procedure IReplicatedSessionImpl_setSequence2Dispatcher(this: IReplicatedSession; status: IStatus; schemaName: PAnsiChar; genName: PAnsiChar; value: Int64); cdecl; +begin + try + IReplicatedSessionImpl(this).setSequence2(status, schemaName, genName, value); except on e: Exception do FbException.catchException(status, e); end @@ -16904,10 +17164,10 @@ begin end end; -procedure IProfilerSessionImpl_defineStatementDispatcher(this: IProfilerSession; status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); cdecl; +procedure IProfilerSessionImpl_deprecatedDefineStatementDispatcher(this: IProfilerSession; status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); cdecl; begin try - IProfilerSessionImpl(this).defineStatement(status, statementId, parentStatementId, type_, packageName, routineName, sqlText); + IProfilerSessionImpl(this).deprecatedDefineStatement(status, statementId, parentStatementId, type_, packageName, routineName, sqlText); except on e: Exception do FbException.catchException(status, e); end @@ -17003,6 +17263,15 @@ begin end end; +procedure IProfilerSessionImpl_defineStatement2Dispatcher(this: IProfilerSession; status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; schemaName: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); cdecl; +begin + try + IProfilerSessionImpl(this).defineStatement2(status, statementId, parentStatementId, type_, schemaName, packageName, routineName, sqlText); + except + on e: Exception do FbException.catchException(status, e); + end +end; + var IProfilerSessionImpl_vTable: ProfilerSessionVTable; @@ -17261,7 +17530,7 @@ initialization ITransactionImpl_vTable.disconnect := @ITransactionImpl_disconnectDispatcher; IMessageMetadataImpl_vTable := MessageMetadataVTable.create; - IMessageMetadataImpl_vTable.version := 4; + IMessageMetadataImpl_vTable.version := 5; IMessageMetadataImpl_vTable.addRef := @IMessageMetadataImpl_addRefDispatcher; IMessageMetadataImpl_vTable.release := @IMessageMetadataImpl_releaseDispatcher; IMessageMetadataImpl_vTable.getCount := @IMessageMetadataImpl_getCountDispatcher; @@ -17281,9 +17550,10 @@ initialization IMessageMetadataImpl_vTable.getMessageLength := @IMessageMetadataImpl_getMessageLengthDispatcher; IMessageMetadataImpl_vTable.getAlignment := @IMessageMetadataImpl_getAlignmentDispatcher; IMessageMetadataImpl_vTable.getAlignedLength := @IMessageMetadataImpl_getAlignedLengthDispatcher; + IMessageMetadataImpl_vTable.getSchema := @IMessageMetadataImpl_getSchemaDispatcher; IMetadataBuilderImpl_vTable := MetadataBuilderVTable.create; - IMetadataBuilderImpl_vTable.version := 4; + IMetadataBuilderImpl_vTable.version := 5; IMetadataBuilderImpl_vTable.addRef := @IMetadataBuilderImpl_addRefDispatcher; IMetadataBuilderImpl_vTable.release := @IMetadataBuilderImpl_releaseDispatcher; IMetadataBuilderImpl_vTable.setType := @IMetadataBuilderImpl_setTypeDispatcher; @@ -17300,6 +17570,7 @@ initialization IMetadataBuilderImpl_vTable.setRelation := @IMetadataBuilderImpl_setRelationDispatcher; IMetadataBuilderImpl_vTable.setOwner := @IMetadataBuilderImpl_setOwnerDispatcher; IMetadataBuilderImpl_vTable.setAlias := @IMetadataBuilderImpl_setAliasDispatcher; + IMetadataBuilderImpl_vTable.setSchema := @IMetadataBuilderImpl_setSchemaDispatcher; IResultSetImpl_vTable := ResultSetVTable.create; IResultSetImpl_vTable.version := 5; @@ -17662,7 +17933,7 @@ initialization IExternalTriggerImpl_vTable.execute := @IExternalTriggerImpl_executeDispatcher; IRoutineMetadataImpl_vTable := RoutineMetadataVTable.create; - IRoutineMetadataImpl_vTable.version := 2; + IRoutineMetadataImpl_vTable.version := 3; IRoutineMetadataImpl_vTable.getPackage := @IRoutineMetadataImpl_getPackageDispatcher; IRoutineMetadataImpl_vTable.getName := @IRoutineMetadataImpl_getNameDispatcher; IRoutineMetadataImpl_vTable.getEntryPoint := @IRoutineMetadataImpl_getEntryPointDispatcher; @@ -17672,6 +17943,7 @@ initialization IRoutineMetadataImpl_vTable.getTriggerMetadata := @IRoutineMetadataImpl_getTriggerMetadataDispatcher; IRoutineMetadataImpl_vTable.getTriggerTable := @IRoutineMetadataImpl_getTriggerTableDispatcher; IRoutineMetadataImpl_vTable.getTriggerType := @IRoutineMetadataImpl_getTriggerTypeDispatcher; + IRoutineMetadataImpl_vTable.getSchema := @IRoutineMetadataImpl_getSchemaDispatcher; IExternalEngineImpl_vTable := ExternalEngineVTable.create; IExternalEngineImpl_vTable.version := 4; @@ -17702,7 +17974,7 @@ initialization IVersionCallbackImpl_vTable.callback := @IVersionCallbackImpl_callbackDispatcher; IUtilImpl_vTable := UtilVTable.create; - IUtilImpl_vTable.version := 4; + IUtilImpl_vTable.version := 5; IUtilImpl_vTable.getFbVersion := @IUtilImpl_getFbVersionDispatcher; IUtilImpl_vTable.loadBlob := @IUtilImpl_loadBlobDispatcher; IUtilImpl_vTable.dumpBlob := @IUtilImpl_dumpBlobDispatcher; @@ -17725,6 +17997,7 @@ initialization IUtilImpl_vTable.getInt128 := @IUtilImpl_getInt128Dispatcher; IUtilImpl_vTable.decodeTimeTzEx := @IUtilImpl_decodeTimeTzExDispatcher; IUtilImpl_vTable.decodeTimeStampTzEx := @IUtilImpl_decodeTimeStampTzExDispatcher; + IUtilImpl_vTable.executeCreateDatabase2 := @IUtilImpl_executeCreateDatabase2Dispatcher; IOffsetsCallbackImpl_vTable := OffsetsCallbackVTable.create; IOffsetsCallbackImpl_vTable.version := 2; @@ -18009,7 +18282,7 @@ initialization IReplicatedRecordImpl_vTable.getRawData := @IReplicatedRecordImpl_getRawDataDispatcher; IReplicatedTransactionImpl_vTable := ReplicatedTransactionVTable.create; - IReplicatedTransactionImpl_vTable.version := 3; + IReplicatedTransactionImpl_vTable.version := 4; IReplicatedTransactionImpl_vTable.dispose := @IReplicatedTransactionImpl_disposeDispatcher; IReplicatedTransactionImpl_vTable.prepare := @IReplicatedTransactionImpl_prepareDispatcher; IReplicatedTransactionImpl_vTable.commit := @IReplicatedTransactionImpl_commitDispatcher; @@ -18017,14 +18290,18 @@ initialization IReplicatedTransactionImpl_vTable.startSavepoint := @IReplicatedTransactionImpl_startSavepointDispatcher; IReplicatedTransactionImpl_vTable.releaseSavepoint := @IReplicatedTransactionImpl_releaseSavepointDispatcher; IReplicatedTransactionImpl_vTable.rollbackSavepoint := @IReplicatedTransactionImpl_rollbackSavepointDispatcher; - IReplicatedTransactionImpl_vTable.insertRecord := @IReplicatedTransactionImpl_insertRecordDispatcher; - IReplicatedTransactionImpl_vTable.updateRecord := @IReplicatedTransactionImpl_updateRecordDispatcher; - IReplicatedTransactionImpl_vTable.deleteRecord := @IReplicatedTransactionImpl_deleteRecordDispatcher; - IReplicatedTransactionImpl_vTable.executeSql := @IReplicatedTransactionImpl_executeSqlDispatcher; - IReplicatedTransactionImpl_vTable.executeSqlIntl := @IReplicatedTransactionImpl_executeSqlIntlDispatcher; + IReplicatedTransactionImpl_vTable.deprecatedInsertRecord := @IReplicatedTransactionImpl_deprecatedInsertRecordDispatcher; + IReplicatedTransactionImpl_vTable.deprecatedUpdateRecord := @IReplicatedTransactionImpl_deprecatedUpdateRecordDispatcher; + IReplicatedTransactionImpl_vTable.deprecatedDeleteRecord := @IReplicatedTransactionImpl_deprecatedDeleteRecordDispatcher; + IReplicatedTransactionImpl_vTable.deprecatedExecuteSql := @IReplicatedTransactionImpl_deprecatedExecuteSqlDispatcher; + IReplicatedTransactionImpl_vTable.deprecatedExecuteSqlIntl := @IReplicatedTransactionImpl_deprecatedExecuteSqlIntlDispatcher; + IReplicatedTransactionImpl_vTable.insertRecord2 := @IReplicatedTransactionImpl_insertRecord2Dispatcher; + IReplicatedTransactionImpl_vTable.updateRecord2 := @IReplicatedTransactionImpl_updateRecord2Dispatcher; + IReplicatedTransactionImpl_vTable.deleteRecord2 := @IReplicatedTransactionImpl_deleteRecord2Dispatcher; + IReplicatedTransactionImpl_vTable.executeSqlIntl2 := @IReplicatedTransactionImpl_executeSqlIntl2Dispatcher; IReplicatedSessionImpl_vTable := ReplicatedSessionVTable.create; - IReplicatedSessionImpl_vTable.version := 4; + IReplicatedSessionImpl_vTable.version := 5; IReplicatedSessionImpl_vTable.addRef := @IReplicatedSessionImpl_addRefDispatcher; IReplicatedSessionImpl_vTable.release := @IReplicatedSessionImpl_releaseDispatcher; IReplicatedSessionImpl_vTable.setOwner := @IReplicatedSessionImpl_setOwnerDispatcher; @@ -18032,7 +18309,8 @@ initialization IReplicatedSessionImpl_vTable.init := @IReplicatedSessionImpl_initDispatcher; IReplicatedSessionImpl_vTable.startTransaction := @IReplicatedSessionImpl_startTransactionDispatcher; IReplicatedSessionImpl_vTable.cleanupTransaction := @IReplicatedSessionImpl_cleanupTransactionDispatcher; - IReplicatedSessionImpl_vTable.setSequence := @IReplicatedSessionImpl_setSequenceDispatcher; + IReplicatedSessionImpl_vTable.deprecatedSetSequence := @IReplicatedSessionImpl_deprecatedSetSequenceDispatcher; + IReplicatedSessionImpl_vTable.setSequence2 := @IReplicatedSessionImpl_setSequence2Dispatcher; IProfilerPluginImpl_vTable := ProfilerPluginVTable.create; IProfilerPluginImpl_vTable.version := 4; @@ -18045,13 +18323,13 @@ initialization IProfilerPluginImpl_vTable.flush := @IProfilerPluginImpl_flushDispatcher; IProfilerSessionImpl_vTable := ProfilerSessionVTable.create; - IProfilerSessionImpl_vTable.version := 3; + IProfilerSessionImpl_vTable.version := 4; IProfilerSessionImpl_vTable.dispose := @IProfilerSessionImpl_disposeDispatcher; IProfilerSessionImpl_vTable.getId := @IProfilerSessionImpl_getIdDispatcher; IProfilerSessionImpl_vTable.getFlags := @IProfilerSessionImpl_getFlagsDispatcher; IProfilerSessionImpl_vTable.cancel := @IProfilerSessionImpl_cancelDispatcher; IProfilerSessionImpl_vTable.finish := @IProfilerSessionImpl_finishDispatcher; - IProfilerSessionImpl_vTable.defineStatement := @IProfilerSessionImpl_defineStatementDispatcher; + IProfilerSessionImpl_vTable.deprecatedDefineStatement := @IProfilerSessionImpl_deprecatedDefineStatementDispatcher; IProfilerSessionImpl_vTable.defineCursor := @IProfilerSessionImpl_defineCursorDispatcher; IProfilerSessionImpl_vTable.defineRecordSource := @IProfilerSessionImpl_defineRecordSourceDispatcher; IProfilerSessionImpl_vTable.onRequestStart := @IProfilerSessionImpl_onRequestStartDispatcher; @@ -18062,6 +18340,7 @@ initialization IProfilerSessionImpl_vTable.afterRecordSourceOpen := @IProfilerSessionImpl_afterRecordSourceOpenDispatcher; IProfilerSessionImpl_vTable.beforeRecordSourceGetRecord := @IProfilerSessionImpl_beforeRecordSourceGetRecordDispatcher; IProfilerSessionImpl_vTable.afterRecordSourceGetRecord := @IProfilerSessionImpl_afterRecordSourceGetRecordDispatcher; + IProfilerSessionImpl_vTable.defineStatement2 := @IProfilerSessionImpl_defineStatement2Dispatcher; IProfilerStatsImpl_vTable := ProfilerStatsVTable.create; IProfilerStatsImpl_vTable.version := 2; diff --git a/src/isql/FrontendParser.cpp b/src/isql/FrontendParser.cpp index 11d39bbce1..7467984c1e 100644 --- a/src/isql/FrontendParser.cpp +++ b/src/isql/FrontendParser.cpp @@ -55,7 +55,7 @@ FrontendParser::AnyNode FrontendParser::internalParse() if (command == TOKEN_ADD) { - if (auto tableName = parseName()) + if (auto tableName = parseQualifiedName()) { AddNode node; node.tableName = std::move(tableName.value()); @@ -120,15 +120,15 @@ FrontendParser::AnyNode FrontendParser::internalParse() } while(true); } else if (command == TOKEN_COPY) - { +{ CopyNode node; - if (auto source = parseName()) + if (auto source = parseQualifiedName()) node.source = std::move(source.value()); else return InvalidNode(); - if (auto destination = parseName()) + if (auto destination = parseQualifiedName()) node.destination = std::move(destination.value()); else return InvalidNode(); @@ -344,7 +344,7 @@ FrontendParser::AnySetNode FrontendParser::parseSet() else if (text == TOKEN_NAMES) { SetNamesNode node; - node.name = parseName(); + node.name = parseQualifiedName(); if (parseEof()) return node; @@ -496,11 +496,11 @@ FrontendParser::AnyShowNode FrontendParser::parseShow() { const auto& text = showCommandToken.processedText; - if (const auto parsed = parseShowOptName(text, TOKEN_CHECKS, 5)) + if (const auto parsed = parseShowOptQualifiedName(text, TOKEN_CHECKS, 5)) return parsed.value(); - else if (const auto parsed = parseShowOptName(text, TOKEN_COLLATES, 7)) + else if (const auto parsed = parseShowOptQualifiedName(text, TOKEN_COLLATES, 7)) return parsed.value(); - else if (const auto parsed = parseShowOptName(text, TOKEN_COLLATIONS, 9)) + else if (const auto parsed = parseShowOptQualifiedName(text, TOKEN_COLLATIONS, 9)) return parsed.value(); else if (text.length() >= 7 && TOKEN_COMMENTS.find(text) == 0) { @@ -512,74 +512,42 @@ FrontendParser::AnyShowNode FrontendParser::parseShow() if (parseEof()) return ShowDatabaseNode(); } - else if (const auto parsed = parseShowOptName(text, TOKEN_DEPENDENCIES, 5)) + else if (const auto parsed = parseShowOptQualifiedName(text, TOKEN_DEPENDENCIES, 5)) return parsed.value(); - else if (const auto parsed = parseShowOptName(text, TOKEN_DEPENDENCY, 5)) + else if (const auto parsed = parseShowOptQualifiedName(text, TOKEN_DEPENDENCY, 5)) return parsed.value(); - else if (const auto parsed = parseShowOptName(text, TOKEN_DOMAINS, 6)) + else if (const auto parsed = parseShowOptQualifiedName(text, TOKEN_DOMAINS, 6)) return parsed.value(); - else if (const auto parsed = parseShowOptName(text, TOKEN_EXCEPTIONS, 5)) + else if (const auto parsed = parseShowOptQualifiedName(text, TOKEN_EXCEPTIONS, 5)) return parsed.value(); else if (const auto parsed = parseShowOptName(text, TOKEN_FILTERS, 6)) return parsed.value(); else if (text.length() >= 4 && TOKEN_FUNCTIONS.find(text) == 0) { ShowFunctionsNode node; - node.name = parseName(); + node.name = parseQualifiedName(); // FIXME: package - if (node.name) - { - if (const auto token = lexer.getToken(); - token.type == Token::TYPE_OTHER && token.rawText == ".") - { - node.package = node.name; - node.name = parseName(); - - if (parseEof()) - return node; - } - else if (token.type == Token::TYPE_EOF) - { - return node; - } - } - else + if (parseEof()) return node; } - else if (const auto parsed = parseShowOptName(text, TOKEN_INDEXES, 3)) + else if (const auto parsed = parseShowOptQualifiedName(text, TOKEN_INDEXES, 3)) return parsed.value(); - else if (const auto parsed = parseShowOptName(text, TOKEN_INDICES, 0)) + else if (const auto parsed = parseShowOptQualifiedName(text, TOKEN_INDICES, 0)) return parsed.value(); - else if (const auto parsed = parseShowOptName(text, TOKEN_GENERATORS, 3)) + else if (const auto parsed = parseShowOptQualifiedName(text, TOKEN_GENERATORS, 3)) return parsed.value(); - else if (const auto parsed = parseShowOptName(text, TOKEN_GRANTS, 5)) + else if (const auto parsed = parseShowOptQualifiedName(text, TOKEN_GRANTS, 5)) return parsed.value(); else if (const auto parsed = parseShowOptName(text, TOKEN_MAPPINGS, 3)) return parsed.value(); - else if (const auto parsed = parseShowOptName(text, TOKEN_PACKAGES, 4)) + else if (const auto parsed = parseShowOptQualifiedName(text, TOKEN_PACKAGES, 4)) return parsed.value(); else if (text.length() >= 4 && TOKEN_PROCEDURES.find(text) == 0) { ShowProceduresNode node; - node.name = parseName(); + node.name = parseQualifiedName(); // FIXME: package - if (node.name) - { - if (const auto token = lexer.getToken(); - token.type == Token::TYPE_OTHER && token.rawText == ".") - { - node.package = node.name; - node.name = parseName(); - - if (parseEof()) - return node; - } - else if (token.type == Token::TYPE_EOF) - { - return node; - } - } - else + if (parseEof()) return node; } else if (const auto parsed = parseShowOptName(text, TOKEN_PUBLICATIONS, 3)) @@ -596,7 +564,7 @@ FrontendParser::AnyShowNode FrontendParser::parseShow() if (!(token.type == Token::TYPE_OTHER && token.rawText == "*")) { lexer.setPos(lexerPos); - node.name = parseName(); + node.name = parseQualifiedName(); if (!node.name) return InvalidNode(); @@ -611,7 +579,7 @@ FrontendParser::AnyShowNode FrontendParser::parseShow() if (parseEof()) return node; } - else if (const auto parsed = parseShowOptName(text, TOKEN_SEQUENCES, 3)) + else if (const auto parsed = parseShowOptQualifiedName(text, TOKEN_SEQUENCES, 3)) return parsed.value(); else if (text == TOKEN_SQL) { @@ -656,9 +624,9 @@ FrontendParser::AnyShowNode FrontendParser::parseShow() return node; } - else if (const auto parsed = parseShowOptName(text, TOKEN_TABLES, 5)) + else if (const auto parsed = parseShowOptQualifiedName(text, TOKEN_TABLES, 5)) return parsed.value(); - else if (const auto parsed = parseShowOptName(text, TOKEN_TRIGGERS, 4)) + else if (const auto parsed = parseShowOptQualifiedName(text, TOKEN_TRIGGERS, 4)) return parsed.value(); else if (text == TOKEN_USERS) { @@ -670,7 +638,7 @@ FrontendParser::AnyShowNode FrontendParser::parseShow() if (parseEof()) return ShowVersionNode(); } - else if (const auto parsed = parseShowOptName(text, TOKEN_VIEWS, 4)) + else if (const auto parsed = parseShowOptQualifiedName(text, TOKEN_VIEWS, 4)) return parsed.value(); else if (text.length() >= 9 && TOKEN_WIRE_STATISTICS.find(text) == 0 || text == TOKEN_WIRE_STATS) @@ -706,6 +674,26 @@ std::optional FrontendParser::parseShowOptName(std: return std::nullopt; } +template +std::optional FrontendParser::parseShowOptQualifiedName(std::string_view showCommand, + std::string_view testCommand, unsigned testCommandMinLen) +{ + if (showCommand == testCommand || + (testCommandMinLen && showCommand.length() >= testCommandMinLen && + std::string(testCommand).find(showCommand) == 0)) + { + Node node; + node.name = parseQualifiedName(); + + if (!parseEof()) + return InvalidNode(); + + return node; + } + + return std::nullopt; +} + std::optional FrontendParser::parseUtilEof() { const auto startIt = lexer.getPos(); diff --git a/src/isql/FrontendParser.h b/src/isql/FrontendParser.h index aa52a0a6fd..bf54135270 100644 --- a/src/isql/FrontendParser.h +++ b/src/isql/FrontendParser.h @@ -27,6 +27,7 @@ #include "../isql/FrontendLexer.h" #include "../jrd/obj.h" #include "../common/classes/MetaString.h" +#include "../common/classes/QualifiedMetaString.h" #include #include #include @@ -46,10 +47,10 @@ public: struct InvalidNode {}; - struct AddNode { Firebird::MetaString tableName; }; + struct AddNode { Firebird::QualifiedMetaString tableName; }; struct BlobDumpViewNode { ISC_QUAD blobId; std::optional file; }; struct ConnectNode { std::vector args; }; - struct CopyNode { Firebird::MetaString source; Firebird::MetaString destination; std::string database; }; + struct CopyNode { Firebird::QualifiedMetaString source; Firebird::QualifiedMetaString destination; std::string database; }; struct CreateDatabaseNode { std::vector args; }; struct DropDatabaseNode {}; struct EditNode { std::optional file; }; @@ -76,7 +77,7 @@ public: struct SetListNode { std::string arg; }; struct SetLocalTimeoutNode { std::string arg; }; struct SetMaxRowsNode { std::string arg; }; - struct SetNamesNode { std::optional name; }; + struct SetNamesNode { std::optional name; }; struct SetPerTableStatsNode { std::string arg; }; struct SetPlanNode { std::string arg; }; struct SetPlanOnlyNode { std::string arg; }; @@ -91,31 +92,31 @@ public: struct SetWireStatsNode { std::string arg; }; struct ShowNode {}; - struct ShowChecksNode { std::optional name; }; - struct ShowCollationsNode { std::optional name; }; + struct ShowChecksNode { std::optional name; }; + struct ShowCollationsNode { std::optional name; }; struct ShowCommentsNode {}; struct ShowDatabaseNode {}; - struct ShowDomainsNode { std::optional name; }; - struct ShowDependenciesNode { std::optional name; }; - struct ShowExceptionsNode { std::optional name; }; + struct ShowDomainsNode { std::optional name; }; + struct ShowDependenciesNode { std::optional name; }; + struct ShowExceptionsNode { std::optional name; }; struct ShowFiltersNode { std::optional name; }; - struct ShowFunctionsNode { std::optional name; std::optional package; }; - struct ShowGeneratorsNode { std::optional name; }; - struct ShowGrantsNode { std::optional name; }; - struct ShowIndexesNode { std::optional name; }; + struct ShowFunctionsNode { std::optional name; }; + struct ShowGeneratorsNode { std::optional name; }; + struct ShowGrantsNode { std::optional name; }; + struct ShowIndexesNode { std::optional name; }; struct ShowMappingsNode { std::optional name; }; - struct ShowPackagesNode { std::optional name; }; - struct ShowProceduresNode { std::optional name; std::optional package; }; + struct ShowPackagesNode { std::optional name; }; + struct ShowProceduresNode { std::optional name; }; struct ShowPublicationsNode { std::optional name; }; struct ShowRolesNode { std::optional name; }; - struct ShowSecClassesNode { std::optional name; bool detail = false; }; + struct ShowSecClassesNode { std::optional name; bool detail = false; }; struct ShowSqlDialectNode {}; struct ShowSystemNode { std::optional objType; }; - struct ShowTablesNode { std::optional name; }; - struct ShowTriggersNode { std::optional name; }; + struct ShowTablesNode { std::optional name; }; + struct ShowTriggersNode { std::optional name; }; struct ShowUsersNode {}; struct ShowVersionNode {}; - struct ShowViewsNode { std::optional name; }; + struct ShowViewsNode { std::optional name; }; struct ShowWireStatsNode {}; using AnySetNode = std::variant< @@ -249,6 +250,10 @@ private: std::optional parseShowOptName(std::string_view showCommand, std::string_view testCommand, unsigned testCommandMinLen = 0); + template + std::optional parseShowOptQualifiedName(std::string_view showCommand, + std::string_view testCommand, unsigned testCommandMinLen = 0); + bool parseEof() { return lexer.getToken().type == Token::TYPE_EOF; @@ -264,6 +269,27 @@ private: return std::nullopt; } + std::optional parseQualifiedName() + { + if (const auto name = parseName()) + { + const auto lexerPos = lexer.getPos(); + const auto token = lexer.getToken(); + + if (token.type == Token::TYPE_OTHER && token.rawText == ".") + { + if (const auto name2 = parseName()) + return Firebird::QualifiedMetaString(name2.value(), name.value()); + } + + lexer.setPos(lexerPos); + + return Firebird::QualifiedMetaString(name.value()); + } + + return std::nullopt; + } + std::optional parseFileName() { const auto token = lexer.getToken(); diff --git a/src/isql/extra_proto.h b/src/isql/extra_proto.h index ff21febf45..8dea6ff7bc 100644 --- a/src/isql/extra_proto.h +++ b/src/isql/extra_proto.h @@ -24,8 +24,15 @@ #ifndef ISQL_EXTRA_PROTO_H #define ISQL_EXTRA_PROTO_H -int EXTRACT_ddl(LegacyTables, const SCHAR*); -int EXTRACT_list_table(const SCHAR*, const SCHAR*, bool, SSHORT); +#include +#include "../common/classes/MetaString.h" +#include "../common/classes/QualifiedMetaString.h" + +using GetDefaultCharSetForSchemaFunc = std::function; + +int EXTRACT_ddl(LegacyTables, const Firebird::QualifiedMetaString&); +int EXTRACT_list_table(const Firebird::QualifiedMetaString&, const Firebird::QualifiedMetaString&, bool, + GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc); processing_state EXTRACT_list_grants (const SCHAR*); #endif // ISQL_EXTRA_PROTO_H diff --git a/src/isql/extract.epp b/src/isql/extract.epp index c281cae6b8..8198f17410 100644 --- a/src/isql/extract.epp +++ b/src/isql/extract.epp @@ -28,8 +28,6 @@ * double quotes if they are in dialect 3 and have special characters. * 2001.09.21 Claudio Valderrama: Show correct mechanism for UDF parameters * and support the RETURNS PARAMETER syntax. - * 2001.10.01 Claudio Valderrama: list_all_grants2() and EXTRACT_list_grants() - * to better organize the code that should be called to handle SHOW GRANTS. * * Revision 1.2 2000/11/18 16:49:24 fsg * Increased PRINT_BUFFER_LENGTH to 2048 to show larger plans @@ -45,6 +43,9 @@ #include #include #include // isdigit +#include +#include "../common/classes/MetaString.h" +#include "../common/classes/QualifiedMetaString.h" #include "../jrd/constants.h" #include "ibase.h" #include "../yvalve/gds_proto.h" @@ -60,39 +61,43 @@ #include "../common/utils_proto.h" #include "../jrd/constants.h" +using namespace Firebird; using MsgFormat::SafeArg; //DATABASE DB = EXTERN COMPILETIME "yachts.lnk"; DATABASE DB = EXTERN COMPILETIME "yachts.lnk" RUNTIME isqlGlob.global_Db_name; -static bool extract_rel_constraints(const char* relation_name); -static void get_procedure_args(const char* proc_name, SSHORT default_char_set_id); -static void get_function_args_ods12(const char*, USHORT, SSHORT default_char_set_id); -static void list_all_grants(); -static processing_state list_all_grants2(bool, const SCHAR*); -static void list_all_tables(LegacyTables flag, SSHORT); +static bool extract_rel_constraints(const QualifiedMetaString& relation_name); +static void get_procedure_args(const QualifiedMetaString& proc_name, + GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc); +static void get_function_args_ods12(const QualifiedMetaString& func_name, USHORT, + GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc); +static processing_state list_all_grants(bool, const SCHAR*); +static void list_all_tables(LegacyTables flag, GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc); static void list_all_triggers(); static void list_check(); static void list_charsets(); static void list_collations(); static void list_create_db(); -static void list_domain_table(const SCHAR*, SSHORT); -static void list_domains(SSHORT); +static void list_domain_table(const QualifiedMetaString&, + GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc); +static void list_domains(GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc); static void listDomainConstraints(); -static void listRelationComputed(LegacyTables flag, SSHORT); +static void listRelationComputed(LegacyTables flag, GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc); static void list_exceptions(); static void list_filters(); static void list_foreign(); -static void list_functions_ods12_headers(SSHORT default_char_set_id); -static void list_functions_ods12_bodies(SSHORT default_char_set_id); +static void list_functions_ods12_headers(GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc); +static void list_functions_ods12_bodies(GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc); static void list_functions_legacy(); static void list_generators(); static void list_indexes(); static void list_package_bodies(); static void list_package_headers(); -static void list_procedure_bodies(SSHORT default_char_set_id); -static void list_procedure_headers(SSHORT default_char_set_id); +static void list_procedure_bodies(GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc); +static void list_procedure_headers(GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc); +static void list_schemas(); static void list_views(); static const char* const Procterm = "^"; // TXNN: script use only @@ -102,7 +107,7 @@ static TEXT SQL_identifier2[BUFFER_XLARGE]; // should be >= 1026 bytes (exceptio -int EXTRACT_ddl(LegacyTables flag, const SCHAR* tabname) +int EXTRACT_ddl(LegacyTables flag, const QualifiedMetaString& tabname) { /************************************** * @@ -156,15 +161,40 @@ int EXTRACT_ddl(LegacyTables flag, const SCHAR* tabname) } const SSHORT default_char_set_id = ISQL_get_default_char_set_id(); + std::map defaultSchemaCharSetMap; + + const auto getDefaultCharSetForSchema = [&](const MetaString& schemaName) -> SSHORT + { + if (schemaName.hasData()) + { + if (const auto it = defaultSchemaCharSetMap.find(schemaName); it != defaultSchemaCharSetMap.end()) + return it->second; + else if (isqlGlob.major_ods >= ODS_VERSION14) + { + FOR SCH IN RDB$SCHEMAS + CROSS CHR IN RDB$CHARACTER_SETS + WITH SCH.RDB$SCHEMA_NAME EQ schemaName.c_str() AND + CHR.RDB$SCHEMA_NAME EQ SCH.RDB$CHARACTER_SET_SCHEMA_NAME AND + CHR.RDB$CHARACTER_SET_NAME EQ SCH.RDB$CHARACTER_SET_NAME + { + return defaultSchemaCharSetMap[schemaName] = CHR.RDB$CHARACTER_SET_ID; + } + END_FOR + } + } + + return default_char_set_id; + }; + int ret_code = FINI_OK; // If a table name was passed, extract only that table and domains - if (*tabname) + if (tabname.object.hasData()) { - if (EXTRACT_list_table(tabname, NULL, true, default_char_set_id)) + if (EXTRACT_list_table(tabname, {}, true, getDefaultCharSetForSchema)) { SCHAR errbuf[MSG_LENGTH]; - IUTILS_msg_get(NOT_FOUND, errbuf, SafeArg() << tabname); + IUTILS_msg_get(NOT_FOUND, errbuf, SafeArg() << tabname.toQuotedString().c_str()); STDERROUT(errbuf); ret_code = FINI_ERROR; } @@ -173,28 +203,29 @@ int EXTRACT_ddl(LegacyTables flag, const SCHAR* tabname) { list_create_db(); list_filters(); + list_schemas(); list_charsets(); list_collations(); list_generators(); - list_domains(default_char_set_id); - list_all_tables(flag, default_char_set_id); + list_domains(getDefaultCharSetForSchema); + list_all_tables(flag, getDefaultCharSetForSchema); list_functions_legacy(); - list_functions_ods12_headers(default_char_set_id); - list_procedure_headers(default_char_set_id); + list_functions_ods12_headers(getDefaultCharSetForSchema); + list_procedure_headers(getDefaultCharSetForSchema); list_package_headers(); list_indexes(); list_foreign(); list_views(); list_exceptions(); - list_functions_ods12_bodies(default_char_set_id); - list_procedure_bodies(default_char_set_id); + list_functions_ods12_bodies(getDefaultCharSetForSchema); + list_procedure_bodies(getDefaultCharSetForSchema); list_package_bodies(); listDomainConstraints(); list_check(); - listRelationComputed(flag, default_char_set_id); + listRelationComputed(flag, getDefaultCharSetForSchema); list_all_triggers(); - list_all_grants(); - SHOW_maps(true, ""); + list_all_grants(true, isqlGlob.global_Term); + SHOW_maps(true, std::nullopt); SHOW_comments(false); // Let's make this an option later. } @@ -230,14 +261,14 @@ processing_state EXTRACT_list_grants(const SCHAR* terminator) * Print the permissions on all user tables, views and procedures. * **************************************/ - return list_all_grants2(false, terminator); + return list_all_grants(false, terminator); } -int EXTRACT_list_table(const SCHAR* relation_name, - const SCHAR* new_name, +int EXTRACT_list_table(const QualifiedMetaString& relation_name, + const QualifiedMetaString& new_name, bool domain_flag, - SSHORT default_char_set_id) + GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc) { /************************************** * @@ -300,7 +331,7 @@ int EXTRACT_list_table(const SCHAR* relation_name, **************************************/ bool first = true; - SCHAR char_sets[CHARSET_COLLATE_SIZE]; + string char_sets; rel_t rel_type = rel_persistent; char ss[28] = ""; @@ -308,15 +339,20 @@ int EXTRACT_list_table(const SCHAR* relation_name, FOR REL IN RDB$RELATIONS CROSS RFR IN RDB$RELATION_FIELDS CROSS - FLD IN RDB$FIELDS WITH - RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND - RFR.RDB$RELATION_NAME EQ REL.RDB$RELATION_NAME AND - REL.RDB$RELATION_NAME EQ relation_name + FLD IN RDB$FIELDS + WITH RFR.RDB$SCHEMA_NAME EQUIV REL.RDB$SCHEMA_NAME AND + RFR.RDB$RELATION_NAME EQ REL.RDB$RELATION_NAME AND + FLD.RDB$SCHEMA_NAME EQUIV RFR.RDB$FIELD_SOURCE_SCHEMA_NAME AND + FLD.RDB$FIELD_NAME EQ RFR.RDB$FIELD_SOURCE AND + REL.RDB$SCHEMA_NAME EQUIV NULLIF(relation_name.schema.c_str(), '') AND + REL.RDB$RELATION_NAME EQ relation_name.object.c_str() SORTED BY RFR.RDB$FIELD_POSITION, RFR.RDB$FIELD_NAME - + { if (!REL.RDB$RELATION_TYPE.NULL) rel_type = (rel_t) REL.RDB$RELATION_TYPE; + const QualifiedMetaString fieldName(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME); + SSHORT collation = 0; SSHORT char_set_id = 0; @@ -325,13 +361,14 @@ int EXTRACT_list_table(const SCHAR* relation_name, first = false; // Do we need to print domains if (domain_flag) - list_domain_table (relation_name, default_char_set_id); + list_domain_table(relation_name, getDefaultCharSetForSchemaFunc); + + const MetaString ownerName(REL.RDB$OWNER_NAME); - fb_utils::exact_name(REL.RDB$OWNER_NAME); isqlGlob.printf("%s/* Table: %s, Owner: %s */%s", NEWLINE, - relation_name, - REL.RDB$OWNER_NAME, + ISQL_name_to_string(relation_name).c_str(), + ISQL_name_to_string(ownerName).c_str(), NEWLINE); if (rel_type == rel_global_temp_preserve || rel_type == rel_global_temp_delete) @@ -339,16 +376,7 @@ int EXTRACT_list_table(const SCHAR* relation_name, else isqlGlob.printf("CREATE TABLE "); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - if (new_name) - IUTILS_copy_SQL_id (new_name, SQL_identifier, DBL_QUOTE); - else - IUTILS_copy_SQL_id (relation_name, SQL_identifier, DBL_QUOTE); - isqlGlob.printf("%s ", SQL_identifier); - } - else - isqlGlob.printf("%s ", new_name ? new_name : relation_name); + isqlGlob.printf("%s ", ISQL_name_to_string(new_name.object.hasData() ? new_name : relation_name).c_str()); if (!REL.RDB$SQL_SECURITY.NULL) { @@ -369,13 +397,8 @@ int EXTRACT_list_table(const SCHAR* relation_name, else isqlGlob.printf(",%s%s", NEWLINE, TAB_AS_SPACES); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (fb_utils::exact_name(RFR.RDB$FIELD_NAME), SQL_identifier, DBL_QUOTE); - isqlGlob.printf("%s ", SQL_identifier); - } - else - isqlGlob.printf("%s ", fb_utils::exact_name(RFR.RDB$FIELD_NAME)); + const MetaString columnName(RFR.RDB$FIELD_NAME); + isqlGlob.printf("%s ", ISQL_name_to_string(columnName).c_str()); /* ** If this is a known domain, then just print the domain rather than type @@ -383,16 +406,9 @@ int EXTRACT_list_table(const SCHAR* relation_name, ** may have not null, default and check overriding their definitions */ - if (!(fb_utils::implicit_domain(FLD.RDB$FIELD_NAME) && FLD.RDB$SYSTEM_FLAG != 1)) + if (!(fb_utils::implicit_domain(fieldName.object.c_str()) && FLD.RDB$SYSTEM_FLAG != 1)) { - fb_utils::exact_name(FLD.RDB$FIELD_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (FLD.RDB$FIELD_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.prints(SQL_identifier); - } - else - isqlGlob.prints(FLD.RDB$FIELD_NAME); + isqlGlob.prints(ISQL_name_to_string(fieldName).c_str()); // International character sets // Print only the character set @@ -407,7 +423,7 @@ int EXTRACT_list_table(const SCHAR* relation_name, } else { - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, + if (!ISQL_printNumericType(fieldName, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) { return FINI_ERROR; @@ -427,7 +443,7 @@ int EXTRACT_list_table(const SCHAR* relation_name, // Catch arrays after printing the type if (!FLD.RDB$DIMENSIONS.NULL) - ISQL_array_dimensions(FLD.RDB$FIELD_NAME); + ISQL_array_dimensions(fieldName); if (FLD.RDB$FIELD_TYPE == blr_blob) { @@ -448,8 +464,6 @@ int EXTRACT_list_table(const SCHAR* relation_name, FLD.RDB$FIELD_TYPE == blr_blob) && !FLD.RDB$CHARACTER_SET_ID.NULL) { - char_sets[0] = '\0'; - // Override rdb$fields id with relation_fields if present if (!RFR.RDB$COLLATION_ID.NULL) @@ -459,9 +473,13 @@ int EXTRACT_list_table(const SCHAR* relation_name, if (!FLD.RDB$CHARACTER_SET_ID.NULL) char_set_id = FLD.RDB$CHARACTER_SET_ID; - ISQL_get_character_sets(char_set_id, collation, default_char_set_id, Get::CHARSET_ONLY, false, true, char_sets); - if (char_sets[0]) - isqlGlob.prints(char_sets); + + ISQL_get_character_sets(char_set_id, collation, getDefaultCharSetForSchemaFunc(relation_name.schema), + Get::CHARSET_ONLY, false, char_sets); + + if (char_sets.hasData()) + isqlGlob.prints(char_sets.c_str()); + // CVC: Someone deleted the code that checks intchar when handling collations // several lines below, so it didn't have any effect. Commented it. //if (!char_set_id) @@ -481,14 +499,15 @@ int EXTRACT_list_table(const SCHAR* relation_name, } else if (!RFR.RDB$COLLATION_ID.NULL) { - SCHAR collate_name[CHARSET_COLLATE_SIZE]; - collate_name[0] = '\0'; - ISQL_get_character_sets(char_set_id, collation, default_char_set_id, Get::COLLATE_ONLY, false, true, collate_name); + string collate_name; - if (collate_name[0]) + ISQL_get_character_sets(char_set_id, collation, getDefaultCharSetForSchemaFunc(relation_name.schema), + Get::COLLATE_ONLY, false, collate_name); + + if (collate_name.hasData()) { - isqlGlob.printf("(CAST(NULL AS VARCHAR(1)%s)", char_sets); - isqlGlob.printf("%s)", collate_name); + isqlGlob.printf("(CAST(NULL AS VARCHAR(1)%s)", char_sets.c_str()); + isqlGlob.printf("%s)", collate_name.c_str()); } else isqlGlob.printf("(NULL)"); @@ -510,7 +529,8 @@ int EXTRACT_list_table(const SCHAR* relation_name, if (!RFR.RDB$GENERATOR_NAME.NULL) { FOR GEN IN RDB$GENERATORS - WITH GEN.RDB$GENERATOR_NAME = RFR.RDB$GENERATOR_NAME + WITH GEN.RDB$SCHEMA_NAME EQUIV NULLIF(RFR.RDB$SCHEMA_NAME, '') AND + GEN.RDB$GENERATOR_NAME = RFR.RDB$GENERATOR_NAME { isqlGlob.printf(" GENERATED %s AS IDENTITY", (RFR.RDB$IDENTITY_TYPE == IDENT_TYPE_BY_DEFAULT ? "BY DEFAULT" : @@ -551,28 +571,25 @@ int EXTRACT_list_table(const SCHAR* relation_name, if (RFR.RDB$NULL_FLAG == 1) { FOR RCO IN RDB$RELATION_CONSTRAINTS CROSS - CON IN RDB$CHECK_CONSTRAINTS WITH - CON.RDB$TRIGGER_NAME = RFR.RDB$FIELD_NAME AND - CON.RDB$CONSTRAINT_NAME = RCO.RDB$CONSTRAINT_NAME AND - RCO.RDB$CONSTRAINT_TYPE EQ "NOT NULL" AND - RCO.RDB$RELATION_NAME = RFR.RDB$RELATION_NAME - + CON IN RDB$CHECK_CONSTRAINTS + WITH CON.RDB$SCHEMA_NAME EQUIV NULLIF(RFR.RDB$SCHEMA_NAME, '') AND + CON.RDB$TRIGGER_NAME = RFR.RDB$FIELD_NAME AND + CON.RDB$CONSTRAINT_NAME = RCO.RDB$CONSTRAINT_NAME AND + RCO.RDB$CONSTRAINT_TYPE EQ "NOT NULL" AND + RCO.RDB$SCHEMA_NAME EQUIV CON.RDB$SCHEMA_NAME AND + RCO.RDB$RELATION_NAME = RFR.RDB$RELATION_NAME + { if (!fb_utils::implicit_integrity(CON.RDB$CONSTRAINT_NAME)) { - fb_utils::exact_name(CON.RDB$CONSTRAINT_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (CON.RDB$CONSTRAINT_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf(" CONSTRAINT %s", SQL_identifier); - } - else - isqlGlob.printf(" CONSTRAINT %s", CON.RDB$CONSTRAINT_NAME); + const MetaString constraintName(CON.RDB$CONSTRAINT_NAME); + isqlGlob.printf(" CONSTRAINT %s", ISQL_name_to_string(constraintName).c_str()); } + } END_FOR ON_ERROR - ISQL_errmsg (fbStatus); + ISQL_errmsg(fbStatus); return FINI_ERROR; - END_ERROR; + END_ERROR isqlGlob.printf(" NOT NULL"); } @@ -581,16 +598,18 @@ int EXTRACT_list_table(const SCHAR* relation_name, if (!RFR.RDB$COLLATION_ID.NULL) { - char_sets[0] = '\0'; - ISQL_get_character_sets(char_set_id, collation, default_char_set_id, Get::COLLATE_ONLY, false, true, char_sets); - if (char_sets[0]) - isqlGlob.prints(char_sets); + ISQL_get_character_sets(char_set_id, collation, getDefaultCharSetForSchemaFunc(relation_name.schema), + Get::COLLATE_ONLY, false, char_sets); + + if (char_sets.hasData()) + isqlGlob.prints(char_sets.c_str()); } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return FINI_ERROR; - END_ERROR; + END_ERROR // Do primary and unique keys only. References come later. if (!extract_rel_constraints(relation_name)) @@ -616,7 +635,7 @@ int EXTRACT_list_table(const SCHAR* relation_name, } -static bool extract_rel_constraints(const char* relation_name) +static bool extract_rel_constraints(const QualifiedMetaString& relation_name) { /************************************************** * @@ -633,30 +652,25 @@ static bool extract_rel_constraints(const char* relation_name) // PK and UK are always based on indices for now, hence this join is safe. FOR RELC IN RDB$RELATION_CONSTRAINTS - CROSS IDX IN RDB$INDICES OVER RDB$INDEX_NAME - WITH - (RELC.RDB$CONSTRAINT_TYPE EQ "PRIMARY KEY" OR - RELC.RDB$CONSTRAINT_TYPE EQ "UNIQUE") AND - RELC.RDB$RELATION_NAME EQ relation_name + CROSS IDX IN RDB$INDICES + WITH (RELC.RDB$CONSTRAINT_TYPE EQ "PRIMARY KEY" OR + RELC.RDB$CONSTRAINT_TYPE EQ "UNIQUE") AND + RELC.RDB$SCHEMA_NAME EQUIV NULLIF(relation_name.schema.c_str(), '') AND + RELC.RDB$RELATION_NAME EQ relation_name.object.c_str() AND + IDX.RDB$SCHEMA_NAME EQUIV RELC.RDB$SCHEMA_NAME AND + IDX.RDB$INDEX_NAME EQ RELC.RDB$INDEX_NAME SORTED BY RELC.RDB$CONSTRAINT_TYPE, RELC.RDB$CONSTRAINT_NAME + { + const QualifiedMetaString indexName(IDX.RDB$INDEX_NAME, IDX.RDB$SCHEMA_NAME); + const MetaString constraintName(RELC.RDB$CONSTRAINT_NAME); isqlGlob.printf(",%s", NEWLINE); - fb_utils::exact_name(RELC.RDB$CONSTRAINT_NAME); - fb_utils::exact_name(IDX.RDB$INDEX_NAME); // If the name of the constraint is not INTEG_..., print it - if (!fb_utils::implicit_integrity(RELC.RDB$CONSTRAINT_NAME)) - { - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (RELC.RDB$CONSTRAINT_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf("CONSTRAINT %s ", SQL_identifier); - } - else - isqlGlob.printf("CONSTRAINT %s ", RELC.RDB$CONSTRAINT_NAME); - } + if (!fb_utils::implicit_integrity(constraintName.c_str())) + isqlGlob.printf("CONSTRAINT %s ", ISQL_name_to_string(constraintName).c_str()); - ISQL_get_index_segments (collist, sizeof(collist), RELC.RDB$INDEX_NAME, true); + ISQL_get_index_segments(collist, sizeof(collist), indexName, true); const bool isPK = !strncmp (RELC.RDB$CONSTRAINT_TYPE, "PRIMARY", 7); if (isPK) @@ -666,32 +680,29 @@ static bool extract_rel_constraints(const char* relation_name) // Yes, the same RDB$... naming convention is used for both domains and indices. const bool explicit_index = ((isPK && !fb_utils::implicit_pk(IDX.RDB$INDEX_NAME)) || - (!isPK && !fb_utils::implicit_domain(IDX.RDB$INDEX_NAME))) && - strcmp(RELC.RDB$CONSTRAINT_NAME, IDX.RDB$INDEX_NAME); + (!isPK && !fb_utils::implicit_domain(indexName.object.c_str()))) && + constraintName != indexName.object; const bool descending_index = !IDX.RDB$INDEX_TYPE.NULL && IDX.RDB$INDEX_TYPE == 1; if (explicit_index || descending_index) { - isqlGlob.printf(" USING %sINDEX", descending_index ? "DESCENDING " : ""); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id(IDX.RDB$INDEX_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf(" %s", SQL_identifier); - } - else - isqlGlob.printf(" %s", IDX.RDB$INDEX_NAME); + isqlGlob.printf( + " USING %sINDEX %s", + (descending_index ? "DESCENDING " : ""), + ISQL_name_to_string(indexName.object).c_str()); } - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return false; - END_ERROR; + END_ERROR return true; } -static void get_procedure_args(const char* proc_name, SSHORT default_char_set_id) +static void get_procedure_args(const QualifiedMetaString& proc_name, + GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc) { /************************************** * @@ -705,7 +716,7 @@ static void get_procedure_args(const char* proc_name, SSHORT default_char_set_id * Make sure to pass here only the names of procedures that are global. * **************************************/ - SCHAR char_sets[95]; + string char_sets; // query to retrieve the parameters. @@ -722,13 +733,15 @@ static void get_procedure_args(const char* proc_name, SSHORT default_char_set_id bool first_time = true; FOR PRM IN RDB$PROCEDURE_PARAMETERS CROSS - FLD IN RDB$FIELDS WITH - PRM.RDB$PROCEDURE_NAME = proc_name AND - PRM.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND - PRM.RDB$PARAMETER_TYPE = ptype AND - PRM.RDB$PACKAGE_NAME MISSING + FLD IN RDB$FIELDS + WITH FLD.RDB$SCHEMA_NAME EQUIV PRM.RDB$FIELD_SOURCE_SCHEMA_NAME AND + FLD.RDB$FIELD_NAME EQ PRM.RDB$FIELD_SOURCE AND + PRM.RDB$SCHEMA_NAME EQUIV NULLIF(proc_name.schema.c_str(), '') AND + PRM.RDB$PROCEDURE_NAME = proc_name.object.c_str() AND + PRM.RDB$PARAMETER_TYPE = ptype AND + PRM.RDB$PACKAGE_NAME MISSING SORTED BY PRM.RDB$PARAMETER_NUMBER - + { bool prm_collation_id_null = PRM.RDB$COLLATION_ID.NULL; SSHORT prm_collation_id = PRM.RDB$COLLATION_ID; @@ -743,26 +756,8 @@ static void get_procedure_args(const char* proc_name, SSHORT default_char_set_id if (!PRM.RDB$PARAMETER_MECHANISM.NULL) prm_mech = (prm_mech_t) PRM.RDB$PARAMETER_MECHANISM; - char relationName[BUFFER_LENGTH256] = ""; - char relationField[BUFFER_LENGTH256] = ""; - - if (!PRM.RDB$RELATION_NAME.NULL) - { - fb_utils::exact_name(PRM.RDB$RELATION_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(PRM.RDB$RELATION_NAME, relationName, DBL_QUOTE); - else - strcpy(relationName, PRM.RDB$RELATION_NAME); - } - - if (!PRM.RDB$FIELD_NAME.NULL) - { - fb_utils::exact_name(PRM.RDB$FIELD_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(PRM.RDB$FIELD_NAME, relationField, DBL_QUOTE); - else - strcpy(relationField, PRM.RDB$FIELD_NAME); - } + QualifiedMetaString relationName(PRM.RDB$RELATION_NAME, PRM.RDB$RELATION_SCHEMA_NAME); + MetaString relationField(PRM.RDB$FIELD_NAME); if (first_time) { @@ -781,48 +776,39 @@ static void get_procedure_args(const char* proc_name, SSHORT default_char_set_id else isqlGlob.printf(",%s", NEWLINE); - fb_utils::exact_name(PRM.RDB$PARAMETER_NAME); + const MetaString parameterName(PRM.RDB$PARAMETER_NAME); + const QualifiedMetaString fieldName(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME); - // CVC: Parameter names need check for dialect 3, too. + isqlGlob.printf("%s ", ISQL_name_to_string(parameterName).c_str()); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id (PRM.RDB$PARAMETER_NAME, SQL_identifier, DBL_QUOTE); - else - strcpy (SQL_identifier, PRM.RDB$PARAMETER_NAME); - - isqlGlob.printf("%s ", SQL_identifier); - - const bool basedOnColumn = relationName[0] && relationField[0]; - if (!fb_utils::implicit_domain(FLD.RDB$FIELD_NAME) || FLD.RDB$SYSTEM_FLAG == 1 || + const bool basedOnColumn = relationName.object.hasData() && relationField.hasData(); + if (!fb_utils::implicit_domain(fieldName.object.c_str()) || FLD.RDB$SYSTEM_FLAG == 1 || basedOnColumn) { if (prm_mech == prm_mech_type_of) isqlGlob.printf("TYPE OF "); if (basedOnColumn) - isqlGlob.printf("COLUMN %s.%s", relationName, relationField); - else { - fb_utils::exact_name(FLD.RDB$FIELD_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (FLD.RDB$FIELD_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.prints(SQL_identifier); - } - else - isqlGlob.prints(FLD.RDB$FIELD_NAME); + isqlGlob.printf( + "COLUMN %s.%s", + ISQL_name_to_string(relationName).c_str(), + ISQL_name_to_string(relationField).c_str()); } + else + isqlGlob.prints(ISQL_name_to_string(fieldName).c_str()); // International character sets // Print only the collation if ((FLD.RDB$FIELD_TYPE == blr_text || FLD.RDB$FIELD_TYPE == blr_varying) && !prm_collation_id_null) { - char_sets[0] = '\0'; - ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, prm_collation_id, default_char_set_id, Get::COLLATE_ONLY, - !prm_null_flag_null && prm_null_flag, true, char_sets); - if (char_sets[0]) - isqlGlob.prints(char_sets); + ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, prm_collation_id, + getDefaultCharSetForSchemaFunc(proc_name.schema), + Get::COLLATE_ONLY, !prm_null_flag_null && prm_null_flag, char_sets); + + if (char_sets.hasData()) + isqlGlob.prints(char_sets.c_str()); } else if (!prm_null_flag_null && prm_null_flag) isqlGlob.printf(" NOT NULL"); @@ -838,7 +824,7 @@ static void get_procedure_args(const char* proc_name, SSHORT default_char_set_id } else { - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, + if (!ISQL_printNumericType(fieldName, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) { return; // ps_ERR; @@ -863,8 +849,6 @@ static void get_procedure_args(const char* proc_name, SSHORT default_char_set_id !(((FLD.RDB$FIELD_TYPE == blr_text) || (FLD.RDB$FIELD_TYPE == blr_varying)) && FLD.RDB$FIELD_SUB_TYPE != fb_text_subtype_text)) { - char_sets[0] = 0; - SSHORT collation = 0; if (!prm_collation_id_null) @@ -875,10 +859,12 @@ static void get_procedure_args(const char* proc_name, SSHORT default_char_set_id if (FLD.RDB$CHARACTER_SET_ID.NULL) FLD.RDB$CHARACTER_SET_ID = 0; - ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, collation, default_char_set_id, Get::BOTH, - !prm_null_flag_null && prm_null_flag, true, char_sets); - if (char_sets[0]) - isqlGlob.prints(char_sets); + ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, collation, + getDefaultCharSetForSchemaFunc(proc_name.schema), + Get::BOTH, !prm_null_flag_null && prm_null_flag, char_sets); + + if (char_sets.hasData()) + isqlGlob.prints(char_sets.c_str()); } else if (!prm_null_flag_null && prm_null_flag) isqlGlob.printf(" NOT NULL"); @@ -897,22 +883,23 @@ static void get_procedure_args(const char* proc_name, SSHORT default_char_set_id } } } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR // If there was at least one param, close parens if (!first_time) isqlGlob.printf(")%s", NEWLINE); - } // end for ptype } -static void get_function_args_ods12(const char* func_name, USHORT out_arg, SSHORT default_char_set_id) +static void get_function_args_ods12(const QualifiedMetaString& func_name, USHORT out_arg, + GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc) { /************************************** * @@ -926,7 +913,7 @@ static void get_function_args_ods12(const char* func_name, USHORT out_arg, SSHOR * Make sure to pass here only the names of functions that are global. * **************************************/ - SCHAR char_sets[95]; + string char_sets; // Pass 0 - inputs, pass 1 - return value @@ -935,12 +922,14 @@ static void get_function_args_ods12(const char* func_name, USHORT out_arg, SSHOR bool first_time = true; FOR ARG IN RDB$FUNCTION_ARGUMENTS CROSS - FLD IN RDB$FIELDS WITH - ARG.RDB$FUNCTION_NAME = func_name AND - ARG.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND - ARG.RDB$PACKAGE_NAME MISSING + FLD IN RDB$FIELDS + WITH FLD.RDB$SCHEMA_NAME EQUIV ARG.RDB$FIELD_SOURCE_SCHEMA_NAME AND + FLD.RDB$FIELD_NAME EQ ARG.RDB$FIELD_SOURCE AND + ARG.RDB$SCHEMA_NAME EQUIV NULLIF(func_name.schema.c_str(), '') AND + ARG.RDB$FUNCTION_NAME = func_name.object.c_str() AND + ARG.RDB$PACKAGE_NAME MISSING SORTED BY ARG.RDB$ARGUMENT_POSITION - + { if ((pass == 0 && ARG.RDB$ARGUMENT_POSITION == out_arg) || (pass != 0 && ARG.RDB$ARGUMENT_POSITION != out_arg)) { @@ -961,28 +950,9 @@ static void get_function_args_ods12(const char* func_name, USHORT out_arg, SSHOR if (!ARG.RDB$ARGUMENT_MECHANISM.NULL) prm_mech = (prm_mech_t) ARG.RDB$ARGUMENT_MECHANISM; - char relationName[BUFFER_LENGTH256] = ""; - char relationField[BUFFER_LENGTH256] = ""; - - if (!ARG.RDB$RELATION_NAME.NULL) - { - fb_utils::exact_name(ARG.RDB$RELATION_NAME); - - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(ARG.RDB$RELATION_NAME, relationName, DBL_QUOTE); - else - strcpy(relationName, ARG.RDB$RELATION_NAME); - } - - if (!ARG.RDB$FIELD_NAME.NULL) - { - fb_utils::exact_name(ARG.RDB$FIELD_NAME); - - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(ARG.RDB$FIELD_NAME, relationField, DBL_QUOTE); - else - strcpy(relationField, ARG.RDB$FIELD_NAME); - } + const QualifiedMetaString relationName(ARG.RDB$RELATION_NAME, ARG.RDB$RELATION_SCHEMA_NAME); + const MetaString relationField(ARG.RDB$FIELD_NAME); + const QualifiedMetaString fieldName(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME); if (first_time) { @@ -1003,50 +973,38 @@ static void get_function_args_ods12(const char* func_name, USHORT out_arg, SSHOR if (pass == 0) { - fb_utils::exact_name(ARG.RDB$ARGUMENT_NAME); - - // CVC: Parameter names need check for dialect 3, too. - - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(ARG.RDB$ARGUMENT_NAME, SQL_identifier, DBL_QUOTE); - else - strcpy (SQL_identifier, ARG.RDB$ARGUMENT_NAME); - - isqlGlob.printf("%s ", SQL_identifier); + const MetaString argumentName(ARG.RDB$ARGUMENT_NAME); + isqlGlob.printf("%s ", ISQL_name_to_string(argumentName).c_str()); } - const bool basedOnColumn = relationName[0] && relationField[0]; - if (!fb_utils::implicit_domain(FLD.RDB$FIELD_NAME) || FLD.RDB$SYSTEM_FLAG == 1 || + const bool basedOnColumn = relationName.object.hasData() && relationField.hasData(); + if (!fb_utils::implicit_domain(fieldName.object.c_str()) || FLD.RDB$SYSTEM_FLAG == 1 || basedOnColumn) { if (prm_mech == prm_mech_type_of) isqlGlob.printf("TYPE OF "); if (basedOnColumn) - isqlGlob.printf("COLUMN %s.%s", relationName, relationField); - else { - fb_utils::exact_name(FLD.RDB$FIELD_NAME); - - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (FLD.RDB$FIELD_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.prints(SQL_identifier); - } - else - isqlGlob.prints(FLD.RDB$FIELD_NAME); + isqlGlob.printf( + "COLUMN %s.%s", + ISQL_name_to_string(relationName).c_str(), + ISQL_name_to_string(relationField).c_str()); } + else + isqlGlob.prints(ISQL_name_to_string(fieldName).c_str()); // International character sets // Print only the collation if ((FLD.RDB$FIELD_TYPE == blr_text || FLD.RDB$FIELD_TYPE == blr_varying) && !prm_collation_id_null) { - char_sets[0] = '\0'; - ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, prm_collation_id, default_char_set_id, Get::COLLATE_ONLY, - !prm_null_flag_null && prm_null_flag, true, char_sets); - if (char_sets[0]) - isqlGlob.prints(char_sets); + ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, prm_collation_id, + getDefaultCharSetForSchemaFunc(func_name.schema), + Get::COLLATE_ONLY, !prm_null_flag_null && prm_null_flag, char_sets); + + if (char_sets.hasData()) + isqlGlob.prints(char_sets.c_str()); } else if (!prm_null_flag_null && prm_null_flag) isqlGlob.printf(" NOT NULL"); @@ -1062,7 +1020,7 @@ static void get_function_args_ods12(const char* func_name, USHORT out_arg, SSHOR } else { - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, + if (!ISQL_printNumericType(fieldName, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) { return; // ps_ERR; @@ -1087,8 +1045,6 @@ static void get_function_args_ods12(const char* func_name, USHORT out_arg, SSHOR !(((FLD.RDB$FIELD_TYPE == blr_text) || (FLD.RDB$FIELD_TYPE == blr_varying)) && FLD.RDB$FIELD_SUB_TYPE != fb_text_subtype_text)) { - char_sets[0] = 0; - SSHORT collation = 0; if (!prm_collation_id_null) @@ -1099,16 +1055,17 @@ static void get_function_args_ods12(const char* func_name, USHORT out_arg, SSHOR if (FLD.RDB$CHARACTER_SET_ID.NULL) FLD.RDB$CHARACTER_SET_ID = 0; - ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, collation, default_char_set_id, Get::BOTH, - !prm_null_flag_null && prm_null_flag, true, char_sets); + ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, collation, + getDefaultCharSetForSchemaFunc(func_name.schema), Get::BOTH, + !prm_null_flag_null && prm_null_flag, char_sets); - if (char_sets[0]) - isqlGlob.prints(char_sets); + if (char_sets.hasData()) + isqlGlob.prints(char_sets.c_str()); } else if (!prm_null_flag_null && prm_null_flag) isqlGlob.printf(" NOT NULL"); - if (pass == 0) // input, try to extract default and make Vlad happy. + if (pass == 0) // input, try to extract default { if (!prm_default_source_null) { @@ -1122,11 +1079,12 @@ static void get_function_args_ods12(const char* func_name, USHORT out_arg, SSHOR } } } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR // If there was at least one param, close parens @@ -1137,30 +1095,11 @@ static void get_function_args_ods12(const char* func_name, USHORT out_arg, SSHOR else isqlGlob.printf("%s", NEWLINE); } - } // end for ptype } -static void list_all_grants() -{ -/************************************** - * - * l i s t _ a l l _ g r a n t s - * - ************************************** - * - * Functional description - * Print the permissions on all user tables, views and procedures. - * - * Wrapper around list_all_grants2(). - * - **************************************/ - list_all_grants2(true, isqlGlob.global_Term); -} - - -static processing_state list_all_grants2(bool show_role_list, const SCHAR* terminator) +static processing_state list_all_grants(bool extract, const SCHAR* terminator) { /************************************** * @@ -1175,60 +1114,50 @@ static processing_state list_all_grants2(bool show_role_list, const SCHAR* termi * **************************************/ bool first_role = true; - TEXT prev_owner[44]; - - // Only extract (not show) wants the role list and with escaped quoted identifiers. - const bool mangle = show_role_list; + MetaString prev_owner; // Process GRANT roles - if (isqlGlob.major_ods >= ODS_VERSION9 && show_role_list) + if (isqlGlob.major_ods >= ODS_VERSION9 && extract) { prev_owner[0] = '\0'; FOR XX IN RDB$ROLES SORTED BY XX.RDB$ROLE_NAME - + { bool system_flag = !XX.RDB$SYSTEM_FLAG.NULL && XX.RDB$SYSTEM_FLAG > 0; if (!system_flag) { + const MetaString roleName(XX.RDB$ROLE_NAME); + const MetaString ownerName(XX.RDB$OWNER_NAME); + if (first_role) { isqlGlob.printf("%s/* Grant roles for this database */%s", NEWLINE, NEWLINE); first_role = false; } - // Null terminate name string - fb_utils::exact_name(XX.RDB$ROLE_NAME); - fb_utils::exact_name(XX.RDB$OWNER_NAME); - - if (strcmp (prev_owner, XX.RDB$OWNER_NAME) != 0) + if (ownerName != prev_owner) { isqlGlob.printf("%s/* Role: %s, Owner: %s */%s", NEWLINE, - XX.RDB$ROLE_NAME, - XX.RDB$OWNER_NAME, + ISQL_name_to_string(roleName).c_str(), + ISQL_name_to_string(ownerName).c_str(), NEWLINE); - strcpy (prev_owner, XX.RDB$OWNER_NAME); + prev_owner = ownerName; } - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (XX.RDB$ROLE_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf("CREATE ROLE %s", SQL_identifier); - } - else - isqlGlob.printf("CREATE ROLE %s", XX.RDB$ROLE_NAME); + isqlGlob.printf("CREATE ROLE %s", ISQL_name_to_string(roleName).c_str()); SHOW_system_privileges(XX.RDB$ROLE_NAME, " SET SYSTEM PRIVILEGES TO", false); isqlGlob.printf(";%s", NEWLINE); } - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return OBJECT_NOT_FOUND; - END_ERROR; + END_ERROR } // This version of cursor gets only sql tables identified by security class @@ -1239,67 +1168,64 @@ static processing_state list_all_grants2(bool show_role_list, const SCHAR* termi bool first = true; - FOR REL IN RDB$RELATIONS WITH - (REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND - REL.RDB$SECURITY_CLASS STARTING "SQL$" - SORTED BY REL.RDB$RELATION_NAME - - // Null terminate name string - - fb_utils::exact_name(REL.RDB$RELATION_NAME); + FOR REL IN RDB$RELATIONS + WITH (REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND + REL.RDB$SECURITY_CLASS STARTING "SQL$" + SORTED BY REL.RDB$SCHEMA_NAME, REL.RDB$RELATION_NAME + { + const QualifiedMetaString relationName(REL.RDB$RELATION_NAME, REL.RDB$SCHEMA_NAME); const processing_state rc = - SHOW_grants2(REL.RDB$RELATION_NAME, terminator, obj_relation, - first ? banner : 0, mangle); - if (rc == SKIP) { - first = false; - } + SHOW_grants2(relationName, terminator, obj_relation, (first ? banner : 0), extract); + if (rc == SKIP) + first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return OBJECT_NOT_FOUND; - END_ERROR; + END_ERROR if (first) - SHOW_grant_roles2(terminator, &first, banner, mangle); + SHOW_grant_roles(terminator, &first, banner, extract); else - SHOW_grant_roles2(terminator, 0, 0, mangle); + SHOW_grant_roles(terminator, nullptr, nullptr, extract); // For stored procedures, but ignore procedures inside packages. FOR PRC IN RDB$PROCEDURES - WITH (PRC.RDB$SYSTEM_FLAG NE 1 OR PRC.RDB$SYSTEM_FLAG MISSING) - AND PRC.RDB$PACKAGE_NAME MISSING - SORTED BY PRC.RDB$PROCEDURE_NAME - - // Null terminate name string - fb_utils::exact_name(PRC.RDB$PROCEDURE_NAME); + WITH (PRC.RDB$SYSTEM_FLAG NE 1 OR PRC.RDB$SYSTEM_FLAG MISSING) AND + PRC.RDB$PACKAGE_NAME MISSING + SORTED BY PRC.RDB$SCHEMA_NAME, PRC.RDB$PROCEDURE_NAME + { + const QualifiedMetaString procedureName(PRC.RDB$PROCEDURE_NAME, PRC.RDB$SCHEMA_NAME); const processing_state rc = - SHOW_grants2(PRC.RDB$PROCEDURE_NAME, terminator, obj_procedure, - first ? banner : 0, mangle); + SHOW_grants2(procedureName, terminator, obj_procedure, (first ? banner : 0), extract); + if (rc == SKIP) first = false; - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return OBJECT_NOT_FOUND; - END_ERROR; + END_ERROR if (isqlGlob.major_ods >= ODS_VERSION12) { FOR PACK IN RDB$PACKAGES WITH (PACK.RDB$SYSTEM_FLAG NE 1 OR PACK.RDB$SYSTEM_FLAG MISSING) - SORTED BY PACK.RDB$PACKAGE_NAME + SORTED BY PACK.RDB$SCHEMA_NAME, PACK.RDB$PACKAGE_NAME + { + const QualifiedMetaString packageName(PACK.RDB$PACKAGE_NAME, PACK.RDB$SCHEMA_NAME); - // Null terminate name string - fb_utils::exact_name(PACK.RDB$PACKAGE_NAME); const processing_state rc = - SHOW_grants2(PACK.RDB$PACKAGE_NAME, terminator, obj_package_header, - first ? banner : 0, mangle); + SHOW_grants2(packageName, terminator, obj_package_header, (first ? banner : 0), extract); + if (rc == SKIP) first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -1309,15 +1235,16 @@ static processing_state list_all_grants2(bool show_role_list, const SCHAR* termi FOR FUN IN RDB$FUNCTIONS WITH (FUN.RDB$SYSTEM_FLAG NE 1 OR FUN.RDB$SYSTEM_FLAG MISSING) AND FUN.RDB$PACKAGE_NAME MISSING - SORTED BY FUN.RDB$FUNCTION_NAME + SORTED BY FUN.RDB$SCHEMA_NAME, FUN.RDB$FUNCTION_NAME + { + const QualifiedMetaString functionName(FUN.RDB$FUNCTION_NAME, FUN.RDB$SCHEMA_NAME); - // Null terminate name string - fb_utils::exact_name(FUN.RDB$FUNCTION_NAME); const processing_state rc = - SHOW_grants2(FUN.RDB$FUNCTION_NAME, terminator, obj_udf, - first ? banner : 0, mangle); + SHOW_grants2(functionName, terminator, obj_udf, (first ? banner : 0), extract); + if (rc == SKIP) first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -1326,15 +1253,16 @@ static processing_state list_all_grants2(bool show_role_list, const SCHAR* termi FOR GEN IN RDB$GENERATORS WITH (GEN.RDB$SYSTEM_FLAG NE 1 OR GEN.RDB$SYSTEM_FLAG MISSING) - SORTED BY GEN.RDB$GENERATOR_NAME + SORTED BY GEN.RDB$SCHEMA_NAME, GEN.RDB$GENERATOR_NAME + { + const QualifiedMetaString generatorName(GEN.RDB$GENERATOR_NAME, GEN.RDB$SCHEMA_NAME); - // Null terminate name string - fb_utils::exact_name(GEN.RDB$GENERATOR_NAME); const processing_state rc = - SHOW_grants2(GEN.RDB$GENERATOR_NAME, terminator, obj_generator, - first ? banner : 0, mangle); + SHOW_grants2(generatorName, terminator, obj_generator, (first ? banner : 0), extract); + if (rc == SKIP) first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -1343,32 +1271,12 @@ static processing_state list_all_grants2(bool show_role_list, const SCHAR* termi FOR XCP IN RDB$EXCEPTIONS WITH (XCP.RDB$SYSTEM_FLAG NE 1 OR XCP.RDB$SYSTEM_FLAG MISSING) - SORTED BY XCP.RDB$EXCEPTION_NAME - - // Null terminate name string - fb_utils::exact_name(XCP.RDB$EXCEPTION_NAME); - const processing_state rc = - SHOW_grants2(XCP.RDB$EXCEPTION_NAME, terminator, obj_exception, - first ? banner : 0, mangle); - if (rc == SKIP) - first = false; - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return OBJECT_NOT_FOUND; - END_ERROR - - /*** - FOR FLD IN RDB$FIELDS WITH - FLD.RDB$FIELD_NAME NOT MATCHING "RDB$+" USING "+=[0-9][0-9]* *" - AND FLD.RDB$SYSTEM_FLAG NE 1 - SORTED BY FLD.RDB$FIELD_NAME + SORTED BY XCP.RDB$SCHEMA_NAME, XCP.RDB$EXCEPTION_NAME { - // Null terminate name string - fb_utils::exact_name(FLD.RDB$FIELD_NAME); + const QualifiedMetaString exceptionName(XCP.RDB$EXCEPTION_NAME, XCP.RDB$SCHEMA_NAME); + const processing_state rc = - SHOW_grants2(FLD.RDB$FIELD_NAME, terminator, obj_field, - (first ? banner : 0), mangle); + SHOW_grants2(exceptionName, terminator, obj_exception, (first ? banner : 0), extract); if (rc == SKIP) first = false; @@ -1379,51 +1287,16 @@ static processing_state list_all_grants2(bool show_role_list, const SCHAR* termi return OBJECT_NOT_FOUND; END_ERROR - FOR CS IN RDB$CHARACTER_SETS - SORTED BY CS.RDB$CHARACTER_SET_NAME - { - // Null terminate name string - fb_utils::exact_name(CS.RDB$CHARACTER_SET_NAME); - const processing_state rc = - SHOW_grants2(CS.RDB$CHARACTER_SET_NAME, terminator, obj_charset, - (first ? banner : 0), mangle); - - if (rc == SKIP) - first = false; - } - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return OBJECT_NOT_FOUND; - END_ERROR - - FOR COL IN RDB$COLLATIONS - SORTED BY COL.RDB$COLLATION_NAME - { - // Null terminate name string - fb_utils::exact_name(COL.RDB$COLLATION_NAME); - const processing_state rc = - SHOW_grants2(COL.RDB$COLLATION_NAME, terminator, obj_collation, - (first ? banner : 0), mangle); - - if (rc == SKIP) - first = false; - } - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return OBJECT_NOT_FOUND; - END_ERROR - ***/ - // Process DDL permissions for (SSHORT obj = obj_database; obj < obj_type_MAX; obj++) { if (!isDdlObject(obj)) continue; - const processing_state rc = - SHOW_grants2(getSecurityClassName(obj), terminator, obj, first ? banner : 0, mangle); + // FIXME: schemas + const processing_state rc = SHOW_grants2( + QualifiedMetaString(getSecurityClassName(obj)), terminator, obj, first ? banner : 0, extract); + if (rc == SKIP) first = false; } @@ -1479,7 +1352,7 @@ static void print_proc_suffix(int obj_type) isqlGlob.printf("SET AUTODDL ON%s%s", isqlGlob.global_Term, NEWLINE); } -static void list_procedure_headers(SSHORT default_char_set_id) +static void list_procedure_headers(GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc) { /************************************** * @@ -1507,26 +1380,22 @@ static void list_procedure_headers(SSHORT default_char_set_id) // create the procedures with their parameters FOR PRC IN RDB$PROCEDURES - WITH (PRC.RDB$SYSTEM_FLAG NE 1 OR PRC.RDB$SYSTEM_FLAG MISSING) - AND PRC.RDB$PACKAGE_NAME MISSING - SORTED BY PRC.RDB$PROCEDURE_NAME + WITH (PRC.RDB$SYSTEM_FLAG NE 1 OR PRC.RDB$SYSTEM_FLAG MISSING) AND + PRC.RDB$PACKAGE_NAME MISSING + SORTED BY PRC.RDB$SCHEMA_NAME, PRC.RDB$PROCEDURE_NAME + { + const QualifiedMetaString name(PRC.RDB$PROCEDURE_NAME, PRC.RDB$SCHEMA_NAME); + if (header) { print_proc_prefix(obj_procedure, true); header = false; } - fb_utils::exact_name(PRC.RDB$PROCEDURE_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (PRC.RDB$PROCEDURE_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf(create_procedure, SQL_identifier); - } - else - { - isqlGlob.printf(create_procedure, PRC.RDB$PROCEDURE_NAME, default_char_set_id); - } - get_procedure_args(PRC.RDB$PROCEDURE_NAME, default_char_set_id); + isqlGlob.printf(create_procedure, ISQL_name_to_string(name).c_str()); + + get_procedure_args(name, getDefaultCharSetForSchemaFunc); + isqlGlob.printf("AS %s", NEWLINE); prc_t proc_type = PRC.RDB$PROCEDURE_TYPE.NULL ? prc_legacy : (prc_t) PRC.RDB$PROCEDURE_TYPE; @@ -1536,12 +1405,13 @@ static void list_procedure_headers(SSHORT default_char_set_id) isqlGlob.printf(body_execut_proc, Procterm, NEWLINE); else isqlGlob.printf(body_select_proc, Procterm, NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR + // Only reset the terminators if there were procs to print if (!header) print_proc_suffix(obj_procedure); @@ -1549,7 +1419,7 @@ static void list_procedure_headers(SSHORT default_char_set_id) -static void list_procedure_bodies(SSHORT default_char_set_id) +static void list_procedure_bodies(GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc) { /************************************** * @@ -1571,25 +1441,21 @@ static void list_procedure_bodies(SSHORT default_char_set_id) TEXT msg[MSG_LENGTH]; FOR PRC IN RDB$PROCEDURES - WITH (PRC.RDB$SYSTEM_FLAG NE 1 OR PRC.RDB$SYSTEM_FLAG MISSING) - AND PRC.RDB$PACKAGE_NAME MISSING - SORTED BY PRC.RDB$PROCEDURE_NAME + WITH (PRC.RDB$SYSTEM_FLAG NE 1 OR PRC.RDB$SYSTEM_FLAG MISSING) AND + PRC.RDB$PACKAGE_NAME MISSING + SORTED BY PRC.RDB$SCHEMA_NAME, PRC.RDB$PROCEDURE_NAME + { + const QualifiedMetaString name(PRC.RDB$PROCEDURE_NAME, PRC.RDB$SCHEMA_NAME); + if (header) { print_proc_prefix(obj_procedure, false); header = false; } - fb_utils::exact_name(PRC.RDB$PROCEDURE_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (PRC.RDB$PROCEDURE_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf("%sALTER PROCEDURE %s ", NEWLINE, SQL_identifier); - } - else - isqlGlob.printf("%sALTER PROCEDURE %s ", NEWLINE, PRC.RDB$PROCEDURE_NAME); + isqlGlob.printf("%sALTER PROCEDURE %s ", NEWLINE, ISQL_name_to_string(name).c_str()); - get_procedure_args(PRC.RDB$PROCEDURE_NAME, default_char_set_id); + get_procedure_args(name, getDefaultCharSetForSchemaFunc); // Print the procedure body @@ -1625,14 +1491,14 @@ static void list_procedure_bodies(SSHORT default_char_set_id) } isqlGlob.printf(" %s%s", Procterm, NEWLINE); - + } END_FOR ON_ERROR IUTILS_msg_get(GEN_ERR, msg, SafeArg() << isc_sqlcode(fbStatus->getErrors())); STDERROUT(msg); // Statement failed, SQLCODE = %d\n\n ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR // Only reset the terminators if there were procs to print if (!header) @@ -1641,7 +1507,7 @@ static void list_procedure_bodies(SSHORT default_char_set_id) -static void list_all_tables(LegacyTables flag, SSHORT default_char_set_id) +static void list_all_tables(LegacyTables flag, GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc) { /************************************** * @@ -1660,27 +1526,26 @@ static void list_all_tables(LegacyTables flag, SSHORT default_char_set_id) // This version of cursor gets only sql tables identified by security class // and misses views, getting only null view_source - FOR REL IN RDB$RELATIONS WITH - (REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND - REL.RDB$VIEW_BLR MISSING - SORTED BY REL.RDB$RELATION_NAME - + FOR REL IN RDB$RELATIONS + WITH (REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND + REL.RDB$VIEW_BLR MISSING + SORTED BY REL.RDB$SCHEMA_NAME, REL.RDB$RELATION_NAME + { // If this is not an SQL table and we aren't doing ALL objects if ((REL.RDB$FLAGS.NULL || !(REL.RDB$FLAGS & REL_sql)) && (flag != ALL_objects) ) continue; - // Null terminate name string - fb_utils::exact_name(REL.RDB$RELATION_NAME); + const QualifiedMetaString relationName(REL.RDB$RELATION_NAME, REL.RDB$SCHEMA_NAME); if (flag || !strncmp (REL.RDB$SECURITY_CLASS, "SQL$", 4)) - EXTRACT_list_table (REL.RDB$RELATION_NAME, NULL, false, default_char_set_id); + EXTRACT_list_table(relationName, {}, false, getDefaultCharSetForSchemaFunc); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); ROLLBACK; return; - END_ERROR; - + END_ERROR } @@ -1705,14 +1570,15 @@ static void list_all_triggers() FOR TRG IN RDB$TRIGGERS WITH (TRG.RDB$SYSTEM_FLAG EQ 0 OR TRG.RDB$SYSTEM_FLAG MISSING) AND TRG.RDB$RELATION_NAME MISSING - SORTED BY TRG.RDB$TRIGGER_TYPE, TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME - + SORTED BY TRG.RDB$TRIGGER_TYPE, TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$SCHEMA_NAME, TRG.RDB$TRIGGER_NAME + { if (header) { print_proc_prefix(obj_trigger, false); header = false; } - fb_utils::exact_name(TRG.RDB$TRIGGER_NAME); + + const QualifiedMetaString name(TRG.RDB$TRIGGER_NAME, TRG.RDB$SCHEMA_NAME); if (TRG.RDB$TRIGGER_INACTIVE.NULL) TRG.RDB$TRIGGER_INACTIVE = 0; @@ -1721,13 +1587,9 @@ static void list_all_triggers() if (!(TRG.RDB$FLAGS & TRG_sql)) isqlGlob.printf("/* "); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id (TRG.RDB$TRIGGER_NAME, SQL_identifier, DBL_QUOTE); - else - strcpy (SQL_identifier, TRG.RDB$TRIGGER_NAME); - isqlGlob.printf("CREATE TRIGGER %s %s%s %s POSITION %d %s", - SQL_identifier, NEWLINE, + ISQL_name_to_string(name).c_str(), + NEWLINE, (TRG.RDB$TRIGGER_INACTIVE ? "INACTIVE" : "ACTIVE"), SHOW_trigger_action(TRG.RDB$TRIGGER_TYPE).c_str(), TRG.RDB$TRIGGER_SEQUENCE, NEWLINE); @@ -1767,21 +1629,24 @@ static void list_all_triggers() { isqlGlob.printf("*/%s", NEWLINE); } - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR - FOR TRG IN RDB$TRIGGERS CROSS REL IN RDB$RELATIONS OVER RDB$RELATION_NAME + FOR TRG IN RDB$TRIGGERS CROSS + REL IN RDB$RELATIONS //WITH (REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND //NOT (ANY CHK IN RDB$CHECK_CONSTRAINTS WITH //TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME) - WITH (TRG.RDB$SYSTEM_FLAG EQ 0 OR TRG.RDB$SYSTEM_FLAG MISSING) - SORTED BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE, - TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME - + WITH REL.RDB$SCHEMA_NAME EQUIV TRG.RDB$SCHEMA_NAME AND + REL.RDB$RELATION_NAME EQ TRG.RDB$RELATION_NAME AND + (TRG.RDB$SYSTEM_FLAG EQ 0 OR TRG.RDB$SYSTEM_FLAG MISSING) + SORTED BY TRG.RDB$SCHEMA_NAME, TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE, + TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME + { if (header) { isqlGlob.printf("SET TERM %s %s%s", Procterm, isqlGlob.global_Term, NEWLINE); @@ -1790,8 +1655,9 @@ static void list_all_triggers() NEWLINE); header = false; } - fb_utils::exact_name(TRG.RDB$TRIGGER_NAME); - fb_utils::exact_name(TRG.RDB$RELATION_NAME); + + const QualifiedMetaString name(TRG.RDB$TRIGGER_NAME, TRG.RDB$SCHEMA_NAME); + const MetaString relationName(TRG.RDB$RELATION_NAME); if (TRG.RDB$TRIGGER_INACTIVE.NULL) TRG.RDB$TRIGGER_INACTIVE = 0; @@ -1800,19 +1666,10 @@ static void list_all_triggers() if (!(TRG.RDB$FLAGS & TRG_sql)) isqlGlob.printf("/* "); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (TRG.RDB$TRIGGER_NAME, SQL_identifier, DBL_QUOTE); - IUTILS_copy_SQL_id (TRG.RDB$RELATION_NAME, SQL_identifier2, DBL_QUOTE); - } - else - { - strcpy (SQL_identifier, TRG.RDB$TRIGGER_NAME); - strcpy (SQL_identifier2, TRG.RDB$RELATION_NAME); - } - isqlGlob.printf("CREATE TRIGGER %s FOR %s %s%s %s POSITION %d %s", - SQL_identifier, SQL_identifier2, NEWLINE, + ISQL_name_to_string(name).c_str(), + ISQL_name_to_string(relationName).c_str(), + NEWLINE, (TRG.RDB$TRIGGER_INACTIVE ? "INACTIVE" : "ACTIVE"), SHOW_trigger_action(TRG.RDB$TRIGGER_TYPE).c_str(), TRG.RDB$TRIGGER_SEQUENCE, NEWLINE); @@ -1852,12 +1709,12 @@ static void list_all_triggers() { isqlGlob.printf("*/%s", NEWLINE); } - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR if (!header) print_proc_suffix(obj_trigger); @@ -1882,57 +1739,47 @@ static void list_check() bool first = true; FOR TRG IN RDB$TRIGGERS CROSS - CHK IN RDB$CHECK_CONSTRAINTS WITH - TRG.RDB$TRIGGER_TYPE EQ 1 AND - TRG.RDB$SYSTEM_FLAG EQ int(fb_sysflag_check_constraint) AND - TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME AND - (ANY RELC IN RDB$RELATION_CONSTRAINTS WITH - CHK.RDB$CONSTRAINT_NAME EQ RELC.RDB$CONSTRAINT_NAME - AND RELC.RDB$CONSTRAINT_TYPE EQ "CHECK") - REDUCED TO CHK.RDB$CONSTRAINT_NAME - SORTED BY CHK.RDB$CONSTRAINT_NAME - + CHK IN RDB$CHECK_CONSTRAINTS + WITH TRG.RDB$TRIGGER_TYPE EQ 1 AND + TRG.RDB$SYSTEM_FLAG EQ int(fb_sysflag_check_constraint) AND + TRG.RDB$SCHEMA_NAME EQUIV CHK.RDB$SCHEMA_NAME AND + TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME AND + (ANY RELC IN RDB$RELATION_CONSTRAINTS + WITH CHK.RDB$SCHEMA_NAME EQUIV RELC.RDB$SCHEMA_NAME AND + CHK.RDB$CONSTRAINT_NAME EQ RELC.RDB$CONSTRAINT_NAME AND + RELC.RDB$CONSTRAINT_TYPE EQ "CHECK") + REDUCED TO CHK.RDB$SCHEMA_NAME, CHK.RDB$CONSTRAINT_NAME + SORTED BY CHK.RDB$SCHEMA_NAME, CHK.RDB$CONSTRAINT_NAME + { if (first) { isqlGlob.printf("%s/* Table constraints */%s", NEWLINE, NEWLINE); first = false; } - fb_utils::exact_name(TRG.RDB$RELATION_NAME); + const QualifiedMetaString relationName(TRG.RDB$RELATION_NAME, TRG.RDB$SCHEMA_NAME); isqlGlob.printf(NEWLINE); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (TRG.RDB$RELATION_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf("ALTER TABLE %s ADD %s%s", SQL_identifier, NEWLINE, TAB_AS_SPACES); - } - else - isqlGlob.printf("ALTER TABLE %s ADD %s%s", TRG.RDB$RELATION_NAME, NEWLINE, TAB_AS_SPACES); + isqlGlob.printf("ALTER TABLE %s ADD %s%s", ISQL_name_to_string(relationName).c_str(), NEWLINE, TAB_AS_SPACES); // If the name of the constraint is not INTEG_..., print it if (!fb_utils::implicit_integrity(CHK.RDB$CONSTRAINT_NAME)) { - fb_utils::exact_name(CHK.RDB$CONSTRAINT_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (CHK.RDB$CONSTRAINT_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf("CONSTRAINT %s ", SQL_identifier); - } - else - isqlGlob.printf("CONSTRAINT %s ", CHK.RDB$CONSTRAINT_NAME); + const MetaString constraintName(CHK.RDB$CONSTRAINT_NAME); + isqlGlob.printf("CONSTRAINT %s ", ISQL_name_to_string(constraintName).c_str()); } if (!TRG.RDB$TRIGGER_SOURCE.NULL) SHOW_print_metadata_text_blob (isqlGlob.Out, &TRG.RDB$TRIGGER_SOURCE); isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR } @@ -1952,37 +1799,33 @@ static void list_charsets() bool first = true; FOR CS IN RDB$CHARACTER_SETS - WITH NOT CS.RDB$CHARACTER_SET_NAME EQ CS.RDB$DEFAULT_COLLATE_NAME - SORTED BY CS.RDB$CHARACTER_SET_NAME - + WITH NOT ( + CS.RDB$SCHEMA_NAME EQUIV CS.RDB$DEFAULT_COLLATE_SCHEMA_NAME AND + CS.RDB$CHARACTER_SET_NAME EQ CS.RDB$DEFAULT_COLLATE_NAME) + SORTED BY CS.RDB$SCHEMA_NAME, CS.RDB$CHARACTER_SET_NAME + { if (first) { isqlGlob.printf("%s/* Character sets */%s", NEWLINE, NEWLINE); first = false; } - isqlGlob.printf("ALTER CHARACTER SET "); + const QualifiedMetaString name(CS.RDB$CHARACTER_SET_NAME, CS.RDB$SCHEMA_NAME); + const QualifiedMetaString defaultCollateName( + CS.RDB$DEFAULT_COLLATE_NAME, CS.RDB$DEFAULT_COLLATE_SCHEMA_NAME); - fb_utils::exact_name(CS.RDB$CHARACTER_SET_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id (CS.RDB$CHARACTER_SET_NAME, SQL_identifier, DBL_QUOTE); - else - strcpy (SQL_identifier, CS.RDB$CHARACTER_SET_NAME); - isqlGlob.printf("%s", SQL_identifier); - - fb_utils::exact_name(CS.RDB$DEFAULT_COLLATE_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id (CS.RDB$DEFAULT_COLLATE_NAME, SQL_identifier, DBL_QUOTE); - else - strcpy (SQL_identifier, CS.RDB$DEFAULT_COLLATE_NAME); - isqlGlob.printf(" SET DEFAULT COLLATION %s", SQL_identifier); + isqlGlob.printf( + "ALTER CHARACTER SET %s SET DEFAULT COLLATION %s", + ISQL_name_to_string(name).c_str(), + ISQL_name_to_string(defaultCollateName).c_str()); isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR if (! first) isqlGlob.printf(NEWLINE); @@ -2008,32 +1851,24 @@ static void list_collations() bool first = true; FOR CL IN RDB$COLLATIONS CROSS - CS IN RDB$CHARACTER_SETS WITH - CS.RDB$CHARACTER_SET_ID EQ CL.RDB$CHARACTER_SET_ID AND - (CL.RDB$SYSTEM_FLAG MISSING OR CL.RDB$SYSTEM_FLAG NE 1) - SORTED BY CS.RDB$CHARACTER_SET_NAME, CL.RDB$COLLATION_NAME - + CS IN RDB$CHARACTER_SETS + WITH CS.RDB$CHARACTER_SET_ID EQ CL.RDB$CHARACTER_SET_ID AND + (CL.RDB$SYSTEM_FLAG MISSING OR CL.RDB$SYSTEM_FLAG NE 1) + SORTED BY CS.RDB$SCHEMA_NAME, CS.RDB$CHARACTER_SET_NAME, CL.RDB$SCHEMA_NAME, CL.RDB$COLLATION_NAME + { if (first) { isqlGlob.printf("%s/* Collations */%s", NEWLINE, NEWLINE); first = false; } - isqlGlob.printf("CREATE COLLATION "); + const QualifiedMetaString name(CL.RDB$COLLATION_NAME, CL.RDB$SCHEMA_NAME); + const QualifiedMetaString charSetName(CS.RDB$CHARACTER_SET_NAME, CS.RDB$SCHEMA_NAME); - fb_utils::exact_name(CL.RDB$COLLATION_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id (CL.RDB$COLLATION_NAME, SQL_identifier, DBL_QUOTE); - else - strcpy (SQL_identifier, CL.RDB$COLLATION_NAME); - isqlGlob.printf("%s", SQL_identifier); - - fb_utils::exact_name(CS.RDB$CHARACTER_SET_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id (CS.RDB$CHARACTER_SET_NAME, SQL_identifier, DBL_QUOTE); - else - strcpy (SQL_identifier, CS.RDB$CHARACTER_SET_NAME); - isqlGlob.printf(" FOR %s", SQL_identifier); + isqlGlob.printf( + "CREATE COLLATION %s FOR %s", + ISQL_name_to_string(name).c_str(), + ISQL_name_to_string(charSetName).c_str()); if (!CL.RDB$BASE_COLLATION_NAME.NULL) { @@ -2062,11 +1897,12 @@ static void list_collations() } isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR isqlGlob.printf(NEWLINE); } @@ -2109,36 +1945,46 @@ static void list_create_db() SHOW_dbb_parameters(DB, page_items, sizeof(page_items), translate, " "); FOR DBP IN RDB$DATABASE - WITH DBP.RDB$CHARACTER_SET_NAME NOT MISSING - AND DBP.RDB$CHARACTER_SET_NAME != " " + WITH DBP.RDB$CHARACTER_SET_NAME NOT MISSING AND + DBP.RDB$CHARACTER_SET_NAME != " " + { + const QualifiedMetaString charSetName( + DBP.RDB$CHARACTER_SET_NAME, DBP.RDB$CHARACTER_SET_SCHEMA_NAME); + isqlGlob.printf("DEFAULT CHARACTER SET %s%s", - fb_utils::exact_name(DBP.RDB$CHARACTER_SET_NAME), isqlGlob.global_Term); + ISQL_name_to_string(charSetName).c_str(), + isqlGlob.global_Term); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR FOR DBP2 IN RDB$DATABASE - WITH DBP2.RDB$LINGER NOT MISSING - AND DBP2.RDB$LINGER > 0 + WITH DBP2.RDB$LINGER NOT MISSING AND + DBP2.RDB$LINGER > 0 + { isqlGlob.printf("%sALTER DATABASE SET LINGER TO %d%s", NEWLINE, DBP2.RDB$LINGER, isqlGlob.global_Term); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR FOR DBPSS IN RDB$DATABASE - WITH DBPSS.RDB$SQL_SECURITY NOT MISSING - AND DBPSS.RDB$SQL_SECURITY == FB_TRUE + WITH DBPSS.RDB$SQL_SECURITY NOT MISSING AND + DBPSS.RDB$SQL_SECURITY == FB_TRUE + { isqlGlob.printf("%sALTER DATABASE SET DEFAULT SQL SECURITY DEFINER%s", NEWLINE, isqlGlob.global_Term); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR if (nodb) isqlGlob.printf(" */%s", NEWLINE); @@ -2151,7 +1997,7 @@ static void list_create_db() FOR FIL IN RDB$FILES SORTED BY FIL.RDB$SHADOW_NUMBER, FIL.RDB$FILE_SEQUENCE - + { // reset nulls to zero if (FIL.RDB$FILE_FLAGS.NULL) FIL.RDB$FILE_FLAGS = 0; @@ -2233,12 +2079,12 @@ static void list_create_db() isqlGlob.printf("%sALTER DATABASE ADD DIFFERENCE FILE '%s'", NEWLINE, FIL.RDB$FILE_NAME); isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); } - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR if (!first) { @@ -2248,7 +2094,8 @@ static void list_create_db() } -static void list_domain_table(const SCHAR* table_name, SSHORT default_char_set_id) +static void list_domain_table(const QualifiedMetaString& table_name, + GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc) { /************************************** * @@ -2265,14 +2112,16 @@ static void list_domain_table(const SCHAR* table_name, SSHORT default_char_set_i * **************************************/ bool first = true; - SCHAR char_sets[CHARSET_COLLATE_SIZE]; + string char_sets; FOR FLD IN RDB$FIELDS CROSS - RFR IN RDB$RELATION_FIELDS WITH - RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND - RFR.RDB$RELATION_NAME EQ table_name - SORTED BY FLD.RDB$FIELD_NAME - + RFR IN RDB$RELATION_FIELDS + WITH RFR.RDB$FIELD_SOURCE_SCHEMA_NAME EQUIV FLD.RDB$SCHEMA_NAME AND + RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND + RFR.RDB$SCHEMA_NAME EQUIV NULLIF(table_name.schema.c_str(), '') AND + RFR.RDB$RELATION_NAME EQ table_name.object.c_str() + SORTED BY FLD.RDB$SCHEMA_NAME, FLD.RDB$FIELD_NAME + { // Skip over artificial domains if (fb_utils::implicit_domain(FLD.RDB$FIELD_NAME) && (FLD.RDB$SYSTEM_FLAG.NULL || FLD.RDB$SYSTEM_FLAG != 1)) @@ -2285,11 +2134,12 @@ static void list_domain_table(const SCHAR* table_name, SSHORT default_char_set_i isqlGlob.printf("/* Domain definitions */%s", NEWLINE); first = false; } - fb_utils::exact_name(FLD.RDB$FIELD_NAME); - isqlGlob.printf("CREATE DOMAIN %s AS ", FLD.RDB$FIELD_NAME); + const QualifiedMetaString name(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME); - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, + isqlGlob.printf("CREATE DOMAIN %s AS ", ISQL_name_to_string(name).c_str()); + + if (!ISQL_printNumericType(name, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) { return; // ps_ERR; @@ -2312,11 +2162,11 @@ static void list_domain_table(const SCHAR* table_name, SSHORT default_char_set_i else if ((FLD.RDB$FIELD_TYPE == blr_text) || (FLD.RDB$FIELD_TYPE == blr_varying)) { // Length for chars - isqlGlob.printf("(%d)", ISQL_get_field_length(FLD.RDB$FIELD_NAME)); + isqlGlob.printf("(%d)", ISQL_get_field_length(name)); } if (!FLD.RDB$DIMENSIONS.NULL) - ISQL_array_dimensions(FLD.RDB$FIELD_NAME); + ISQL_array_dimensions(name); // Bug 8261: do not show the collation information just yet! If you // do, then the domain syntax when printed is not correct. @@ -2326,11 +2176,12 @@ static void list_domain_table(const SCHAR* table_name, SSHORT default_char_set_i !(((FLD.RDB$FIELD_TYPE == blr_text) || (FLD.RDB$FIELD_TYPE == blr_varying)) && FLD.RDB$FIELD_SUB_TYPE != fb_text_subtype_text)) { + ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, FLD.RDB$COLLATION_ID, + getDefaultCharSetForSchemaFunc(name.schema), + Get::CHARSET_ONLY, false, char_sets); - char_sets[0] = 0; - ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, FLD.RDB$COLLATION_ID, default_char_set_id, Get::CHARSET_ONLY, false, true, char_sets); - if (char_sets[0]) - isqlGlob.prints(char_sets); + if (char_sets.hasData()) + isqlGlob.prints(char_sets.c_str()); } if (!FLD.RDB$DEFAULT_SOURCE.NULL) @@ -2355,24 +2206,25 @@ static void list_domain_table(const SCHAR* table_name, SSHORT default_char_set_i if (!FLD.RDB$COLLATION_ID.NULL) { - char_sets[0] = 0; - ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, FLD.RDB$COLLATION_ID, default_char_set_id, Get::COLLATE_ONLY, - false, true, char_sets); + ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, FLD.RDB$COLLATION_ID, + getDefaultCharSetForSchemaFunc(name.schema), + Get::COLLATE_ONLY, false, char_sets); - if (char_sets[0]) - isqlGlob.prints(char_sets); + if (char_sets.hasData()) + isqlGlob.prints(char_sets.c_str()); } isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR } -static void list_domains(SSHORT default_char_set_id) +static void list_domains(GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc) { /************************************** * @@ -2388,29 +2240,24 @@ static void list_domains(SSHORT default_char_set_id) * **************************************/ bool first = true; - SCHAR char_sets[CHARSET_COLLATE_SIZE]; - - FOR FLD IN RDB$FIELDS WITH - FLD.RDB$FIELD_NAME NOT MATCHING "RDB$+" USING "+=[0-9][0-9]* *" - AND FLD.RDB$SYSTEM_FLAG NE 1 - SORTED BY FLD.RDB$FIELD_NAME + string char_sets; + FOR FLD IN RDB$FIELDS + WITH FLD.RDB$FIELD_NAME NOT MATCHING "RDB$+" USING "+=[0-9][0-9]* *" AND + FLD.RDB$SYSTEM_FLAG NE 1 + SORTED BY FLD.RDB$SCHEMA_NAME, FLD.RDB$FIELD_NAME + { if (first) { isqlGlob.printf("/* Domain definitions */%s", NEWLINE); first = false; } - fb_utils::exact_name(FLD.RDB$FIELD_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id(FLD.RDB$FIELD_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf("CREATE DOMAIN %s AS ", SQL_identifier); - } - else - isqlGlob.printf("CREATE DOMAIN %s AS ", FLD.RDB$FIELD_NAME); + const QualifiedMetaString name(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME); - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, + isqlGlob.printf("CREATE DOMAIN %s AS ", ISQL_name_to_string(name).c_str()); + + if (!ISQL_printNumericType(name, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) { return; // ps_ERR; @@ -2434,11 +2281,11 @@ static void list_domains(SSHORT default_char_set_id) else if ((FLD.RDB$FIELD_TYPE == blr_text) || (FLD.RDB$FIELD_TYPE == blr_varying)) { // Length for chars - isqlGlob.printf("(%d)", ISQL_get_field_length(FLD.RDB$FIELD_NAME)); + isqlGlob.printf("(%d)", ISQL_get_field_length(name)); } if (!FLD.RDB$DIMENSIONS.NULL) - ISQL_array_dimensions(FLD.RDB$FIELD_NAME); + ISQL_array_dimensions(name); // Bug 8261: do not show the collation information just yet! If you // do, then the domain syntax when printed is not correct. @@ -2448,10 +2295,12 @@ static void list_domains(SSHORT default_char_set_id) !(((FLD.RDB$FIELD_TYPE == blr_text) || (FLD.RDB$FIELD_TYPE == blr_varying)) && FLD.RDB$FIELD_SUB_TYPE != fb_text_subtype_text)) { - char_sets[0] = 0; - ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, FLD.RDB$COLLATION_ID, default_char_set_id, Get::CHARSET_ONLY, false, true, char_sets); - if (char_sets[0]) - isqlGlob.prints(char_sets); + ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, FLD.RDB$COLLATION_ID, + getDefaultCharSetForSchemaFunc(name.schema), + Get::CHARSET_ONLY, false, char_sets); + + if (char_sets.hasData()) + isqlGlob.prints(char_sets.c_str()); } if (!FLD.RDB$DEFAULT_SOURCE.NULL) @@ -2472,20 +2321,22 @@ static void list_domains(SSHORT default_char_set_id) if (!FLD.RDB$COLLATION_ID.NULL) { - char_sets[0] = 0; - ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, FLD.RDB$COLLATION_ID, default_char_set_id, Get::COLLATE_ONLY, - false, true, char_sets); + ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, FLD.RDB$COLLATION_ID, + getDefaultCharSetForSchemaFunc(name.schema), + Get::COLLATE_ONLY, false, char_sets); - if (char_sets[0]) - isqlGlob.prints(char_sets); + if (char_sets.hasData()) + isqlGlob.prints(char_sets.c_str()); } isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR + isqlGlob.printf("COMMIT WORK%s%s", isqlGlob.global_Term, NEWLINE); } @@ -2494,47 +2345,43 @@ static void listDomainConstraints() { bool first = true; - FOR FLD IN RDB$FIELDS WITH - FLD.RDB$FIELD_NAME NOT MATCHING "RDB$+" USING "+=[0-9][0-9]* *" - AND FLD.RDB$SYSTEM_FLAG NE 1 - AND FLD.RDB$VALIDATION_SOURCE NOT MISSING - SORTED BY FLD.RDB$FIELD_NAME - + FOR FLD IN RDB$FIELDS + WITH FLD.RDB$FIELD_NAME NOT MATCHING "RDB$+" USING "+=[0-9][0-9]* *" AND + FLD.RDB$SYSTEM_FLAG NE 1 AND + FLD.RDB$VALIDATION_SOURCE NOT MISSING + SORTED BY FLD.RDB$SCHEMA_NAME, FLD.RDB$FIELD_NAME + { if (first) { isqlGlob.printf("%s/* Domain constraints */%s", NEWLINE, NEWLINE); first = false; } - fb_utils::exact_name(FLD.RDB$FIELD_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id(FLD.RDB$FIELD_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf("ALTER DOMAIN %s ADD CONSTRAINT", SQL_identifier); - } - else - isqlGlob.printf("ALTER DOMAIN %s ADD CONSTRAINT", FLD.RDB$FIELD_NAME); + const QualifiedMetaString name(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME); + + isqlGlob.printf("ALTER DOMAIN %s ADD CONSTRAINT", ISQL_name_to_string(name).c_str()); isqlGlob.printf("%s%s ", NEWLINE, TAB_AS_SPACES); ISQL_print_validation (isqlGlob.Out, &FLD.RDB$VALIDATION_SOURCE, false, fbTrans); isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR } // Fix computed field expressions. -static void listRelationComputed(LegacyTables flag, SSHORT default_char_set_id) +static void listRelationComputed(LegacyTables flag, GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc) { // This version of cursor gets only sql tables identified by security class // and misses views, getting only null view_source - Firebird::string lastTable; - SCHAR char_sets[CHARSET_COLLATE_SIZE]; + QualifiedMetaString lastRelation; + string char_sets; FOR REL IN RDB$RELATIONS CROSS RFR IN RDB$RELATION_FIELDS CROSS @@ -2542,10 +2389,12 @@ static void listRelationComputed(LegacyTables flag, SSHORT default_char_set_id) WITH (REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND REL.RDB$VIEW_BLR MISSING AND FLD.RDB$COMPUTED_BLR NOT MISSING AND + RFR.RDB$FIELD_SOURCE_SCHEMA_NAME EQUIV FLD.RDB$SCHEMA_NAME AND RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND + RFR.RDB$SCHEMA_NAME EQUIV REL.RDB$SCHEMA_NAME AND RFR.RDB$RELATION_NAME EQ REL.RDB$RELATION_NAME - SORTED BY REL.RDB$RELATION_NAME, RFR.RDB$FIELD_POSITION, RFR.RDB$FIELD_NAME - + SORTED BY REL.RDB$SCHEMA_NAME, REL.RDB$RELATION_NAME, RFR.RDB$FIELD_POSITION, RFR.RDB$FIELD_NAME + { // If this is not an SQL table and we aren't doing ALL objects if ((REL.RDB$FLAGS.NULL || !(REL.RDB$FLAGS & REL_sql)) && (flag != ALL_objects) ) continue; @@ -2553,44 +2402,29 @@ static void listRelationComputed(LegacyTables flag, SSHORT default_char_set_id) SSHORT collation = 0; SSHORT char_set_id = 0; - // Null terminate name string - fb_utils::exact_name(REL.RDB$RELATION_NAME); + const QualifiedMetaString relationName(REL.RDB$RELATION_NAME, REL.RDB$SCHEMA_NAME); + const QualifiedMetaString fieldName(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME); if (flag || !strncmp(REL.RDB$SECURITY_CLASS, "SQL$", 4)) { - if (lastTable.isEmpty()) + if (lastRelation.object.isEmpty()) isqlGlob.printf("%s/* Computed fields */%s%s", NEWLINE, NEWLINE, NEWLINE); - if (lastTable != REL.RDB$RELATION_NAME) + if (lastRelation != relationName) { - if (!lastTable.isEmpty()) + if (!lastRelation.object.isEmpty()) isqlGlob.printf("%s%s%s", isqlGlob.global_Term, NEWLINE, NEWLINE); - isqlGlob.printf("ALTER TABLE "); + isqlGlob.printf("ALTER TABLE %s", ISQL_name_to_string(relationName).c_str()); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id(REL.RDB$RELATION_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf("%s ", SQL_identifier); - } - else - isqlGlob.printf("%s ", REL.RDB$RELATION_NAME); - - lastTable = REL.RDB$RELATION_NAME; + lastRelation = relationName; } else isqlGlob.printf(","); - isqlGlob.printf("%s%sALTER ", NEWLINE, TAB_AS_SPACES); - - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id(fb_utils::exact_name(RFR.RDB$FIELD_NAME), SQL_identifier, DBL_QUOTE); - isqlGlob.printf("%s ", SQL_identifier); - } - else - isqlGlob.printf("%s ", fb_utils::exact_name(RFR.RDB$FIELD_NAME)); + const MetaString columnName(RFR.RDB$FIELD_NAME); + isqlGlob.printf("%s%sALTER %s ", NEWLINE, TAB_AS_SPACES, ISQL_name_to_string(columnName).c_str()); isqlGlob.printf("TYPE "); /* @@ -2599,34 +2433,28 @@ static void listRelationComputed(LegacyTables flag, SSHORT default_char_set_id) ** may have not null, default and check overriding their definitions */ - if (!(fb_utils::implicit_domain(FLD.RDB$FIELD_NAME) && FLD.RDB$SYSTEM_FLAG != 1)) + if (!(fb_utils::implicit_domain(fieldName.object.c_str()) && FLD.RDB$SYSTEM_FLAG != 1)) { - fb_utils::exact_name(FLD.RDB$FIELD_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (FLD.RDB$FIELD_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.prints(SQL_identifier); - } - else - isqlGlob.prints(FLD.RDB$FIELD_NAME); + isqlGlob.prints(ISQL_name_to_string(fieldName).c_str()); // International character sets // Print only the collation if ((FLD.RDB$FIELD_TYPE == blr_text || FLD.RDB$FIELD_TYPE == blr_varying) && !RFR.RDB$COLLATION_ID.NULL) { - char_sets[0] = '\0'; collation = RFR.RDB$COLLATION_ID; char_set_id = FLD.RDB$CHARACTER_SET_ID; - ISQL_get_character_sets(char_set_id, collation, default_char_set_id, Get::COLLATE_ONLY, false, true, char_sets); + ISQL_get_character_sets(char_set_id, collation, + getDefaultCharSetForSchemaFunc(relationName.schema), + Get::COLLATE_ONLY, false, char_sets); - if (char_sets[0]) - isqlGlob.prints(char_sets); + if (char_sets.hasData()) + isqlGlob.prints(char_sets.c_str()); } } else { - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, + if (!ISQL_printNumericType(fieldName, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) { return; @@ -2646,7 +2474,7 @@ static void listRelationComputed(LegacyTables flag, SSHORT default_char_set_id) // Catch arrays after printing the type if (!FLD.RDB$DIMENSIONS.NULL) - ISQL_array_dimensions(FLD.RDB$FIELD_NAME); + ISQL_array_dimensions(fieldName); if (FLD.RDB$FIELD_TYPE == blr_blob) { @@ -2667,7 +2495,7 @@ static void listRelationComputed(LegacyTables flag, SSHORT default_char_set_id) FLD.RDB$FIELD_TYPE == blr_blob) && !FLD.RDB$CHARACTER_SET_ID.NULL) { - char_sets[0] = '\0'; + char_sets.clear(); // Override rdb$fields id with relation_fields if present @@ -2678,13 +2506,16 @@ static void listRelationComputed(LegacyTables flag, SSHORT default_char_set_id) if (!FLD.RDB$CHARACTER_SET_ID.NULL) char_set_id = FLD.RDB$CHARACTER_SET_ID; - if (char_set_id != default_char_set_id) + if (char_set_id != getDefaultCharSetForSchemaFunc(relationName.schema)) { // Currently ALTER TABLE syntax doesn't allow collation here. - ISQL_get_character_sets(char_set_id, collation, default_char_set_id, Get::CHARSET_ONLY, false, true, char_sets); + ISQL_get_character_sets(char_set_id, collation, + getDefaultCharSetForSchemaFunc(relationName.schema), + Get::CHARSET_ONLY, false, char_sets); } - if (char_sets[0]) - isqlGlob.prints(char_sets); + + if (char_sets.hasData()) + isqlGlob.prints(char_sets.c_str()); // CVC: Someone deleted the code that checks intchar when handling collations // several lines below, so it didn't have any effect. Commented it. //if (!char_set_id) @@ -2697,14 +2528,15 @@ static void listRelationComputed(LegacyTables flag, SSHORT default_char_set_id) if (!FLD.RDB$COMPUTED_SOURCE.NULL) ISQL_print_validation(isqlGlob.Out, &FLD.RDB$COMPUTED_SOURCE, true, fbTrans); } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); ROLLBACK; return; - END_ERROR; + END_ERROR - if (lastTable.hasData()) + if (lastRelation.object.hasData()) isqlGlob.printf("%s%s%s", isqlGlob.global_Term, NEWLINE, NEWLINE); } @@ -2726,31 +2558,29 @@ static void list_exceptions() bool first = true; FOR EXC IN RDB$EXCEPTIONS - SORTED BY EXC.RDB$EXCEPTION_NAME - + SORTED BY EXC.RDB$SCHEMA_NAME, EXC.RDB$EXCEPTION_NAME + { if (first) - { isqlGlob.printf("%s/* Exceptions */%s", NEWLINE, NEWLINE); - } + first = false; - fb_utils::exact_name(EXC.RDB$EXCEPTION_NAME); + + const QualifiedMetaString name(EXC.RDB$EXCEPTION_NAME, EXC.RDB$SCHEMA_NAME); IUTILS_copy_SQL_id (EXC.RDB$MESSAGE, SQL_identifier2, SINGLE_QUOTE); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (EXC.RDB$EXCEPTION_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf("CREATE EXCEPTION %s %s%s%s", - SQL_identifier, SQL_identifier2, isqlGlob.global_Term, NEWLINE); - } - else - isqlGlob.printf("CREATE EXCEPTION %s %s%s%s", - EXC.RDB$EXCEPTION_NAME, SQL_identifier2, isqlGlob.global_Term, NEWLINE); + isqlGlob.printf( + "CREATE EXCEPTION %s %s%s%s", + ISQL_name_to_string(name).c_str(), + SQL_identifier2, + isqlGlob.global_Term, + NEWLINE); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR } @@ -2774,8 +2604,7 @@ static void list_filters() FOR FIL IN RDB$FILTERS SORTED BY FIL.RDB$FUNCTION_NAME - - fb_utils::exact_name(FIL.RDB$FUNCTION_NAME); + { fb_utils::exact_name(FIL.RDB$MODULE_NAME); fb_utils::exact_name(FIL.RDB$ENTRYPOINT); @@ -2785,13 +2614,10 @@ static void list_filters() first = false; } - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(FIL.RDB$FUNCTION_NAME, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, FIL.RDB$FUNCTION_NAME); + const MetaString name(FIL.RDB$FUNCTION_NAME); isqlGlob.printf("DECLARE FILTER %s INPUT_TYPE %d OUTPUT_TYPE %d%s", - SQL_identifier, FIL.RDB$INPUT_SUB_TYPE, FIL.RDB$OUTPUT_SUB_TYPE, NEWLINE); + ISQL_name_to_string(name).c_str(), FIL.RDB$INPUT_SUB_TYPE, FIL.RDB$OUTPUT_SUB_TYPE, NEWLINE); IUTILS_copy_SQL_id(FIL.RDB$ENTRYPOINT, SQL_identifier, SINGLE_QUOTE); IUTILS_copy_SQL_id(FIL.RDB$MODULE_NAME, SQL_identifier2, SINGLE_QUOTE); @@ -2799,13 +2625,12 @@ static void list_filters() isqlGlob.printf("%sENTRY_POINT %s MODULE_NAME %s%s%s%s", TAB_AS_SPACES, SQL_identifier, SQL_identifier2, isqlGlob.global_Term, NEWLINE, NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; - + END_ERROR } @@ -2828,55 +2653,43 @@ static void list_foreign() FOR RELC1 IN RDB$RELATION_CONSTRAINTS CROSS RELC2 IN RDB$RELATION_CONSTRAINTS CROSS - REFC IN RDB$REF_CONSTRAINTS WITH - RELC1.RDB$CONSTRAINT_TYPE EQ "FOREIGN KEY" AND - REFC.RDB$CONST_NAME_UQ EQ RELC2.RDB$CONSTRAINT_NAME AND - REFC.RDB$CONSTRAINT_NAME EQ RELC1.RDB$CONSTRAINT_NAME AND - (RELC2.RDB$CONSTRAINT_TYPE EQ "UNIQUE" OR - RELC2.RDB$CONSTRAINT_TYPE EQ "PRIMARY KEY") - SORTED BY RELC1.RDB$RELATION_NAME, RELC1.RDB$CONSTRAINT_NAME + REFC IN RDB$REF_CONSTRAINTS + WITH RELC1.RDB$CONSTRAINT_TYPE EQ "FOREIGN KEY" AND + REFC.RDB$CONST_SCHEMA_NAME_UQ EQUIV RELC2.RDB$SCHEMA_NAME AND + REFC.RDB$CONST_NAME_UQ EQ RELC2.RDB$CONSTRAINT_NAME AND + REFC.RDB$SCHEMA_NAME EQUIV RELC1.RDB$SCHEMA_NAME AND + REFC.RDB$CONSTRAINT_NAME EQ RELC1.RDB$CONSTRAINT_NAME AND + (RELC2.RDB$CONSTRAINT_TYPE EQ "UNIQUE" OR + RELC2.RDB$CONSTRAINT_TYPE EQ "PRIMARY KEY") + SORTED BY RELC1.RDB$SCHEMA_NAME, RELC1.RDB$RELATION_NAME, RELC1.RDB$CONSTRAINT_NAME + { + const QualifiedMetaString relationName1(RELC1.RDB$RELATION_NAME, RELC1.RDB$SCHEMA_NAME); + const QualifiedMetaString indexName1(RELC1.RDB$INDEX_NAME, RELC1.RDB$SCHEMA_NAME); + const QualifiedMetaString relationName2(RELC2.RDB$RELATION_NAME, RELC2.RDB$SCHEMA_NAME); + const QualifiedMetaString indexName2(RELC2.RDB$INDEX_NAME, RELC2.RDB$SCHEMA_NAME); + const MetaString constraintName(RELC1.RDB$CONSTRAINT_NAME); - fb_utils::exact_name(RELC1.RDB$RELATION_NAME); - fb_utils::exact_name(RELC2.RDB$RELATION_NAME); - - ISQL_get_index_segments (collist, sizeof(collist), RELC1.RDB$INDEX_NAME, true); + ISQL_get_index_segments(collist, sizeof(collist), indexName1, true); isqlGlob.printf(NEWLINE); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (RELC1.RDB$RELATION_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf("ALTER TABLE %s ADD ", SQL_identifier); - } - else - isqlGlob.printf("ALTER TABLE %s ADD ", RELC1.RDB$RELATION_NAME); + isqlGlob.printf("ALTER TABLE %s ADD ", ISQL_name_to_string(relationName1).c_str()); // If the name of the constraint is not INTEG..., print it. // INTEG_... are internally generated names. if (!RELC1.RDB$CONSTRAINT_NAME.NULL && - !fb_utils::implicit_integrity(RELC1.RDB$CONSTRAINT_NAME)) + !fb_utils::implicit_integrity(constraintName.c_str())) { - IUTILS_truncate_term (RELC1.RDB$CONSTRAINT_NAME, static_cast(strlen(RELC1.RDB$CONSTRAINT_NAME))); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (RELC1.RDB$CONSTRAINT_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf("CONSTRAINT %s ", SQL_identifier); - } - else - isqlGlob.printf("CONSTRAINT %s ", RELC1.RDB$CONSTRAINT_NAME); + isqlGlob.printf( + "CONSTRAINT %s ", + ISQL_name_to_string(constraintName).c_str()); } - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (RELC2.RDB$RELATION_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf("FOREIGN KEY (%s) REFERENCES %s ", collist, SQL_identifier); - } - else - isqlGlob.printf("FOREIGN KEY (%s) REFERENCES %s ", collist, RELC2.RDB$RELATION_NAME); + isqlGlob.printf("FOREIGN KEY (%s) REFERENCES %s ", collist, ISQL_name_to_string(relationName2).c_str()); // Get the column list for the primary key - ISQL_get_index_segments (collist, sizeof(collist), RELC2.RDB$INDEX_NAME, true); + ISQL_get_index_segments(collist, sizeof(collist), indexName2, true); isqlGlob.printf("(%s)", collist); @@ -2894,12 +2707,12 @@ static void list_foreign() } isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR } @@ -2921,18 +2734,17 @@ static void list_functions_legacy() * RETURNS INTEGER BY VALUE * ENTRY_POINT entrypoint MODULE_NAME module; **************************************/ - char type_buffer[BUFFER_LENGTH256]; - char return_buffer[BUFFER_LENGTH256]; + string type_buffer; + string return_buffer; bool first = true; FOR FUN IN RDB$FUNCTIONS - WITH (FUN.RDB$SYSTEM_FLAG NE 1 OR FUN.RDB$SYSTEM_FLAG MISSING) - AND FUN.RDB$MODULE_NAME NOT MISSING - AND FUN.RDB$PACKAGE_NAME MISSING - SORTED BY FUN.RDB$FUNCTION_NAME - - fb_utils::exact_name(FUN.RDB$FUNCTION_NAME); + WITH (FUN.RDB$SYSTEM_FLAG NE 1 OR FUN.RDB$SYSTEM_FLAG MISSING) AND + FUN.RDB$MODULE_NAME NOT MISSING AND + FUN.RDB$PACKAGE_NAME MISSING + SORTED BY FUN.RDB$SCHEMA_NAME, FUN.RDB$FUNCTION_NAME + { fb_utils::exact_name(FUN.RDB$MODULE_NAME); fb_utils::exact_name(FUN.RDB$ENTRYPOINT); if (first) @@ -2941,21 +2753,19 @@ static void list_functions_legacy() first = false; } - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(FUN.RDB$FUNCTION_NAME, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, FUN.RDB$FUNCTION_NAME); + const QualifiedMetaString name(FUN.RDB$FUNCTION_NAME, FUN.RDB$SCHEMA_NAME); // Start new function declaration - isqlGlob.printf("DECLARE EXTERNAL FUNCTION %s%s", SQL_identifier, NEWLINE); + isqlGlob.printf("DECLARE EXTERNAL FUNCTION %s%s", ISQL_name_to_string(name).c_str(), NEWLINE); bool firstarg = true; FOR FNA IN RDB$FUNCTION_ARGUMENTS - WITH FUN.RDB$FUNCTION_NAME EQ FNA.RDB$FUNCTION_NAME - AND FNA.RDB$PACKAGE_NAME MISSING + WITH FNA.RDB$SCHEMA_NAME EQUIV FUN.RDB$SCHEMA_NAME AND + FNA.RDB$FUNCTION_NAME EQ FUN.RDB$FUNCTION_NAME AND + FNA.RDB$PACKAGE_NAME MISSING SORTED BY FNA.RDB$ARGUMENT_POSITION - + { // Find parameter type int i = 0; while (FNA.RDB$FIELD_TYPE != Column_types[i].type) @@ -2971,23 +2781,27 @@ static void list_functions_legacy() bool did_charset = false; FOR CHARSET IN RDB$CHARACTER_SETS WITH CHARSET.RDB$CHARACTER_SET_ID = FNA.RDB$CHARACTER_SET_ID + { + const QualifiedMetaString charSetName( + CHARSET.RDB$CHARACTER_SET_NAME, CHARSET.RDB$SCHEMA_NAME); did_charset = true; - fb_utils::exact_name(CHARSET.RDB$CHARACTER_SET_NAME); - fb_utils::snprintf(type_buffer, sizeof(type_buffer), "%s(%d) CHARACTER SET %s", + type_buffer.printf("%s(%d) CHARACTER SET %s", Column_types[i].type_name, (FNA.RDB$FIELD_LENGTH / MAX (1, CHARSET.RDB$BYTES_PER_CHARACTER)), - CHARSET.RDB$CHARACTER_SET_NAME); - + ISQL_name_to_string(charSetName).c_str()); + } END_FOR ON_ERROR ISQL_errmsg (fbStatus); return; - END_ERROR; + END_ERROR if (!did_charset) - fb_utils::snprintf(type_buffer, sizeof(type_buffer), "%s(%d)", + { + type_buffer.printf("%s(%d)", Column_types[i].type_name, FNA.RDB$FIELD_LENGTH); + } } else { @@ -3005,7 +2819,7 @@ static void list_functions_legacy() FNA.RDB$FIELD_SUB_TYPE > 0 && FNA.RDB$FIELD_SUB_TYPE <= MAX_INTSUBTYPES) { - fb_utils::snprintf(type_buffer, sizeof(type_buffer), "%s(%d, %d)", + type_buffer.printf("%s(%d, %d)", Integral_subtypes[FNA.RDB$FIELD_SUB_TYPE], FNA.RDB$FIELD_PRECISION, -FNA.RDB$FIELD_SCALE); @@ -3017,13 +2831,13 @@ static void list_functions_legacy() { // Take a stab at numerics and decimals if ((FNA.RDB$FIELD_TYPE == blr_short) && (FNA.RDB$FIELD_SCALE < 0)) - fb_utils::snprintf(type_buffer, sizeof(type_buffer), "NUMERIC(4, %d)", -FNA.RDB$FIELD_SCALE); + type_buffer.printf("NUMERIC(4, %d)", -FNA.RDB$FIELD_SCALE); else if ((FNA.RDB$FIELD_TYPE == blr_long) && (FNA.RDB$FIELD_SCALE < 0)) - fb_utils::snprintf(type_buffer, sizeof(type_buffer), "NUMERIC(9, %d)", -FNA.RDB$FIELD_SCALE); + type_buffer.printf("NUMERIC(9, %d)", -FNA.RDB$FIELD_SCALE); else if ((FNA.RDB$FIELD_TYPE == blr_double) && (FNA.RDB$FIELD_SCALE < 0)) - fb_utils::snprintf(type_buffer, sizeof(type_buffer), "NUMERIC(15, %d)", -FNA.RDB$FIELD_SCALE); + type_buffer.printf("NUMERIC(15, %d)", -FNA.RDB$FIELD_SCALE); else - fb_utils::snprintf(type_buffer, sizeof(type_buffer), "%s", Column_types[i].type_name); + type_buffer.printf("%s", Column_types[i].type_name); } // if !precision_known } // if blr_text or blr_varying or blr_cstring ... else @@ -3046,36 +2860,34 @@ static void list_functions_legacy() bool printarg = true; - if (FUN.RDB$RETURN_ARGUMENT == FNA.RDB$ARGUMENT_POSITION) { if (FUN.RDB$RETURN_ARGUMENT) - fb_utils::snprintf(return_buffer, sizeof(return_buffer), "RETURNS PARAMETER %d", FUN.RDB$RETURN_ARGUMENT); + return_buffer.printf("RETURNS PARAMETER %d", FUN.RDB$RETURN_ARGUMENT); else { - fb_utils::snprintf(return_buffer, sizeof(return_buffer), "RETURNS %s%s %s", type_buffer, + return_buffer.printf("RETURNS %s%s %s", type_buffer.c_str(), UDF_param_types[ptype], (FNA.RDB$MECHANISM < 0 ? "FREE_IT" : "")); printarg = false; } - } if (printarg) { // First arg needs no comma - isqlGlob.printf("%s%s%s", (firstarg ? "" : ", "), type_buffer, UDF_param_types[ptype]); + isqlGlob.printf("%s%s%s", (firstarg ? "" : ", "), type_buffer.c_str(), UDF_param_types[ptype]); firstarg = false; } - + } END_FOR ON_ERROR ISQL_errmsg (fbStatus); return; - END_ERROR; + END_ERROR // Print the return type -- All functions return a type - isqlGlob.printf("%s%s%s", NEWLINE, return_buffer, NEWLINE); + isqlGlob.printf("%s%s%s", NEWLINE, return_buffer.c_str(), NEWLINE); // Print out entrypoint information IUTILS_copy_SQL_id(FUN.RDB$ENTRYPOINT, SQL_identifier, SINGLE_QUOTE); @@ -3087,15 +2899,15 @@ static void list_functions_legacy() isqlGlob.global_Term, NEWLINE, NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR } -static void list_functions_ods12_headers(SSHORT default_char_set_id) +static void list_functions_ods12_headers(GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc) { fb_assert(isqlGlob.major_ods >= ODS_VERSION12); @@ -3106,10 +2918,12 @@ static void list_functions_ods12_headers(SSHORT default_char_set_id) // First the dummy functions (without bodies) FOR FUN IN RDB$FUNCTIONS - WITH (FUN.RDB$SYSTEM_FLAG NE 1 OR FUN.RDB$SYSTEM_FLAG MISSING) - AND FUN.RDB$PACKAGE_NAME MISSING - AND FUN.RDB$MODULE_NAME MISSING - SORTED BY FUN.RDB$FUNCTION_NAME + WITH (FUN.RDB$SYSTEM_FLAG NE 1 OR FUN.RDB$SYSTEM_FLAG MISSING) AND + FUN.RDB$PACKAGE_NAME MISSING AND + FUN.RDB$MODULE_NAME MISSING + SORTED BY FUN.RDB$SCHEMA_NAME, FUN.RDB$FUNCTION_NAME + { + const QualifiedMetaString name(FUN.RDB$FUNCTION_NAME, FUN.RDB$SCHEMA_NAME); if (header) { @@ -3117,37 +2931,28 @@ static void list_functions_ods12_headers(SSHORT default_char_set_id) header = false; } - fb_utils::exact_name(FUN.RDB$FUNCTION_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id(FUN.RDB$FUNCTION_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf(create_function, SQL_identifier); - } - else - { - isqlGlob.printf(create_function, FUN.RDB$FUNCTION_NAME); - } + isqlGlob.printf(create_function, ISQL_name_to_string(name).c_str()); - get_function_args_ods12(FUN.RDB$FUNCTION_NAME, FUN.RDB$RETURN_ARGUMENT, default_char_set_id); + get_function_args_ods12(name, FUN.RDB$RETURN_ARGUMENT, getDefaultCharSetForSchemaFunc); if (!FUN.RDB$DETERMINISTIC_FLAG.NULL && FUN.RDB$DETERMINISTIC_FLAG) isqlGlob.printf("DETERMINISTIC %s", NEWLINE); isqlGlob.printf("AS %s", NEWLINE); isqlGlob.printf(body_function, Procterm, NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR // Only reset the terminators if there were procs to print if (!header) print_proc_suffix(obj_udf); } -static void list_functions_ods12_bodies(SSHORT default_char_set_id) +static void list_functions_ods12_bodies(GetDefaultCharSetForSchemaFunc getDefaultCharSetForSchemaFunc) { fb_assert(isqlGlob.major_ods >= ODS_VERSION12); @@ -3158,26 +2963,22 @@ static void list_functions_ods12_bodies(SSHORT default_char_set_id) TEXT msg[MSG_LENGTH]; FOR FUN IN RDB$FUNCTIONS - WITH (FUN.RDB$SYSTEM_FLAG NE 1 OR FUN.RDB$SYSTEM_FLAG MISSING) - AND FUN.RDB$PACKAGE_NAME MISSING - AND FUN.RDB$MODULE_NAME MISSING - SORTED BY FUN.RDB$FUNCTION_NAME + WITH (FUN.RDB$SYSTEM_FLAG NE 1 OR FUN.RDB$SYSTEM_FLAG MISSING) AND + FUN.RDB$PACKAGE_NAME MISSING AND + FUN.RDB$MODULE_NAME MISSING + SORTED BY FUN.RDB$SCHEMA_NAME, FUN.RDB$FUNCTION_NAME + { + const QualifiedMetaString name(FUN.RDB$FUNCTION_NAME, FUN.RDB$SCHEMA_NAME); + if (header) { print_proc_prefix(obj_udf, false); header = false; } - fb_utils::exact_name(FUN.RDB$FUNCTION_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id(FUN.RDB$FUNCTION_NAME, SQL_identifier, DBL_QUOTE); - isqlGlob.printf("%sALTER FUNCTION %s ", NEWLINE, SQL_identifier); - } - else - isqlGlob.printf("%sALTER FUNCTION %s ", NEWLINE, FUN.RDB$FUNCTION_NAME); + isqlGlob.printf("%sALTER FUNCTION %s ", NEWLINE, ISQL_name_to_string(name).c_str()); - get_function_args_ods12(FUN.RDB$FUNCTION_NAME, FUN.RDB$RETURN_ARGUMENT, default_char_set_id); + get_function_args_ods12(name, FUN.RDB$RETURN_ARGUMENT, getDefaultCharSetForSchemaFunc); if (!FUN.RDB$DETERMINISTIC_FLAG.NULL && FUN.RDB$DETERMINISTIC_FLAG) isqlGlob.printf("DETERMINISTIC %s", NEWLINE); @@ -3216,14 +3017,14 @@ static void list_functions_ods12_bodies(SSHORT default_char_set_id) } isqlGlob.printf(" %s%s", Procterm, NEWLINE); - + } END_FOR ON_ERROR IUTILS_msg_get(GEN_ERR, msg, SafeArg() << isc_sqlcode(fbStatus->getErrors())); STDERROUT(msg); // Statement failed, SQLCODE = %d\n\n ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR // Only reset the terminators if there were procs to print if (!header) @@ -3250,7 +3051,7 @@ static void list_generators() WITH GEN.RDB$GENERATOR_NAME NOT MATCHING "RDB$+" USING "+=[0-9][0-9]* *" AND GEN.RDB$GENERATOR_NAME NOT MATCHING "SQL$+" USING "+=[0-9][0-9]* *" AND (GEN.RDB$SYSTEM_FLAG MISSING OR GEN.RDB$SYSTEM_FLAG NE 1) - SORTED BY GEN.RDB$GENERATOR_NAME + SORTED BY GEN.RDB$SCHEMA_NAME, GEN.RDB$GENERATOR_NAME { if (first) { @@ -3258,31 +3059,17 @@ static void list_generators() first = false; } - fb_utils::exact_name(GEN.RDB$GENERATOR_NAME); + const QualifiedMetaString name(GEN.RDB$GENERATOR_NAME, GEN.RDB$SCHEMA_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(GEN.RDB$GENERATOR_NAME, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, GEN.RDB$GENERATOR_NAME); - - isqlGlob.printf("CREATE GENERATOR %s", SQL_identifier); + isqlGlob.printf("CREATE GENERATOR %s", ISQL_name_to_string(name).c_str()); if (isqlGlob.major_ods >= ODS_VERSION12) { - FOR G2 IN RDB$GENERATORS - WITH G2.RDB$GENERATOR_NAME = GEN.RDB$GENERATOR_NAME + if (!GEN.RDB$INITIAL_VALUE.NULL && GEN.RDB$INITIAL_VALUE != 0) + isqlGlob.printf(" START WITH %" SQUADFORMAT, GEN.RDB$INITIAL_VALUE); - if (!G2.RDB$INITIAL_VALUE.NULL && G2.RDB$INITIAL_VALUE != 0) - isqlGlob.printf(" START WITH %" SQUADFORMAT, G2.RDB$INITIAL_VALUE); - - if (G2.RDB$GENERATOR_INCREMENT != 1) - isqlGlob.printf(" INCREMENT %" SLONGFORMAT, G2.RDB$GENERATOR_INCREMENT); - - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return; - END_ERROR; + if (GEN.RDB$GENERATOR_INCREMENT != 1) + isqlGlob.printf(" INCREMENT %" SLONGFORMAT, GEN.RDB$GENERATOR_INCREMENT); } isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); @@ -3316,41 +3103,33 @@ static void list_indexes() bool first = true; - FOR IDX IN RDB$INDICES CROSS RELC IN RDB$RELATIONS - OVER RDB$RELATION_NAME - WITH (RELC.RDB$SYSTEM_FLAG NE 1 OR RELC.RDB$SYSTEM_FLAG MISSING) - AND NOT (ANY RC IN RDB$RELATION_CONSTRAINTS - WITH RC.RDB$INDEX_NAME EQ IDX.RDB$INDEX_NAME) - SORTED BY IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME - + FOR IDX IN RDB$INDICES CROSS + RELC IN RDB$RELATIONS + WITH RELC.RDB$SCHEMA_NAME EQUIV IDX.RDB$SCHEMA_NAME AND + RELC.RDB$RELATION_NAME EQ IDX.RDB$RELATION_NAME AND + (RELC.RDB$SYSTEM_FLAG NE 1 OR RELC.RDB$SYSTEM_FLAG MISSING) AND + NOT ( + ANY RC IN RDB$RELATION_CONSTRAINTS + WITH RC.RDB$SCHEMA_NAME EQUIV IDX.RDB$SCHEMA_NAME AND + RC.RDB$INDEX_NAME EQ IDX.RDB$INDEX_NAME) + SORTED BY IDX.RDB$SCHEMA_NAME, IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME + { if (first) { isqlGlob.printf("%s/* Index definitions for all user tables */%s", NEWLINE, NEWLINE); first = false; } - // Strip trailing blanks - fb_utils::exact_name(IDX.RDB$RELATION_NAME); - fb_utils::exact_name(IDX.RDB$INDEX_NAME); + const QualifiedMetaString name(IDX.RDB$INDEX_NAME, IDX.RDB$SCHEMA_NAME); + const MetaString relationName(IDX.RDB$RELATION_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (IDX.RDB$INDEX_NAME, SQL_identifier, DBL_QUOTE); - IUTILS_copy_SQL_id (IDX.RDB$RELATION_NAME, SQL_identifier2, DBL_QUOTE); - isqlGlob.printf("CREATE%s%s INDEX %s%s ON %s", - (IDX.RDB$UNIQUE_FLAG ? " UNIQUE" : ""), - (IDX.RDB$INDEX_TYPE ? " DESCENDING" : ""), - SQL_identifier, - (IDX.RDB$INDEX_INACTIVE ? " INACTIVE" : ""), - SQL_identifier2); - } - else - isqlGlob.printf("CREATE%s%s INDEX %s%s ON %s", - (IDX.RDB$UNIQUE_FLAG ? " UNIQUE" : ""), - (IDX.RDB$INDEX_TYPE ? " DESCENDING" : ""), - IDX.RDB$INDEX_NAME, - (IDX.RDB$INDEX_INACTIVE ? " INACTIVE" : ""), - IDX.RDB$RELATION_NAME); + isqlGlob.printf( + "CREATE%s%s INDEX %s%s ON %s", + (IDX.RDB$UNIQUE_FLAG ? " UNIQUE" : ""), + (IDX.RDB$INDEX_TYPE ? " DESCENDING" : ""), + ISQL_name_to_string(name).c_str(), + (IDX.RDB$INDEX_INACTIVE ? " INACTIVE" : ""), + ISQL_name_to_string(relationName).c_str()); // Get index expression or column names @@ -3360,32 +3139,24 @@ static void list_indexes() if (!IDX.RDB$EXPRESSION_SOURCE.NULL) SHOW_print_metadata_text_blob(isqlGlob.Out, &IDX.RDB$EXPRESSION_SOURCE, false, true); } - else if (ISQL_get_index_segments (collist, sizeof(collist), IDX.RDB$INDEX_NAME, true)) - { + else if (ISQL_get_index_segments(collist, sizeof(collist), name, true)) isqlGlob.printf(" (%s)", collist); - } // Get index condition, if present - if (ENCODE_ODS(isqlGlob.major_ods, isqlGlob.minor_ods) >= ODS_13_1) + if (ENCODE_ODS(isqlGlob.major_ods, isqlGlob.minor_ods) >= ODS_13_1 && !IDX.RDB$CONDITION_SOURCE.NULL) { - FOR IDX2 IN RDB$INDICES WITH - IDX2.RDB$INDEX_NAME = IDX.RDB$INDEX_NAME - AND IDX2.RDB$CONDITION_SOURCE NOT MISSING - { - isqlGlob.printf("%s ", NEWLINE); - SHOW_print_metadata_text_blob(isqlGlob.Out, &IDX2.RDB$CONDITION_SOURCE, false, true); - } - END_FOR + isqlGlob.printf("%s ", NEWLINE); + SHOW_print_metadata_text_blob(isqlGlob.Out, &IDX.RDB$CONDITION_SOURCE, false, true); } isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR } @@ -3409,45 +3180,39 @@ static void list_package_bodies() bool header = true; - FOR PACK IN RDB$PACKAGES WITH - (PACK.RDB$SYSTEM_FLAG NE 1 OR PACK.RDB$SYSTEM_FLAG MISSING) - AND PACK.RDB$PACKAGE_BODY_SOURCE NOT MISSING - SORTED BY PACK.RDB$PACKAGE_NAME - + FOR PACK IN RDB$PACKAGES + WITH (PACK.RDB$SYSTEM_FLAG NE 1 OR PACK.RDB$SYSTEM_FLAG MISSING) AND + PACK.RDB$PACKAGE_BODY_SOURCE NOT MISSING + SORTED BY PACK.RDB$SCHEMA_NAME, PACK.RDB$PACKAGE_NAME + { if (header) { print_proc_prefix(obj_package_body, false); header = false; } - fb_utils::exact_name(PACK.RDB$PACKAGE_NAME); - - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id (PACK.RDB$PACKAGE_NAME, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, PACK.RDB$PACKAGE_NAME); - - fb_utils::exact_name(PACK.RDB$OWNER_NAME); + const QualifiedMetaString name(PACK.RDB$PACKAGE_NAME, PACK.RDB$SCHEMA_NAME); + const MetaString ownerName(PACK.RDB$OWNER_NAME); isqlGlob.printf("%s/* Package body: %s, Owner: %s%s */%s", NEWLINE, - PACK.RDB$PACKAGE_NAME, - PACK.RDB$OWNER_NAME, + ISQL_name_to_string(name).c_str(), + ISQL_name_to_string(ownerName).c_str(), (!PACK.RDB$VALID_BODY_FLAG.NULL && PACK.RDB$VALID_BODY_FLAG != 0 ? "" : ", Invalid"), NEWLINE); if (!PACK.RDB$VALID_BODY_FLAG.NULL && PACK.RDB$VALID_BODY_FLAG != 0) { - isqlGlob.printf("CREATE PACKAGE BODY %s AS%s", SQL_identifier, NEWLINE); + isqlGlob.printf("CREATE PACKAGE BODY %s AS%s", ISQL_name_to_string(name).c_str(), NEWLINE); SHOW_print_metadata_text_blob(isqlGlob.Out, &PACK.RDB$PACKAGE_BODY_SOURCE); isqlGlob.printf("%s%s", Procterm, NEWLINE); } - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR if (!header) print_proc_suffix(obj_package_body); @@ -3473,35 +3238,29 @@ static void list_package_headers() bool header = true; - FOR PACK IN RDB$PACKAGES WITH - (PACK.RDB$SYSTEM_FLAG NE 1 OR PACK.RDB$SYSTEM_FLAG MISSING) - SORTED BY PACK.RDB$PACKAGE_NAME - + FOR PACK IN RDB$PACKAGES + WITH (PACK.RDB$SYSTEM_FLAG NE 1 OR PACK.RDB$SYSTEM_FLAG MISSING) + SORTED BY PACK.RDB$SCHEMA_NAME, PACK.RDB$PACKAGE_NAME + { if (header) { print_proc_prefix(obj_package_header, false); header = false; } - fb_utils::exact_name(PACK.RDB$PACKAGE_NAME); - - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id (PACK.RDB$PACKAGE_NAME, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, PACK.RDB$PACKAGE_NAME); - - fb_utils::exact_name(PACK.RDB$OWNER_NAME); + const QualifiedMetaString name(PACK.RDB$PACKAGE_NAME, PACK.RDB$SCHEMA_NAME); + const MetaString ownerName(PACK.RDB$OWNER_NAME); isqlGlob.printf("%s/* Package header: %s, Owner: %s */%s", NEWLINE, - PACK.RDB$PACKAGE_NAME, - PACK.RDB$OWNER_NAME, + ISQL_name_to_string(name).c_str(), + ISQL_name_to_string(ownerName).c_str(), NEWLINE); const char* ss = PACK.RDB$SQL_SECURITY.NULL ? "" : (PACK.RDB$SQL_SECURITY ? " SQL SECURITY DEFINER" : " SQL SECURITY INVOKER"); - isqlGlob.printf("CREATE PACKAGE %s%s AS%s", SQL_identifier, ss, NEWLINE); + isqlGlob.printf("CREATE PACKAGE %s%s AS%s", ISQL_name_to_string(name).c_str(), ss, NEWLINE); if (!PACK.RDB$PACKAGE_HEADER_SOURCE.NULL) SHOW_print_metadata_text_blob(isqlGlob.Out, &PACK.RDB$PACKAGE_HEADER_SOURCE); @@ -3509,18 +3268,75 @@ static void list_package_headers() isqlGlob.printf("BEGIN END /* Missing package header info. */"); isqlGlob.printf("%s%s", Procterm, NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR if (!header) print_proc_suffix(obj_package_header); } +// Show schemas. +static void list_schemas() +{ + if (isqlGlob.major_ods < ODS_VERSION14) + return; + + bool first = true; + + FOR SCH IN RDB$SCHEMAS + CROSS DB IN RDB$DATABASE + WITH (SCH.RDB$SYSTEM_FLAG NE 1 OR SCH.RDB$SYSTEM_FLAG MISSING) + SORTED BY SCH.RDB$SCHEMA_NAME + { + const MetaString name(SCH.RDB$SCHEMA_NAME); + const MetaString ownerName(SCH.RDB$OWNER_NAME); + const QualifiedMetaString schemaCharSetName( + SCH.RDB$CHARACTER_SET_NAME, + (SCH.RDB$CHARACTER_SET_SCHEMA_NAME.NULL ? "" : SCH.RDB$CHARACTER_SET_SCHEMA_NAME)); + const QualifiedMetaString databaseCharSetName( + DB.RDB$CHARACTER_SET_NAME, + (DB.RDB$CHARACTER_SET_SCHEMA_NAME.NULL ? "" : DB.RDB$CHARACTER_SET_SCHEMA_NAME)); + + if (first) + { + isqlGlob.printf("%s/* Schema definitions */%s", NEWLINE, NEWLINE); + first = false; + } + + const bool isPublicSchema = name == "PUBLIC"; + + isqlGlob.printf("%s/* Schema: %s, Owner: %s */%s", + NEWLINE, + ISQL_name_to_string(name).c_str(), + ISQL_name_to_string(ownerName).c_str(), + NEWLINE); + + isqlGlob.printf( + "CREATE%s SCHEMA %s", + (isPublicSchema ? " OR ALTER" : ""), + ISQL_name_to_string(name).c_str()); + + if (isPublicSchema || schemaCharSetName != databaseCharSetName) + isqlGlob.printf(" DEFAULT CHARACTER SET %s", ISQL_name_to_string(schemaCharSetName).c_str()); + + isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); + } + END_FOR + ON_ERROR + ISQL_errmsg(fbStatus); + return; + END_ERROR + + if (!first) + isqlGlob.printf("%sCOMMIT WORK%s%s", NEWLINE, isqlGlob.global_Term, NEWLINE); +} + + static void list_views() { /************************************** @@ -3538,50 +3354,39 @@ static void list_views() // If this is a view, use print_blob to print the view text - FOR REL IN RDB$RELATIONS WITH - (REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND - REL.RDB$VIEW_BLR NOT MISSING AND - REL.RDB$FLAGS = REL_sql - SORTED BY REL.RDB$RELATION_ID - - fb_utils::exact_name(REL.RDB$RELATION_NAME); - - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id (REL.RDB$RELATION_NAME, SQL_identifier, DBL_QUOTE); - else - strcpy (SQL_identifier, REL.RDB$RELATION_NAME); - - fb_utils::exact_name(REL.RDB$OWNER_NAME); + FOR REL IN RDB$RELATIONS + WITH (REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND + REL.RDB$VIEW_BLR NOT MISSING AND + REL.RDB$FLAGS = REL_sql + SORTED BY REL.RDB$SCHEMA_NAME, REL.RDB$RELATION_ID + { + const QualifiedMetaString name(REL.RDB$RELATION_NAME, REL.RDB$SCHEMA_NAME); + const MetaString ownerName(REL.RDB$OWNER_NAME); isqlGlob.printf("%s/* View: %s, Owner: %s */%s", NEWLINE, - REL.RDB$RELATION_NAME, - REL.RDB$OWNER_NAME, + ISQL_name_to_string(name).c_str(), + ISQL_name_to_string(ownerName).c_str(), NEWLINE); - isqlGlob.printf("CREATE VIEW %s (", SQL_identifier); + isqlGlob.printf("CREATE VIEW %s (", ISQL_name_to_string(name).c_str()); bool first = true; // Get column list - FOR RFR IN RDB$RELATION_FIELDS WITH - RFR.RDB$RELATION_NAME = REL.RDB$RELATION_NAME + FOR RFR IN RDB$RELATION_FIELDS + WITH RFR.RDB$SCHEMA_NAME EQUIV NULLIF(REL.RDB$SCHEMA_NAME, '') AND + RFR.RDB$RELATION_NAME = REL.RDB$RELATION_NAME SORTED BY RFR.RDB$FIELD_POSITION - - fb_utils::exact_name(RFR.RDB$FIELD_NAME); - - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id (RFR.RDB$FIELD_NAME, SQL_identifier, DBL_QUOTE); - else - strcpy (SQL_identifier, RFR.RDB$FIELD_NAME); - - isqlGlob.printf("%s%s", (first ? "" : ", "), SQL_identifier); + { + const MetaString columnName(RFR.RDB$FIELD_NAME); + isqlGlob.printf("%s%s", (first ? "" : ", "), ISQL_name_to_string(columnName).c_str()); first = false; - + } END_FOR ON_ERROR ISQL_errmsg (fbStatus); return; - END_ERROR; + END_ERROR isqlGlob.printf(") AS%s", NEWLINE); @@ -3589,10 +3394,10 @@ static void list_views() SHOW_print_metadata_text_blob (isqlGlob.Out, &REL.RDB$VIEW_SOURCE); isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR } diff --git a/src/isql/isql.epp b/src/isql/isql.epp index 640765d2aa..e727851603 100644 --- a/src/isql/isql.epp +++ b/src/isql/isql.epp @@ -54,6 +54,7 @@ #include #include #include +#include #include "../isql/FrontendLexer.h" #include "../isql/FrontendParser.h" #include "../common/StdHelper.h" @@ -150,7 +151,6 @@ IsqlGlobals isqlGlob; // Print lengths of numeric values -const size_t MAXCHARSET_SIZE = 32; // CHARSET names const int SHORT_LEN = 7; // NUMERIC (4,2) = -327.68 const int LONG_LEN = 12; // NUMERIC (9,2) = -21474836.48 const int INT64_LEN = 21; // NUMERIC(18,2) = -92233720368547758.08 @@ -452,7 +452,7 @@ struct ri_actions const SCHAR* ri_action_print_mixed; }; -static processing_state add_row(const MetaString&); +static processing_state add_row(const QualifiedMetaString&); static processing_state blobedit(ISC_QUAD, const char*); static processing_state bulk_insert_hack(const char* command); static bool bulk_insert_retriever(const char* prompt); @@ -460,8 +460,8 @@ static void check_autoterm(); static bool check_date(const tm& times); static bool check_time(const tm& times); static bool check_timestamp(const tm& times, const int msec); -static void col_check(const MetaString&, unsigned*); -static processing_state copy_table(const MetaString&, const MetaString&, const TEXT*); +static void col_check(const QualifiedMetaString&, unsigned*); +static processing_state copy_table(const QualifiedMetaString&, const QualifiedMetaString&, const TEXT*); static processing_state create_db(const FrontendParser::CreateDatabaseNode& node); static void do_isql(); static processing_state drop_db(); @@ -485,7 +485,7 @@ static processing_state newoutput(const TEXT*); static processing_state newsize(const TEXT*, const TEXT*); static processing_state newMaxRows(const TEXT* newMaxRowsStr); static processing_state newtrans(const TEXT*); -static processing_state parse_arg(int, SCHAR**, SCHAR*); //, FILE**); +static processing_state parse_arg(int, SCHAR**, QualifiedMetaString&); //, FILE**); static unsigned print_item(TEXT**, const IsqlVar*, const unsigned); static void print_item_numeric(SINT64, int, int, TEXT*); static processing_state print_line(Firebird::IMessageMetadata*, UCHAR*, const unsigned pad[], TEXT line[]); @@ -505,7 +505,7 @@ static int query_abort(const int, const int, void*); static bool stdin_redirected(); static void strip_quotes(const TEXT*, TEXT*); static const char* sqltype_to_string(unsigned); -static const char* charset_to_string(unsigned); +static const QualifiedMetaString& charset_to_string(unsigned); // The dialect spoken by the database, should be 0 when no database is connected. USHORT global_dialect_spoken = 0; @@ -523,7 +523,6 @@ static Firebird::ITransaction* M__trans = NULL; static int global_numbufs; // # of cache buffers on connect static Firebird::IStatement* global_Stmt = NULL; static SCHAR Password[128]; -static SCHAR Charset[128]; static bool Merge_stderr; static Firebird::GlobalPtr global_Buffer; @@ -566,7 +565,6 @@ public: Heading = true; BailOnError = false; StmtTimeout = 0; - ISQL_charset[0] = 0; KeepTranParams = true; TranParams->assign(DEFAULT_DML_TRANS_SQL); PerTableStats = false; @@ -594,7 +592,7 @@ public: bool Heading; bool BailOnError; unsigned int StmtTimeout; - SCHAR ISQL_charset[MAXCHARSET_SIZE]; + std::optional ISQL_charset; bool KeepTranParams; bool PerTableStats; bool WireStats; @@ -617,6 +615,7 @@ static const char FORBIDDEN_TERM_CHARS_DISPLAY[] = ", -, *, /, SINGLE_QUO static bool global_psw = false; static bool global_usr = false; static bool global_role = false; +static bool global_search_path = false; static bool has_global_numbufs = false; static bool have_trans = false; // translation of word "Yes" static TEXT yesword[BUFFER_LENGTH128]; @@ -696,7 +695,7 @@ private: bool m_initialized; // initial (before) stats loaded OK StatArray m_stat; - Firebird::GenericMap> m_relNames; + Firebird::RightPooledMap m_relNames; static const unsigned ITEM_COUNT = 8; static const unsigned char m_items[ITEM_COUNT + 1]; @@ -839,8 +838,7 @@ int ISQL_main(int argc, char* argv[]) #endif atexit(&atexit_fb_shutdown); - TEXT tabname[MAX_SQL_IDENTIFIER_SIZE]; - tabname[0] = '\0'; + QualifiedMetaString tabname; // Initialize globals isqlGlob.major_ods = 0; @@ -869,7 +867,6 @@ int ISQL_main(int argc, char* argv[]) if (Merge_stderr) isqlGlob.Errfp = isqlGlob.Out; - IUTILS_make_upper(tabname); switch (ret) { case EXTRACT: @@ -930,7 +927,26 @@ int ISQL_main(int argc, char* argv[]) } -void ISQL_array_dimensions(const TEXT* fieldname) +// FIXME: Move to IUTILS. Base in IUTILS_copy_SQL_id, verifying special characters and keywords. +string ISQL_name_to_string(const MetaString& name) +{ + if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) + return name.toQuotedString(); + else + return name.c_str(); +} + + +string ISQL_name_to_string(const QualifiedMetaString& name) +{ + if (isqlGlob.major_ods >= ODS_VERSION14) + return ISQL_name_to_string(name.schema) + "." + ISQL_name_to_string(name.object); + + return ISQL_name_to_string(name.object); +} + + +void ISQL_array_dimensions(const QualifiedMetaString& fieldname) { /************************************** * @@ -950,10 +966,11 @@ void ISQL_array_dimensions(const TEXT* fieldname) if (!frontendTransaction()) return; - FOR FDIM IN RDB$FIELD_DIMENSIONS WITH - FDIM.RDB$FIELD_NAME EQ fieldname - SORTED BY FDIM.RDB$DIMENSION - + FOR FDIM IN RDB$FIELD_DIMENSIONS + WITH FDIM.RDB$SCHEMA_NAME EQUIV NULLIF(fieldname.schema.c_str(), '') AND + FDIM.RDB$FIELD_NAME EQ fieldname.object.c_str() + SORTED BY FDIM.RDB$DIMENSION + { // Format is [lower:upper, lower:upper,..] // When lower == 1 no need to print a range. Done. // When upper == 1 no need to print a range either, but it's confusing. Not done. @@ -965,12 +982,12 @@ void ISQL_array_dimensions(const TEXT* fieldname) isqlGlob.printf("%ld", FDIM.RDB$UPPER_BOUND); else isqlGlob.printf("%ld:%ld", FDIM.RDB$LOWER_BOUND, FDIM.RDB$UPPER_BOUND); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR isqlGlob.printf("]"); } @@ -1376,7 +1393,7 @@ SSHORT ISQL_get_default_char_set_id() } -SSHORT ISQL_get_field_length(const TEXT* field_name) +SSHORT ISQL_get_field_length(const QualifiedMetaString& field_name) { /************************************** * @@ -1392,18 +1409,21 @@ SSHORT ISQL_get_field_length(const TEXT* field_name) return 0; SSHORT l = 0; - FOR FLD IN RDB$FIELDS WITH - FLD.RDB$FIELD_NAME EQ field_name + FOR FLD IN RDB$FIELDS + WITH FLD.RDB$SCHEMA_NAME EQUIV NULLIF(field_name.schema.c_str(), '') AND + FLD.RDB$FIELD_NAME EQ field_name.object.c_str() + { if (FLD.RDB$CHARACTER_LENGTH.NULL) l = FLD.RDB$FIELD_LENGTH; else l = FLD.RDB$CHARACTER_LENGTH; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return 0; - END_ERROR; + END_ERROR return l; } @@ -1439,7 +1459,7 @@ SSHORT ISQL_get_char_length( void ISQL_get_character_sets(SSHORT char_set_id, SSHORT collation, SSHORT default_char_set_id, Get what, - bool not_null, bool quote, TEXT* string) + bool not_null, string& text) { /************************************** * @@ -1455,41 +1475,30 @@ void ISQL_get_character_sets(SSHORT char_set_id, SSHORT collation, #endif const char* notNullStr = not_null ? " NOT NULL" : ""; - string[0] = 0; + text.clear(); if (!frontendTransaction()) return; - FOR FIRST 1 COL IN RDB$COLLATIONS CROSS - CST IN RDB$CHARACTER_SETS WITH - COL.RDB$CHARACTER_SET_ID EQ CST.RDB$CHARACTER_SET_ID AND - COL.RDB$COLLATION_ID EQ collation AND - CST.RDB$CHARACTER_SET_ID EQ char_set_id + FOR FIRST 1 + COL IN RDB$COLLATIONS CROSS + CST IN RDB$CHARACTER_SETS + WITH COL.RDB$CHARACTER_SET_ID EQ CST.RDB$CHARACTER_SET_ID AND + COL.RDB$COLLATION_ID EQ collation AND + CST.RDB$CHARACTER_SET_ID EQ char_set_id SORTED BY COL.RDB$COLLATION_NAME, CST.RDB$CHARACTER_SET_NAME - + { #ifdef DEV_BUILD found = true; #endif - fb_utils::exact_name(CST.RDB$CHARACTER_SET_NAME); - fb_utils::exact_name(COL.RDB$COLLATION_NAME); - fb_utils::exact_name(CST.RDB$DEFAULT_COLLATE_NAME); - char charSetName[QUOTED_NAME_SIZE]; - char collateName[QUOTED_NAME_SIZE]; + const QualifiedMetaString charSetName(CST.RDB$CHARACTER_SET_NAME, CST.RDB$SCHEMA_NAME); + const QualifiedMetaString collationName(COL.RDB$COLLATION_NAME, COL.RDB$SCHEMA_NAME); + const QualifiedMetaString defaultCollateName( + CST.RDB$DEFAULT_COLLATE_NAME, CST.RDB$DEFAULT_COLLATE_SCHEMA_NAME); - if (quote && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id(CST.RDB$CHARACTER_SET_NAME, charSetName, DBL_QUOTE); - IUTILS_copy_SQL_id(COL.RDB$COLLATION_NAME, collateName, DBL_QUOTE); - } - else - { - strcpy(charSetName, CST.RDB$CHARACTER_SET_NAME); - strcpy(collateName, COL.RDB$COLLATION_NAME); - } - - bool charsetIsDefault = char_set_id == default_char_set_id; - bool collationIsDefault = strcmp(CST.RDB$DEFAULT_COLLATE_NAME, COL.RDB$COLLATION_NAME) == 0; + const bool charsetIsDefault = char_set_id == default_char_set_id; + const bool collationIsDefault = defaultCollateName == collationName; switch (what) { @@ -1500,7 +1509,7 @@ void ISQL_get_character_sets(SSHORT char_set_id, SSHORT collation, // if global default charset has been changed. if (!charsetIsDefault || !collationIsDefault) { - sprintf(string, " CHARACTER SET %s%s", charSetName, notNullStr); + text.printf(" CHARACTER SET %s%s", ISQL_name_to_string(charSetName).c_str(), notNullStr); return; } break; @@ -1509,34 +1518,40 @@ void ISQL_get_character_sets(SSHORT char_set_id, SSHORT collation, // Default colation is not printed to allow easy global change if (!collationIsDefault) { - sprintf(string, "%s COLLATE %s", notNullStr, collateName); + text.printf("%s COLLATE %s%s", notNullStr, ISQL_name_to_string(collationName).c_str()); return; } break; case Get::BOTH: - // If they both are default - supress output completely + // If they both are default - suppress output completely if (!charsetIsDefault || !collationIsDefault) { if (collationIsDefault) // Suppress collation only - sprintf(string, " CHARACTER SET %s%s", charSetName, notNullStr); + text.printf(" CHARACTER SET %s%s", ISQL_name_to_string(charSetName).c_str(), notNullStr); else - sprintf(string, " CHARACTER SET %s%s COLLATE %s", charSetName, notNullStr, collateName); + { + text.printf( + " CHARACTER SET %s%s COLLATE %s", + ISQL_name_to_string(charSetName).c_str(), + notNullStr, + ISQL_name_to_string(collationName).c_str()); + } return; } break; - } + // No need to write charset or collation but still must print "NOT NULL" if (not_null) - { - sprintf(string, "%s", notNullStr); - } + text.printf("%s", notNullStr); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR + #ifdef DEV_BUILD if (!found) { @@ -1707,72 +1722,42 @@ bool ISQL_statement_ends_in_comment(const char* statement) } -void ISQL_get_default_source(const TEXT* rel_name, - TEXT* field_name, - ISC_QUAD* blob_id) +void ISQL_get_domain_default_source(const QualifiedMetaString& fieldName, ISC_QUAD* blobId) { /************************************** * - * I S Q L _ g e t _ d e f a u l t _ s o u r c e + * I S Q L _ g e t _ d o m a i n _ d e f a u l t _ s o u r c e * ************************************** * * Retrieve the default source of a field. - * Relation_fields takes precedence over fields if both - * are present * - * For a domain, a NULL is passed for rel_name **************************************/ - fb_utils::exact_name(field_name); - - *blob_id = fbBlobNull; + *blobId = fbBlobNull; if (!frontendTransaction()) return; - if (rel_name) + FOR FLD IN RDB$FIELDS + WITH FLD.RDB$SCHEMA_NAME EQUIV NULLIF(fieldName.object.c_str(), '') AND + FLD.RDB$FIELD_NAME EQ fieldName.object.c_str() { - // This is default for a column of a table - FOR FLD IN RDB$FIELDS CROSS - RFR IN RDB$RELATION_FIELDS WITH - RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND - RFR.RDB$RELATION_NAME EQ rel_name AND - FLD.RDB$FIELD_NAME EQ field_name - - if (!RFR.RDB$DEFAULT_SOURCE.NULL) - *blob_id = RFR.RDB$DEFAULT_SOURCE; - else if (!FLD.RDB$DEFAULT_SOURCE.NULL) - *blob_id = FLD.RDB$DEFAULT_SOURCE; - - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return; - END_ERROR; - } - else - { - // Default for a domain - FOR FLD IN RDB$FIELDS WITH - FLD.RDB$FIELD_NAME EQ field_name - - if (!FLD.RDB$DEFAULT_SOURCE.NULL) - *blob_id = FLD.RDB$DEFAULT_SOURCE; - - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return; - END_ERROR; + if (!FLD.RDB$DEFAULT_SOURCE.NULL) + *blobId = FLD.RDB$DEFAULT_SOURCE; } + END_FOR + ON_ERROR + ISQL_errmsg(fbStatus); + return; + END_ERROR } SLONG ISQL_get_index_segments(TEXT* segs, const size_t buf_size, - const TEXT* indexname, - bool delimited_yes) + const QualifiedMetaString& indexname, + bool delimited_yes) // FIXME: { /************************************** * @@ -1796,17 +1781,18 @@ SLONG ISQL_get_index_segments(TEXT* segs, SLONG n = 0; bool count_only = false; - FOR SEG IN RDB$INDEX_SEGMENTS WITH - SEG.RDB$INDEX_NAME EQ indexname + FOR SEG IN RDB$INDEX_SEGMENTS + WITH SEG.RDB$SCHEMA_NAME EQUIV NULLIF(indexname.schema.c_str(), '') AND + SEG.RDB$INDEX_NAME EQ indexname.object.c_str() SORTED BY SEG.RDB$FIELD_POSITION - + { ++n; if (count_only) continue; // Place a comma and a blank between each segment column name - fb_utils::exact_name(SEG.RDB$FIELD_NAME); + fb_utils::exact_name(SEG.RDB$FIELD_NAME); // FIXME: if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION && delimited_yes) { IUTILS_copy_SQL_id (SEG.RDB$FIELD_NAME, SQL_identifier, DBL_QUOTE); } @@ -1836,21 +1822,21 @@ SLONG ISQL_get_index_segments(TEXT* segs, segs += len + 2; } } - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); ROLLBACK; return 0; - END_ERROR; + END_ERROR return n; } -bool ISQL_get_base_column_null_flag(const TEXT* view_name, +bool ISQL_get_base_column_null_flag(const QualifiedMetaString& view_name, const SSHORT view_context, - const TEXT* base_field) + const MetaString& base_field) { /************************************** * @@ -1863,14 +1849,11 @@ bool ISQL_get_base_column_null_flag(const TEXT* view_name, * view_context and the base_field of the view column. * **************************************/ - BASED_ON RDB$RELATION_FIELDS.RDB$RELATION_NAME save_view_name, - save_base_field; + QualifiedMetaString save_view_name(view_name); + MetaString save_base_field(base_field); - strcpy(save_view_name, view_name); - strcpy(save_base_field, base_field); SSHORT save_view_context = view_context; - if (!frontendTransaction()) return false; @@ -1887,17 +1870,17 @@ bool ISQL_get_base_column_null_flag(const TEXT* view_name, bool error = false; while (!done && !error) { - fb_utils::exact_name(save_view_name); - fb_utils::exact_name(save_base_field); bool found = false; FOR FIRST 1 VR IN RDB$VIEW_RELATIONS - CROSS NEWRFR IN RDB$RELATION_FIELDS WITH - VR.RDB$VIEW_NAME EQ save_view_name AND - VR.RDB$VIEW_CONTEXT EQ save_view_context AND - NEWRFR.RDB$RELATION_NAME = VR.RDB$RELATION_NAME AND - NEWRFR.RDB$FIELD_NAME = save_base_field - + CROSS NEWRFR IN RDB$RELATION_FIELDS + WITH VR.RDB$SCHEMA_NAME EQUIV NULLIF(save_view_name.schema.c_str(), '') AND + VR.RDB$VIEW_NAME EQ save_view_name.object.c_str() AND + VR.RDB$VIEW_CONTEXT EQ save_view_context AND + NEWRFR.RDB$SCHEMA_NAME EQUIV VR.RDB$RELATION_SCHEMA_NAME AND + NEWRFR.RDB$RELATION_NAME = VR.RDB$RELATION_NAME AND + NEWRFR.RDB$FIELD_NAME = save_base_field.c_str() + { found = true; if (NEWRFR.RDB$BASE_FIELD.NULL) { @@ -1908,14 +1891,15 @@ bool ISQL_get_base_column_null_flag(const TEXT* view_name, } else { - strcpy (save_view_name, NEWRFR.RDB$RELATION_NAME); + save_view_name = QualifiedMetaString(NEWRFR.RDB$RELATION_NAME, NEWRFR.RDB$SCHEMA_NAME); save_view_context = NEWRFR.RDB$VIEW_CONTEXT; - strcpy (save_base_field, NEWRFR.RDB$BASE_FIELD); + save_base_field = NEWRFR.RDB$BASE_FIELD; } + } END_FOR ON_ERROR error = true; - END_ERROR; + END_ERROR if (!found) { @@ -1924,45 +1908,51 @@ bool ISQL_get_base_column_null_flag(const TEXT* view_name, // Copy/paste from DYN_UTIL_find_field_source FOR FIRST 1 VRL IN RDB$VIEW_RELATIONS CROSS - PPR IN RDB$PROCEDURE_PARAMETERS - WITH VRL.RDB$RELATION_NAME EQ PPR.RDB$PROCEDURE_NAME AND - VRL.RDB$VIEW_NAME EQ save_view_name AND - VRL.RDB$VIEW_CONTEXT EQ save_view_context AND - VRL.RDB$CONTEXT_TYPE EQ VCT_PROCEDURE AND - PPR.RDB$PACKAGE_NAME EQUIV VRL.RDB$PACKAGE_NAME AND - PPR.RDB$PARAMETER_NAME EQ save_base_field AND - PPR.RDB$PARAMETER_TYPE = 1 // output - + PPR IN RDB$PROCEDURE_PARAMETERS + WITH VRL.RDB$RELATION_SCHEMA_NAME EQUIV PPR.RDB$SCHEMA_NAME AND + VRL.RDB$RELATION_NAME EQ PPR.RDB$PROCEDURE_NAME AND + VRL.RDB$SCHEMA_NAME EQUIV NULLIF(save_view_name.schema.c_str(), '') AND + VRL.RDB$VIEW_NAME EQ save_view_name.object.c_str() AND + VRL.RDB$VIEW_CONTEXT EQ save_view_context AND + VRL.RDB$CONTEXT_TYPE EQ VCT_PROCEDURE AND + PPR.RDB$PACKAGE_NAME EQUIV VRL.RDB$PACKAGE_NAME AND + PPR.RDB$PARAMETER_NAME EQ save_base_field.c_str() AND + PPR.RDB$PARAMETER_TYPE = 1 // output + { found = true; if (!PPR.RDB$NULL_FLAG.NULL && PPR.RDB$NULL_FLAG == 1) null_flag = false; done = true; + } END_FOR ON_ERROR error = true; - END_ERROR; + END_ERROR } else if (ENCODE_ODS(isqlGlob.major_ods, isqlGlob.minor_ods) >= ODS_11_2) { FOR FIRST 1 VR IN RDB$VIEW_RELATIONS - CROSS NEWPP IN RDB$PROCEDURE_PARAMETERS WITH - VR.RDB$VIEW_NAME EQ save_view_name AND - VR.RDB$VIEW_CONTEXT EQ save_view_context AND - NEWPP.RDB$PROCEDURE_NAME = VR.RDB$RELATION_NAME AND - NEWPP.RDB$PARAMETER_NAME = save_base_field AND - NEWPP.RDB$PARAMETER_TYPE = 1 // output param - + CROSS NEWPP IN RDB$PROCEDURE_PARAMETERS + WITH VR.RDB$SCHEMA_NAME EQUIV NULLIF(save_view_name.schema.c_str(), '') AND + VR.RDB$VIEW_NAME EQ save_view_name.object.c_str() AND + VR.RDB$VIEW_CONTEXT EQ save_view_context AND + NEWPP.RDB$SCHEMA_NAME EQUIV VR.RDB$RELATION_SCHEMA_NAME AND + NEWPP.RDB$PROCEDURE_NAME = VR.RDB$RELATION_NAME AND + NEWPP.RDB$PARAMETER_NAME = save_base_field.c_str() AND + NEWPP.RDB$PARAMETER_TYPE = 1 // output param + { found = true; if (!NEWPP.RDB$NULL_FLAG.NULL && NEWPP.RDB$NULL_FLAG == 1) null_flag = false; done = true; + } END_FOR ON_ERROR error = true; - END_ERROR; + END_ERROR } } @@ -1974,8 +1964,8 @@ bool ISQL_get_base_column_null_flag(const TEXT* view_name, return null_flag; } -bool ISQL_get_null_flag(const TEXT* rel_name, - TEXT* field_name) +bool ISQL_get_null_flag(const QualifiedMetaString& rel_name, + const MetaString& field_name) { /************************************** * @@ -1989,64 +1979,45 @@ bool ISQL_get_null_flag(const TEXT* rel_name, * We are passed the relation name and the relation_field name * For domains, the relation name is null. **************************************/ - fb_utils::exact_name(field_name); - bool null_flag = true; if (!frontendTransaction()) return false; - if (rel_name) + FOR FLD IN RDB$FIELDS CROSS + RFR IN RDB$RELATION_FIELDS + WITH RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND + RFR.RDB$SCHEMA_NAME EQUIV NULLIF(rel_name.schema.c_str(), '') AND + RFR.RDB$RELATION_NAME EQ rel_name.object.c_str() AND + RFR.RDB$FIELD_NAME EQ field_name.c_str() { - FOR FLD IN RDB$FIELDS CROSS - RFR IN RDB$RELATION_FIELDS WITH - RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND - RFR.RDB$RELATION_NAME EQ rel_name AND - RFR.RDB$FIELD_NAME EQ field_name + if (!FLD.RDB$NULL_FLAG.NULL && FLD.RDB$NULL_FLAG == 1) + null_flag = false; + else + { - if (!FLD.RDB$NULL_FLAG.NULL && FLD.RDB$NULL_FLAG == 1) - null_flag = false; - else + // If RDB$BASE_FIELD is not null then it is a view column + + if (RFR.RDB$BASE_FIELD.NULL) { - // If RDB$BASE_FIELD is not null then it is a view column + // Simple column. Did user define it not null? - if (RFR.RDB$BASE_FIELD.NULL) - { - - // Simple column. Did user define it not null? - - if (!RFR.RDB$NULL_FLAG.NULL && RFR.RDB$NULL_FLAG == 1) - null_flag = false; - } - else - { - null_flag = ISQL_get_base_column_null_flag (rel_name, - RFR.RDB$VIEW_CONTEXT, RFR.RDB$BASE_FIELD); - } + if (!RFR.RDB$NULL_FLAG.NULL && RFR.RDB$NULL_FLAG == 1) + null_flag = false; } - - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return null_flag; - END_ERROR; - } - else - { - // Domains have only field entries to worry about - FOR FLD IN RDB$FIELDS WITH - FLD.RDB$FIELD_NAME EQ field_name - - if (FLD.RDB$NULL_FLAG == 1) - null_flag = false; - - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return null_flag; - END_ERROR; + else + { + null_flag = ISQL_get_base_column_null_flag(rel_name, + RFR.RDB$VIEW_CONTEXT, RFR.RDB$BASE_FIELD); + } + } } + END_FOR + ON_ERROR + ISQL_errmsg(fbStatus); + return null_flag; + END_ERROR return null_flag; } @@ -2123,45 +2094,9 @@ void ISQL_disconnect_database(bool nQuietMode) } -#ifdef NOT_USED_OR_REPLACED -bool ISQL_is_domain(const TEXT* field_name) -{ -/************************************** - * - * I S Q L _ i s _ d o m a i n - * - ************************************** - * - * Determine if a field in rdb$fields is a domain, - * - **************************************/ - bool is_domain = false; - - if (!frontendTransaction()) - return false; - - FOR FLD IN RDB$FIELDS WITH - FLD.RDB$FIELD_NAME EQ field_name - - if (!(implicit_domain(FLD.RDB$FIELD_NAME) && FLD.RDB$SYSTEM_FLAG != 1)) - { - is_domain = true; - } - - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return is_domain; - END_ERROR; - - return is_domain; -} -#endif - - // Print the numeric type as accurately as possible, depending on the ODS. // If it isn't numeric/decimal or is another non-numeric data type, print only the type. -bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int fieldSubType, +bool ISQL_printNumericType(const QualifiedMetaString& fieldName, const int fieldType, const int fieldSubType, const int fieldPrecision, const int fieldScale) { // Look through types array @@ -2172,7 +2107,9 @@ bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int fb_assert(Column_types[i].type != 0); if (Column_types[i].type == 0) { - isqlGlob.printf("Unknown data type %d for field name %s%s", fieldType, fieldName, NEWLINE); + isqlGlob.printf("Unknown data type %d for field name %s%s", fieldType, + ISQL_name_to_string(fieldName).c_str(), + NEWLINE); return false; } @@ -2381,7 +2318,7 @@ static string get_numeric_value(const char* fromStr) } -static processing_state add_row(const MetaString& tabname) +static processing_state add_row(const QualifiedMetaString& tabname) { /************************************** * @@ -2400,7 +2337,7 @@ static processing_state add_row(const MetaString& tabname) * tabname -- Name of table to insert into * **************************************/ - if (tabname.isEmpty()) + if (tabname.object.isEmpty()) return (ps_ERR); if (!Interactive) @@ -2453,7 +2390,12 @@ static processing_state add_row(const MetaString& tabname) // Array for storing select/insert column mapping, colcheck sets it up Firebird::Array coln; unsigned* colnumber = coln.getBuffer(n_cols); - col_check(tabname, colnumber); + + auto fixedTabName = tabname; + if (fixedTabName.schema.isEmpty() && isqlGlob.major_ods >= ODS_VERSION14) + fixedTabName.schema = msg->getSchema(fbStatus, 0); + + col_check(fixedTabName, colnumber); // Create the new INSERT statement from the sqlda info @@ -2478,7 +2420,7 @@ static processing_state add_row(const MetaString& tabname) const bool delimited_yes = fldname[0] == DBL_QUOTE; if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION && delimited_yes) { - IUTILS_copy_SQL_id(fldname, fldfixed, DBL_QUOTE); + IUTILS_copy_SQL_id(fldname, fldfixed, DBL_QUOTE); // FIXME: } else { @@ -4068,7 +4010,7 @@ static bool check_timestamp(const tm& times, const int msec) } -static void col_check(const MetaString& tabname, unsigned* colnumber) +static void col_check(const QualifiedMetaString& tabname, unsigned* colnumber) { /************************************** * @@ -4087,24 +4029,28 @@ static void col_check(const MetaString& tabname, unsigned* colnumber) // Query to get array info and computed source not available in the sqlda int i = 0, j = 0; FOR F IN RDB$FIELDS CROSS - R IN RDB$RELATION_FIELDS WITH - F.RDB$FIELD_NAME = R.RDB$FIELD_SOURCE AND - R.RDB$RELATION_NAME EQ tabname.c_str() + R IN RDB$RELATION_FIELDS + WITH F.RDB$SCHEMA_NAME EQUIV R.RDB$FIELD_SOURCE_SCHEMA_NAME AND + F.RDB$FIELD_NAME = R.RDB$FIELD_SOURCE AND + R.RDB$SCHEMA_NAME EQUIV NULLIF(tabname.schema.c_str(), '') AND + R.RDB$RELATION_NAME EQ tabname.object.c_str() SORTED BY R.RDB$FIELD_POSITION, R.RDB$FIELD_NAME - + { if ((!F.RDB$DIMENSIONS.NULL && F.RDB$DIMENSIONS) || (!F.RDB$COMPUTED_BLR.NULL)) colnumber[i] = ~0u; else colnumber[i] = j++; ++i; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); - END_ERROR; + END_ERROR } -static processing_state copy_table(const MetaString& source, const MetaString& destination, const TEXT* otherdb) +static processing_state copy_table(const QualifiedMetaString& source, const QualifiedMetaString& destination, + const TEXT* otherdb) { /************************************** * @@ -4119,7 +4065,7 @@ static processing_state copy_table(const MetaString& source, const MetaString& d * destination == name of newly created table * **************************************/ - if (source.isEmpty() || destination.isEmpty()) + if (source.object.isEmpty() || destination.object.isEmpty()) { STDERROUT("Either source or destination tables are missing"); return SKIP; @@ -4148,9 +4094,9 @@ static processing_state copy_table(const MetaString& source, const MetaString& d return END; } - if (EXTRACT_list_table(source.c_str(), destination.c_str(), domain_flag, -1)) + if (EXTRACT_list_table(source, destination, domain_flag, [](auto&&) { return -1; })) { - IUTILS_msg_get(NOT_FOUND, errbuf, SafeArg() << source.c_str()); + IUTILS_msg_get(NOT_FOUND, errbuf, SafeArg() << source.toQuotedString().c_str()); STDERROUT(errbuf); fclose(isqlGlob.Out); } @@ -4166,7 +4112,7 @@ static processing_state copy_table(const MetaString& source, const MetaString& d sprintf(cmd, "isql -q %s -i %s", altdb, ftmp.c_str()); if (system(cmd)) { - IUTILS_msg_get(COPY_ERR, errbuf, SafeArg() << destination.c_str() << altdb); + IUTILS_msg_get(COPY_ERR, errbuf, SafeArg() << destination.toQuotedString().c_str() << altdb); STDERROUT(errbuf); } } @@ -4216,8 +4162,13 @@ static processing_state create_db(const FrontendParser::CreateDatabaseNode& node if (global_role && createWithRole) statement += std::string(" ROLE ") + isqlGlob.Role; - if (*setValues.ISQL_charset && strcmp(setValues.ISQL_charset, DEFCHARSET) != 0) - statement += std::string(" SET NAMES '") + setValues.ISQL_charset + "'"; + if (setValues.ISQL_charset) + { + if (setValues.ISQL_charset->schema.isEmpty()) + statement += std::string(" SET NAMES '") + setValues.ISQL_charset->object.c_str() + "'"; + else + statement += std::string(" SET NAMES '") + setValues.ISQL_charset->toQuotedString().c_str() + "'"; + } for (std::size_t i = 1; i < node.args.size(); ++i) statement += std::string(" ") + node.args[i].rawText; @@ -4229,8 +4180,16 @@ static processing_state create_db(const FrontendParser::CreateDatabaseNode& node (isqlGlob.SQL_dialect == 0 || isqlGlob.SQL_dialect == SQL_DIALECT_V6_TRANSITION) ? requested_SQL_dialect : isqlGlob.SQL_dialect; - DB = Firebird::UtilInterfacePtr()->executeCreateDatabase(fbStatus, statement.length(), - statement.c_str(), dialect, nullptr); + // Build up a dpb + ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE); + + if (global_search_path && isqlGlob.SearchPath[0]) + dpb.insertString(isc_dpb_search_path, isqlGlob.SearchPath); + + dpb.insertString(isc_dpb_blr_request_search_path, SYSTEM_SCHEMA); // FIXME: plugins? + + DB = UtilInterfacePtr()->executeCreateDatabase2(fbStatus, statement.length(), + statement.c_str(), dialect, dpb.getBufferLength(), dpb.getBuffer(), nullptr); if (!DB && createWithRole && fbStatus->getErrors()[1] == isc_dsql_error) { @@ -4271,7 +4230,6 @@ static processing_state create_db(const FrontendParser::CreateDatabaseNode& node if (setValues.Autocommit) D_Transaction(); } - } return (ret); @@ -5192,14 +5150,7 @@ static processing_state frontend(const std::string& statement) [](const FrontendParser::SetNamesNode& node) { - const auto setNames = node.name ? node.name->c_str() : DEFCHARSET; - - const size_t lgth = strlen(setNames); - if (lgth < MAXCHARSET_SIZE) - strcpy(setValues.ISQL_charset, setNames); - else - fb_utils::copy_terminate(setValues.ISQL_charset, setNames, MAXCHARSET_SIZE); - + setValues.ISQL_charset = node.name; return SKIP; }, @@ -5980,9 +5931,8 @@ static processing_state print_sets() } isqlGlob.printf(NEWLINE); - if (*setValues.ISQL_charset && strcmp(setValues.ISQL_charset, DEFCHARSET)) { - isqlGlob.printf("%-25s%s%s", "Set names:", setValues.ISQL_charset, NEWLINE); - } + if (setValues.ISQL_charset) + isqlGlob.printf("%-25s%s%s", "Set names:", setValues.ISQL_charset->toQuotedString().c_str(), NEWLINE); print_set("Column headings:", setValues.Heading); @@ -6229,10 +6179,13 @@ static bool printUser(const char* dbName) }; FbTransCommit fbTransCommit; - const char* sql = "SELECT CURRENT_USER, CURRENT_ROLE FROM RDB$DATABASE"; + string sql; + sql.printf( + "SELECT CURRENT_USER, CURRENT_ROLE FROM %sRDB$DATABASE", + (isqlGlob.major_ods >= ODS_VERSION14 ? "SYSTEM." : "")); Firebird::RefPtr st(Firebird::REF_NO_INCR, - DB->prepare(fbStatus, fbTrans, 0, sql, 3, Firebird::IStatement::PREPARE_PREFETCH_METADATA)); + DB->prepare(fbStatus, fbTrans, 0, sql.c_str(), 3, Firebird::IStatement::PREPARE_PREFETCH_METADATA)); if (failed()) return false; Firebird::RefPtr m(Firebird::REF_NO_INCR, @@ -6381,8 +6334,10 @@ static processing_state newdb(const TEXT* dbname, // Build up a dpb Firebird::ClumpletWriter dpb(Firebird::ClumpletReader::dpbList, MAX_DPB_SIZE); - if (*setValues.ISQL_charset && strcmp(setValues.ISQL_charset, DEFCHARSET)) { - dpb.insertString(isc_dpb_lc_ctype, setValues.ISQL_charset, fb_strlen(setValues.ISQL_charset)); + if (setValues.ISQL_charset) + { + const auto charSet = setValues.ISQL_charset->toQuotedString(); + dpb.insertString(isc_dpb_lc_ctype, charSet.c_str(), charSet.length()); } FB_SIZE_T l; @@ -6400,6 +6355,11 @@ static processing_state newdb(const TEXT* dbname, dpb.insertString(isc_dpb_sql_role_name, local_sql_role, l); } + if (global_search_path && (l = fb_strlen(isqlGlob.SearchPath))) + dpb.insertString(isc_dpb_search_path, isqlGlob.SearchPath, l); + + dpb.insertString(isc_dpb_blr_request_search_path, SYSTEM_SCHEMA); // FIXME: plugins? + if (local_numbufs > 0) { dpb.insertInt(isc_dpb_num_buffers, local_numbufs); } @@ -6756,7 +6716,7 @@ static processing_state newtrans(const TEXT* statement) } -static processing_state parse_arg(int argc, SCHAR** argv, SCHAR* tabname) +static processing_state parse_arg(int argc, SCHAR** argv, QualifiedMetaString& tabname) // , FILE** sess) Last param was for wisql { /************************************** @@ -6793,13 +6753,7 @@ static processing_state parse_arg(int argc, SCHAR** argv, SCHAR* tabname) Merge_stderr = false; Merge_diagnostic = false; - { // scope - const size_t lgth = strlen(DEFCHARSET); - if (lgth < MAXCHARSET_SIZE) - strcpy(setValues.ISQL_charset, DEFCHARSET); - else - fb_utils::copy_terminate(setValues.ISQL_charset, DEFCHARSET, MAXCHARSET_SIZE); - } // scope + setValues.ISQL_charset.reset(); // redirected stdin means act like -i was set @@ -7046,6 +7000,11 @@ static processing_state parse_arg(int argc, SCHAR** argv, SCHAR* tabname) global_role = true; break; + case IN_SW_ISQL_SEARCH_PATH: + fb_utils::copy_terminate(isqlGlob.SearchPath, swarg_str, sizeof(isqlGlob.SearchPath)); + global_search_path = true; + break; + case IN_SW_ISQL_CACHE: if (swarg_int <= 0) { @@ -7058,15 +7017,7 @@ static processing_state parse_arg(int argc, SCHAR** argv, SCHAR* tabname) break; case IN_SW_ISQL_CHARSET: - { - fb_utils::copy_terminate(Charset, swarg_str, sizeof(Charset)); - const size_t lgth = strlen(Charset); - if (lgth < MAXCHARSET_SIZE) { - strcpy(setValues.ISQL_charset, Charset); - } - else - fb_utils::copy_terminate(setValues.ISQL_charset, Charset, MAXCHARSET_SIZE); - } + setValues.ISQL_charset = QualifiedMetaString::parseSchemaObject(swarg_str); break; case IN_SW_ISQL_QUIET: @@ -7138,7 +7089,7 @@ static processing_state parse_arg(int argc, SCHAR** argv, SCHAR* tabname) #ifdef DEV_BUILD // If there is a table name, it follows if (istable && (++i < argc) && (s = argv[i]) && *s) - fb_utils::copy_terminate(tabname, s, MAX_SQL_IDENTIFIER_SIZE); + tabname = QualifiedMetaString::parseSchemaObject(s); #endif } } @@ -8083,7 +8034,7 @@ static void print_message(Firebird::IMessageMetadata* msg, const char* dir) case SQL_TEXT: case SQL_VARYING: cs = msg->getCharSet(fbStatus, i); - isqlGlob.printf(" charset: %d %s", cs, charset_to_string(cs)); + isqlGlob.printf(" charset: %d %s", cs, charset_to_string(cs).toQuotedString().c_str()); break; } @@ -9047,6 +8998,7 @@ static bool stdin_redirected() } +// FIXME: // CVC: There's something either wrong or on purpose in this routine: // it doesn't unescape the embedded quotes that may exist. // But it's useful for paths as it's now. @@ -9148,7 +9100,7 @@ static const char* sqltype_to_string(unsigned sqltype) } -static const char* charset_to_string(unsigned charset) +static const QualifiedMetaString& charset_to_string(unsigned charset) { /************************************** * @@ -9160,27 +9112,26 @@ static const char* charset_to_string(unsigned charset) * Return a more readable version of SQLDA.sqltype * **************************************/ - static Firebird::GlobalPtr > > > csMap; + static GlobalPtr> csMap; + static const QualifiedMetaString UNKNOWN_CS("*unknown*"); charset = TTYPE_TO_CHARSET(charset); - string* text = csMap->get(charset); - if (text) - return text->c_str(); + if (const auto name = csMap->get(charset)) + return *name; csMap->clear(); bool err = false; if (!frontendTransaction()) - return UNKNOWN; + return UNKNOWN_CS; FOR CS IN RDB$CHARACTER_SETS if (!err) { try { - fb_utils::exact_name(CS.RDB$CHARACTER_SET_NAME); - csMap->put(CS.RDB$CHARACTER_SET_ID, CS.RDB$CHARACTER_SET_NAME); + csMap->put(CS.RDB$CHARACTER_SET_ID, QualifiedMetaString(CS.RDB$CHARACTER_SET_NAME, CS.RDB$SCHEMA_NAME)); } catch (const Firebird::Exception& ex) { @@ -9194,11 +9145,10 @@ static const char* charset_to_string(unsigned charset) ISQL_errmsg(fbStatus); END_ERROR; - text = csMap->get(charset); - if (text) - return text->c_str(); + if (const auto name = csMap->get(charset)) + return *name; - return UNKNOWN; + return UNKNOWN_CS; } @@ -9313,6 +9263,7 @@ void PerTableStats::printStats(Firebird::IAttachment* att) IUTILS_printf2(Diag, "%s%s", h.c_str(), NEWLINE); + // FIXME: schema string s; s.printf("%-*s|", lenTable, " Table name"); @@ -9336,10 +9287,10 @@ void PerTableStats::printStats(Firebird::IAttachment* att) relId = item.relId; - if (string* relName = m_relNames.get(relId)) + if (const auto relName = m_relNames.get(relId)) { IcuUtil::pad(s.getBuffer(lenTable * 4 + 1), isqlGlob.att_charset, - relName->length(), relName->c_str(), + relName->object.length(), relName->object.c_str(), lenTable, false); s.recalculate_length(); lenName = s.length(); @@ -9391,8 +9342,8 @@ unsigned PerTableStats::loadRelNames(Firebird::IAttachment* att) if (m_relNames.exist(relId)) { - const auto str = m_relNames.get(relId); - const unsigned len = IcuUtil::charLength(isqlGlob.att_charset, str->length(), str->c_str()); + const auto name = m_relNames.get(relId); + const unsigned len = IcuUtil::charLength(isqlGlob.att_charset, name->object.length(), name->object.c_str()); if (maxLen < len) maxLen = len; @@ -9414,8 +9365,10 @@ unsigned PerTableStats::loadRelNames(Firebird::IAttachment* att) return maxLen; // ? string sql; - sql.printf("SELECT RDB$RELATION_ID, RDB$RELATION_NAME FROM RDB$RELATIONS WHERE RDB$RELATION_ID IN (%s)", - sIds.c_str()); + sql.printf( + "SELECT RDB$RELATION_ID, RDB$RELATION_NAME FROM %sRDB$RELATIONS WHERE RDB$RELATION_ID IN (%s)", + (isqlGlob.major_ods >= ODS_VERSION14 ? "SYSTEM." : ""), + sIds.c_str()); Firebird::IResultSet* rs = att->openCursor(fbStatus, fbTrans, sql.length(), sql.c_str(), SQL_DIALECT_CURRENT, @@ -9452,7 +9405,7 @@ unsigned PerTableStats::loadRelNames(Firebird::IAttachment* att) if (maxLen < len) maxLen = len; - m_relNames.put(*pRelID, name); + m_relNames.put(*pRelID, QualifiedMetaString(name)); // FIXME: } outMeta->release(); diff --git a/src/isql/isql.h b/src/isql/isql.h index 8c97ec42a8..792609a41c 100644 --- a/src/isql/isql.h +++ b/src/isql/isql.h @@ -99,7 +99,6 @@ const size_t CHARSET_COLLATE_SIZE = 1; // null terminator static const char* const DEFTERM = ";"; -static const char* const DEFCHARSET = "NONE"; const unsigned NULL_DISP_LEN = 6; @@ -234,6 +233,7 @@ public: size_t Termlen; SCHAR User[128]; SCHAR Role[256]; + SCHAR SearchPath[512]; USHORT SQL_dialect; USHORT db_SQL_dialect; // from isql.epp diff --git a/src/isql/isql_proto.h b/src/isql/isql_proto.h index 6bf042a773..16f39d2341 100644 --- a/src/isql/isql_proto.h +++ b/src/isql/isql_proto.h @@ -25,10 +25,14 @@ #define ISQL_ISQL_PROTO_H #include +#include "../common/classes/fb_string.h" +#include "../common/classes/MetaString.h" +#include "../common/classes/QualifiedMetaString.h" +#include struct IsqlVar; -void ISQL_array_dimensions(const TEXT*); +void ISQL_array_dimensions(const Firebird::QualifiedMetaString&); //void ISQL_build_table_list(void**, FILE*, FILE*, FILE*); //void ISQL_build_view_list(void**, FILE*, FILE*, FILE*); //int ISQL_commit_work(int, FILE*, FILE*, FILE*); @@ -40,7 +44,7 @@ void ISQL_exit_db(); // CVC: Not found. //int ISQL_extract(TEXT*, int, FILE*, FILE*, FILE*); int ISQL_frontend_command(TEXT*, FILE*, FILE*, FILE*); -bool ISQL_get_base_column_null_flag(const TEXT*, const SSHORT, const TEXT*); +bool ISQL_get_base_column_null_flag(const Firebird::QualifiedMetaString&, const SSHORT, const Firebird::MetaString&); // Shall become obsolete when collation become a part of data type as in SQL standard enum class Get { @@ -51,24 +55,23 @@ enum class Get void ISQL_get_character_sets( SSHORT char_set_id, SSHORT collation, SSHORT default_char_set_id, Get what, - bool not_null, bool quote, TEXT* string); + bool not_null, Firebird::string& text); SSHORT ISQL_get_default_char_set_id(); -void ISQL_get_default_source(const TEXT*, TEXT*, ISC_QUAD*); -SSHORT ISQL_get_field_length(const TEXT*); +void ISQL_get_domain_default_source(const Firebird::QualifiedMetaString&, ISC_QUAD*); +SSHORT ISQL_get_field_length(const Firebird::QualifiedMetaString&); SSHORT ISQL_get_char_length( SSHORT fieldLength, SSHORT characterLengthNull, SSHORT characterLength, SSHORT characterSetIdNull, SSHORT characterSetId); -SLONG ISQL_get_index_segments(TEXT*, const size_t, const TEXT*, bool); -bool ISQL_get_null_flag(const TEXT*, TEXT*); +SLONG ISQL_get_index_segments(TEXT*, const size_t, const Firebird::QualifiedMetaString&, bool); +bool ISQL_get_null_flag(const Firebird::QualifiedMetaString&, const Firebird::MetaString&); void ISQL_get_version(bool); SSHORT ISQL_init(FILE*, FILE*); -#ifdef NOT_USED_OR_REPLACED -bool ISQL_is_domain(const TEXT*); -#endif int ISQL_main(int, char**); -bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int fieldSubType, - const int fieldPrecision, const int fieldScale); +Firebird::string ISQL_name_to_string(const Firebird::MetaString& name); +Firebird::string ISQL_name_to_string(const Firebird::QualifiedMetaString& name); +bool ISQL_printNumericType(const Firebird::QualifiedMetaString& fieldName, const int fieldType, + const int fieldSubType, const int fieldPrecision, const int fieldScale); void ISQL_print_validation(FILE*, ISC_QUAD*, bool, Firebird::ITransaction*); //void ISQL_query_database(SSHORT*, FILE*, FILE*, FILE*); //void ISQL_reset_settings(); diff --git a/src/isql/isqlswi.h b/src/isql/isqlswi.h index f401e601cc..4f976c944f 100644 --- a/src/isql/isqlswi.h +++ b/src/isql/isqlswi.h @@ -52,17 +52,18 @@ enum isql_switches IN_SW_ISQL_QUIET = 19, IN_SW_ISQL_ROLE = 20, IN_SW_ISQL_ROLE2 = 21, - IN_SW_ISQL_SQLDIALECT = 22, - IN_SW_ISQL_TERM = 23, + IN_SW_ISQL_SEARCH_PATH = 22, + IN_SW_ISQL_SQLDIALECT = 23, + IN_SW_ISQL_TERM = 24, #ifdef TRUSTED_AUTH - IN_SW_ISQL_TRUSTED = 24, + IN_SW_ISQL_TRUSTED = 25, #endif - IN_SW_ISQL_USER = 25, - IN_SW_ISQL_VERSION = 26, + IN_SW_ISQL_USER = 26, + IN_SW_ISQL_VERSION = 27, #ifdef DEV_BUILD - IN_SW_ISQL_EXTRACTTBL = 27, + IN_SW_ISQL_EXTRACTTBL = 28, #endif - IN_SW_ISQL_HELP = 28 + IN_SW_ISQL_HELP = 29 }; @@ -91,6 +92,7 @@ static const Switches::in_sw_tab_t isql_in_sw_table[] = {IN_SW_ISQL_QUIET , 0, "QUIET" , 0, 0, 0, false, false, 134 , 1, NULL, iqoArgNone}, {IN_SW_ISQL_ROLE , 0, "ROLE" , 0, 0, 0, false, false, 135 , 1, NULL, iqoArgString}, {IN_SW_ISQL_ROLE2 , 0, "R2" , 0, 0, 0, false, false, 136 , 2, NULL, iqoArgString}, + {IN_SW_ISQL_SEARCH_PATH , 0, "SEARCH_PATH" , 0, 0, 0, false, false, 210 , 2, NULL, iqoArgString}, {IN_SW_ISQL_SQLDIALECT , 0, "SQLDIALECT" , 0, 0, 0, false, false, 137 , 1, NULL, iqoArgInteger}, {IN_SW_ISQL_SQLDIALECT , 0, "SQL_DIALECT" , 0, 0, 0, false, false, 0 , 1, NULL, iqoArgInteger}, {IN_SW_ISQL_TERM , 0, "TERMINATOR" , 0, 0, 0, false, false, 138 , 1, NULL, iqoArgString}, diff --git a/src/isql/iutils.cpp b/src/isql/iutils.cpp index 09dc0a537f..688f44da4f 100644 --- a/src/isql/iutils.cpp +++ b/src/isql/iutils.cpp @@ -159,6 +159,33 @@ string IUTILS_name_to_string(const MetaString& name) } +string IUTILS_name_to_string(const QualifiedMetaString& name) +{ + if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) + return name.toQuotedString(); + else + { + string str(name.schema.c_str()); + + if (name.package.hasData()) + { + if (str.hasData()) + str += "."; + str += name.package.c_str(); + } + + if (name.object.hasData()) + { + if (str.hasData()) + str += "."; + str += name.object.c_str(); + } + + return str; + } +} + + void IUTILS_printf(FILE* fp, const char* buffer) { /************************************** diff --git a/src/isql/iutils_proto.h b/src/isql/iutils_proto.h index c61826081a..f8f9071a0a 100644 --- a/src/isql/iutils_proto.h +++ b/src/isql/iutils_proto.h @@ -25,6 +25,7 @@ #define ISQL_IUTILS_PROTO_H #include "../common/classes/MetaString.h" +#include "../common/classes/QualifiedMetaString.h" #include "../common/classes/SafeArg.h" #include @@ -35,6 +36,7 @@ void IUTILS_msg_get(USHORT number, TEXT* msg, void IUTILS_msg_get(USHORT number, USHORT size, TEXT* msg, const MsgFormat::SafeArg& args = MsgFormat::SafeArg()); Firebird::string IUTILS_name_to_string(const Firebird::MetaString& name); +Firebird::string IUTILS_name_to_string(const Firebird::QualifiedMetaString& name); void IUTILS_printf(FILE*, const char*); void IUTILS_printf2(FILE*, const char*, ...); void IUTILS_put_errmsg(USHORT number, const MsgFormat::SafeArg& args); diff --git a/src/isql/show.epp b/src/isql/show.epp index 540f758a26..87fdc54fd6 100644 --- a/src/isql/show.epp +++ b/src/isql/show.epp @@ -86,40 +86,40 @@ enum commentMode {cmmShow, cmmExtract}; static void make_priv_string(USHORT, char*, bool); static processing_state show_all_tables(SSHORT); static void show_charsets(SSHORT char_set_id, SSHORT collation); -static processing_state show_check(const SCHAR*); -static processing_state show_collations(const SCHAR*, SSHORT sys_flag, const char* msg = 0, bool compact = false); -static void show_comment(const char* objtype, char* packageName, char* name1, char* name2, +static processing_state show_check(const std::optional& name); +static processing_state show_collations(const std::optional& name, + SSHORT sys_flag, const char* msg = nullptr, bool compact = false); +static void show_comment(const char* objtype, const QualifiedMetaString& name, const MetaString& name2, ISC_QUAD* blobfld, const commentMode showextract, const char* banner); static processing_state show_comments(const commentMode showextract, const char* banner); static void show_db(); -static processing_state show_dependencies(const char* object); -static processing_state show_dependencies(const char* object, int obj_type); +static processing_state show_dependencies(const std::optional& name); +static processing_state show_dependencies(const QualifiedMetaString& name, int obj_type); static processing_state show_dialect(); -static processing_state show_domains(const SCHAR*); -static processing_state show_exceptions(const SCHAR*); -static processing_state show_filters(const SCHAR*); -static processing_state show_functions( - const char* funcname, const char* packname, bool quoted, bool system, const char* msg = nullptr); -static processing_state show_func_legacy(const MetaString&); -static processing_state show_func(const MetaString&, const MetaString&); -static processing_state show_generators(const SCHAR*); -static void show_index(SCHAR*, SCHAR*, const SSHORT, const SSHORT, const SSHORT); -static processing_state show_indices(const char*); -static processing_state show_proc(const char*, const char*, bool, bool, const char* msg = nullptr); -static processing_state show_packages(const SCHAR* package_name, bool, const SCHAR* = NULL); -static processing_state show_publications(const SCHAR* pub_name, bool, const SCHAR* = NULL); -static void show_pub_table(const SCHAR* table_name); -static processing_state show_role(const SCHAR*, bool, const char* msg = NULL); -static processing_state show_secclass(const std::optional& object, bool detail); -static processing_state show_table(const SCHAR*, bool); -static processing_state show_trigger(const SCHAR*, bool, bool); +static processing_state show_domains(const std::optional& name); +static processing_state show_exceptions(const std::optional& name); +static processing_state show_filters(const std::optional& name); +static processing_state show_functions(const std::optional& name, + bool quoted, bool system, const char* msg = nullptr); +static processing_state show_func_legacy(const QualifiedMetaString& name); +static processing_state show_func(const QualifiedMetaString& name); +static processing_state show_generators(const std::optional& name); +static void show_index(const QualifiedMetaString&, const QualifiedMetaString&, const SSHORT, const SSHORT, const SSHORT); +static processing_state show_indices(const std::optional& name); +static processing_state show_proc(const std::optional& name, bool, bool, const char* msg = nullptr); +static processing_state show_packages(const std::optional& name, bool, const SCHAR* = NULL); +static processing_state show_publications(const std::optional& name, bool, const SCHAR* = NULL); +static void show_pub_table(const QualifiedMetaString& name); +static processing_state show_role(const std::optional& name, bool, const char* msg = NULL); +static processing_state show_secclass(const std::optional& object, bool detail); +static processing_state show_table(const QualifiedMetaString& name, bool); +static processing_state show_trigger(const std::optional& name, bool, bool); static processing_state show_users(); static processing_state show_users12(); static processing_state show_wireStats(); const char* const spaces = " "; static TEXT Print_buffer[512]; -static TEXT SQL_identifier[BUFFER_LENGTH256]; static bool reReadDbOwner = true; @@ -673,7 +673,7 @@ void SHOW_dbb_parameters(Firebird::IAttachment* db_handle, } -processing_state SHOW_grants(const SCHAR* object, const SCHAR* terminator, ObjectType obj_type) +processing_state SHOW_grants(const std::optional& name, const SCHAR* terminator, ObjectType obj_type) { /************************************** * @@ -685,7 +685,10 @@ processing_state SHOW_grants(const SCHAR* object, const SCHAR* terminator, Objec * Placeholder for SHOW_grants2 without additional message. * **************************************/ - return SHOW_grants2 (object, terminator, obj_type, NULL, false); + if (!name) + return ps_ERR; + + return SHOW_grants2(name.value(), terminator, obj_type, nullptr, false); } @@ -705,7 +708,7 @@ void SHOW_read_owner() } -static const char* granted_by(char* buffer, const char* grantor, bool nullGrantor) +static string granted_by(const MetaString& grantor, bool nullGrantor) { /************************************** * @@ -717,86 +720,78 @@ static const char* granted_by(char* buffer, const char* grantor, bool nullGranto * Output message only if not granted by DB owner. * **************************************/ - static BASED_ON RDB$RELATIONS.RDB$OWNER_NAME owner; + static MetaString owner; if (reReadDbOwner) { // Get the owner name - strcpy(owner, DBA_USER_NAME); - - FOR REL IN RDB$RELATIONS WITH - REL.RDB$RELATION_NAME = "RDB$DATABASE" + owner = DBA_USER_NAME; + FOR REL IN RDB$RELATIONS + WITH (REL.RDB$SCHEMA_NAME = SYSTEM_SCHEMA OR REL.RDB$SCHEMA_NAME MISSING) AND + REL.RDB$RELATION_NAME = "RDB$DATABASE" + { if (!REL.RDB$OWNER_NAME.NULL) - strcpy(owner, REL.RDB$OWNER_NAME); + owner = REL.RDB$OWNER_NAME; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); - buffer[0] = '\0'; return ""; - END_ERROR; + END_ERROR - fb_utils::exact_name(owner); reReadDbOwner = false; } - strcpy(buffer, grantor); - fb_utils::exact_name(buffer); - if ((!strcmp(buffer, owner)) || nullGrantor) - buffer[0] = '\0'; - else - { - strcpy(buffer, " GRANTED BY "); - strcat(buffer, grantor); - fb_utils::exact_name(buffer); - } + if (grantor == owner || nullGrantor) + return ""; - return buffer; + return " GRANTED BY " + grantor.toQuotedString(); } -static void set_grantee(int user_type, const char* SQL_identifier, char* user_string) +static void set_grantee(int user_type, const QualifiedMetaString& name, string& user_string) { switch (user_type) { case obj_view: - sprintf(user_string, "VIEW %s", SQL_identifier); + user_string.printf("VIEW %s", name.toQuotedString().c_str()); break; case obj_trigger: - sprintf(user_string, "TRIGGER %s", SQL_identifier); + user_string.printf("TRIGGER %s", name.toQuotedString().c_str()); break; case obj_procedure: - sprintf(user_string, "PROCEDURE %s", SQL_identifier); + user_string.printf("PROCEDURE %s", name.toQuotedString().c_str()); break; case obj_udf: - sprintf(user_string, "FUNCTION %s", SQL_identifier); + user_string.printf("FUNCTION %s", name.toQuotedString().c_str()); break; case obj_user: - if (strcmp(SQL_identifier, "PUBLIC")) - sprintf(user_string, "USER %s", SQL_identifier); + if (name.object == "PUBLIC") + user_string.printf("USER %s", name.toQuotedString().c_str()); else - strcpy(user_string, SQL_identifier); + user_string = name.toQuotedString().c_str(); break; case obj_user_group: - sprintf(user_string, "GROUP %s", SQL_identifier); + user_string.printf("GROUP %s", name.toQuotedString().c_str()); break; case obj_sql_role: - sprintf(user_string, "ROLE %s", SQL_identifier); + user_string.printf("ROLE %s", name.toQuotedString().c_str()); break; case obj_package_header: - sprintf(user_string, "PACKAGE %s", SQL_identifier); + user_string.printf("PACKAGE %s", name.toQuotedString().c_str()); break; case obj_privilege: FOR T IN RDB$TYPES WITH T.RDB$FIELD_NAME EQ 'RDB$SYSTEM_PRIVILEGES' AND - T.RDB$TYPE EQ atoi(SQL_identifier) + T.RDB$TYPE EQ atoi(name.object.c_str()) { - sprintf(user_string, "SYSTEM PRIVILEGE %s", fb_utils::exact_name(T.RDB$TYPE_NAME)); + user_string.printf("SYSTEM PRIVILEGE %s", fb_utils::exact_name(T.RDB$TYPE_NAME)); } END_FOR break; default: - strcpy(user_string, SQL_identifier); + user_string = name.toQuotedString().c_str(); break; } } @@ -852,11 +847,11 @@ static void make_privilege_string_with_fields(USHORT priv_flags, } -processing_state SHOW_grants2 (const SCHAR* object, +processing_state SHOW_grants2(const QualifiedMetaString& name, const SCHAR* terminator, ObjectType obj_type, const TEXT* optional_msg, - bool mangle) + bool mangle) // FIXME: use "mangle" / "extract" { /************************************** * @@ -877,11 +872,10 @@ processing_state SHOW_grants2 (const SCHAR* object, * header message after this routine, so it should be printed here. * **************************************/ - BASED_ON RDB$USER_PRIVILEGES.RDB$USER prev_user; + QualifiedMetaString prev_user; BASED_ON RDB$USER_PRIVILEGES.RDB$GRANT_OPTION prev_grant_option; - BASED_ON RDB$USER_PRIVILEGES.RDB$GRANTOR prev_grantor; - SCHAR buf_grantor[sizeof(prev_grantor) + 20]; - SCHAR user_string[QUOTED_NAME_SIZE + 20]; + MetaString prev_grantor; + string user_string; SCHAR obj_string[QUOTED_NAME_SIZE + 20]; PrivilegeFields priv_fields[] = @@ -893,16 +887,13 @@ processing_state SHOW_grants2 (const SCHAR* object, bool first = true; - if (!*object) + if (name.object.isEmpty()) return ps_ERR; // Query against user_privileges instead of looking at rdb$security_classes prev_grant_option = -1; - prev_user[0] = '\0'; - prev_grantor[0] = '\0'; char priv_string[MAX_PRIV_LIST] = ""; - string col_string; char with_option[19] = ""; USHORT priv_flags = 0; @@ -910,20 +901,26 @@ processing_state SHOW_grants2 (const SCHAR* object, { // Find the user specified relation and show its privileges - FOR FIRST 1 R IN RDB$RELATIONS WITH R.RDB$RELATION_NAME EQ object + FOR FIRST 1 R IN RDB$RELATIONS + WITH R.RDB$RELATION_NAME EQ name.object.c_str() + { + if (name.schema.hasData() && name.schema != R.RDB$SCHEMA_NAME) + continue; // This query only finds tables, eliminating owner privileges FOR PRV IN RDB$USER_PRIVILEGES CROSS - REL IN RDB$RELATIONS WITH - PRV.RDB$GRANTOR NOT MISSING AND - PRV.RDB$RELATION_NAME EQ object AND - REL.RDB$RELATION_NAME EQ object AND - PRV.RDB$PRIVILEGE NE 'M' AND - REL.RDB$OWNER_NAME NE PRV.RDB$USER - SORTED BY PRV.RDB$USER, PRV.RDB$GRANT_OPTION, PRV.RDB$FIELD_NAME; - - fb_utils::exact_name(PRV.RDB$USER); + REL IN RDB$RELATIONS + WITH PRV.RDB$GRANTOR NOT MISSING AND + PRV.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(R.RDB$SCHEMA_NAME, '') AND + PRV.RDB$RELATION_NAME EQ name.object.c_str() AND + REL.RDB$SCHEMA_NAME EQUIV PRV.RDB$RELATION_SCHEMA_NAME AND + REL.RDB$RELATION_NAME EQ PRV.RDB$RELATION_NAME AND + PRV.RDB$PRIVILEGE NE 'M' AND + REL.RDB$OWNER_NAME NE PRV.RDB$USER + SORTED BY PRV.RDB$USER_SCHEMA_NAME, PRV.RDB$USER, PRV.RDB$GRANT_OPTION, PRV.RDB$FIELD_NAME + { + const QualifiedMetaString user(PRV.RDB$USER, PRV.RDB$USER_SCHEMA_NAME); // Sometimes grant options are null, sometimes 0. Both same @@ -936,19 +933,14 @@ processing_state SHOW_grants2 (const SCHAR* object, // Print a new grant statement for each new user or change of option if (prev_grant_option != -1 && - (strcmp(prev_user, PRV.RDB$USER) || - prev_grant_option != PRV.RDB$GRANT_OPTION || - strcmp(prev_grantor, PRV.RDB$GRANTOR))) + (prev_user != user || + prev_grant_option != PRV.RDB$GRANT_OPTION || + prev_grantor != PRV.RDB$GRANTOR)) { if (first && optional_msg) isqlGlob.prints(optional_msg); first = false; - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(object, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, object); - if (prev_grant_option) strcpy(with_option, " WITH GRANT OPTION"); @@ -958,86 +950,52 @@ processing_state SHOW_grants2 (const SCHAR* object, isqlGlob.printf("GRANT %s ON %s TO %s%s%s%s%s", combine_privileges.c_str(), - SQL_identifier, - user_string, with_option, granted_by(buf_grantor, prev_grantor, false), + name.toQuotedString().c_str(), + user_string.c_str(), with_option, granted_by(prev_grantor, false), terminator, NEWLINE); // re-initialize priv_flags = 0; with_option[0] = '\0'; priv_string[0] = '\0'; - col_string = ""; for (int i = 0; i < priv_fields_count; i++) priv_fields[i].fields = ""; } // At each row, store this value for the next compare of contol break - strcpy (prev_user, PRV.RDB$USER); + prev_user = user; prev_grant_option = PRV.RDB$GRANT_OPTION; - strcpy (prev_grantor, PRV.RDB$GRANTOR); + prev_grantor = PRV.RDB$GRANTOR; - switch (PRV.RDB$USER_TYPE) - { - case obj_relation: - case obj_view: - case obj_trigger: - case obj_procedure: - case obj_udf: - case obj_sql_role: - case obj_package_header: - case obj_user: // Users can be machine\user and need quoting - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(PRV.RDB$USER, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, PRV.RDB$USER); - break; - default: - strcpy(SQL_identifier, PRV.RDB$USER); - break; - } - - set_grantee(PRV.RDB$USER_TYPE, SQL_identifier, user_string); + set_grantee(PRV.RDB$USER_TYPE, user, user_string); // Only the first character is used for permissions const char c = PRV.RDB$PRIVILEGE[0]; // Column level privileges for update and references only if (PRV.RDB$FIELD_NAME.NULL) - { - col_string = ""; priv_flags |= convert_privilege_to_code(c); - continue; - } else { - fb_utils::exact_name(PRV.RDB$FIELD_NAME); - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) + for (int i = 0; i < priv_fields_count; i++) { - IUTILS_copy_SQL_id(PRV.RDB$FIELD_NAME, SQL_identifier, DBL_QUOTE); - col_string = SQL_identifier; - } - else - { - col_string = PRV.RDB$FIELD_NAME; + if (c == priv_fields[i].privilege[0]) + { + if (priv_fields[i].fields.hasData()) + priv_fields[i].fields += ", "; + + priv_fields[i].fields += MetaString(PRV.RDB$FIELD_NAME).toQuotedString(); + break; + } } } - - for (int i = 0; i < priv_fields_count; i++) - { - if (c == priv_fields[i].privilege[0]) - { - priv_fields[i].fields += priv_fields[i].fields.isEmpty() ? col_string - : ", " + col_string; - break; - } - } - + } END_FOR ON_ERROR ISQL_errmsg (fbStatus); return ps_ERR; - END_ERROR; + END_ERROR // Print last case if there was anything to print @@ -1047,11 +1005,6 @@ processing_state SHOW_grants2 (const SCHAR* object, isqlGlob.prints(optional_msg); first = false; - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(object, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, object); - if (prev_grant_option) strcpy(with_option, " WITH GRANT OPTION"); @@ -1061,16 +1014,16 @@ processing_state SHOW_grants2 (const SCHAR* object, isqlGlob.printf("GRANT %s ON %s TO %s%s%s%s%s", combine_privileges.c_str(), - SQL_identifier, - user_string, with_option, granted_by(buf_grantor, prev_grantor, false), + name.toQuotedString().c_str(), + user_string.c_str(), with_option, granted_by(prev_grantor, false), terminator, NEWLINE); } - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR if (!first) return (SKIP); @@ -1079,9 +1032,13 @@ processing_state SHOW_grants2 (const SCHAR* object, // No relation called "object" was found, try procedure "object" if (obj_type == obj_procedure || obj_type == obj_any) { - FOR FIRST 1 P IN RDB$PROCEDURES WITH - P.RDB$PROCEDURE_NAME EQ object AND - P.RDB$PACKAGE_NAME MISSING + FOR FIRST 1 P IN RDB$PROCEDURES + WITH P.RDB$PROCEDURE_NAME EQ name.object.c_str() AND + P.RDB$PACKAGE_NAME MISSING + SORTED BY P.RDB$SCHEMA_NAME + { + if (name.schema.hasData() && name.schema != P.RDB$SCHEMA_NAME) + continue; // Part two is for stored procedures only @@ -1089,74 +1046,52 @@ processing_state SHOW_grants2 (const SCHAR* object, PRC IN RDB$PROCEDURES WITH PRV.RDB$GRANTOR NOT MISSING AND PRV.RDB$OBJECT_TYPE = obj_procedure AND - PRV.RDB$RELATION_NAME EQ object AND - PRC.RDB$PROCEDURE_NAME EQ object AND + PRV.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(P.RDB$SCHEMA_NAME, '') AND + PRV.RDB$RELATION_NAME EQ name.object.c_str() AND + PRC.RDB$SCHEMA_NAME EQUIV PRV.RDB$RELATION_SCHEMA_NAME AND + PRC.RDB$PROCEDURE_NAME EQ PRV.RDB$RELATION_NAME AND PRV.RDB$PRIVILEGE EQ 'X' AND PRC.RDB$OWNER_NAME NE PRV.RDB$USER AND PRC.RDB$PACKAGE_NAME MISSING - SORTED BY PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION - + SORTED BY PRV.RDB$USER_SCHEMA_NAME, PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION + { if (first && optional_msg) isqlGlob.prints(optional_msg); first = false; - fb_utils::exact_name(PRV.RDB$USER); - switch (PRV.RDB$USER_TYPE) - { - case obj_relation: - case obj_view: - case obj_trigger: - case obj_procedure: - case obj_udf: - case obj_sql_role: - case obj_package_header: - case obj_user: - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(PRV.RDB$USER, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, PRV.RDB$USER); - break; - default: - strcpy(SQL_identifier, PRV.RDB$USER); - break; - } - - set_grantee(PRV.RDB$USER_TYPE, SQL_identifier, user_string); + set_grantee(PRV.RDB$USER_TYPE, QualifiedMetaString(PRV.RDB$USER, PRV.RDB$USER_SCHEMA_NAME), user_string); if (PRV.RDB$GRANT_OPTION) strcpy(with_option, " WITH GRANT OPTION"); else with_option[0] = '\0'; - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(object, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, object); - isqlGlob.printf("GRANT EXECUTE ON PROCEDURE %s TO %s%s%s%s%s", - SQL_identifier, user_string, with_option, - granted_by(buf_grantor, PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), terminator, NEWLINE); - + name.toQuotedString().c_str(), + user_string.c_str(), with_option, + granted_by(PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), terminator, NEWLINE); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; END_ERROR + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR if (!first) return (SKIP); } // No procedure called "object" was found, try role "object" - SCHAR role_name[BUFFER_LENGTH256]; + MetaString role_name; - if (obj_type == obj_sql_role || obj_type == obj_any) + if ((obj_type == obj_sql_role || obj_type == obj_any) && name.schema.isEmpty()) { // No procedure called "object" was found, try role "object" // CVC: This code could be superseded by SHOW_grant_roles() below @@ -1164,26 +1099,21 @@ processing_state SHOW_grants2 (const SCHAR* object, // This part is only used by SHOW GRANT command // Metadata extraction and SHOW GRANT with no param uses SHOW_grant_roles. - FOR FIRST 1 R IN RDB$ROLES WITH R.RDB$ROLE_NAME EQ object + FOR FIRST 1 R IN RDB$ROLES + WITH R.RDB$ROLE_NAME EQ name.object.c_str() + { + FOR PRV IN RDB$USER_PRIVILEGES + WITH PRV.RDB$GRANTOR NOT MISSING AND + PRV.RDB$OBJECT_TYPE EQ obj_sql_role AND + (PRV.RDB$USER_TYPE EQ obj_user OR + PRV.RDB$USER_TYPE EQ obj_sql_role) AND + PRV.RDB$RELATION_NAME EQ name.object.c_str() AND + PRV.RDB$PRIVILEGE EQ 'M' + SORTED BY PRV.RDB$USER_SCHEMA_NAME, PRV.RDB$USER + { + role_name = PRV.RDB$RELATION_NAME; - FOR PRV IN RDB$USER_PRIVILEGES WITH - PRV.RDB$GRANTOR NOT MISSING AND - PRV.RDB$OBJECT_TYPE EQ obj_sql_role AND - (PRV.RDB$USER_TYPE EQ obj_user OR - PRV.RDB$USER_TYPE EQ obj_sql_role) AND - PRV.RDB$RELATION_NAME EQ object AND - PRV.RDB$PRIVILEGE EQ 'M' - SORTED BY PRV.RDB$USER - - fb_utils::exact_name(PRV.RDB$RELATION_NAME); - strcpy (role_name, PRV.RDB$RELATION_NAME); - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(role_name, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, role_name); - - fb_utils::exact_name(PRV.RDB$USER); - strcpy(user_string, PRV.RDB$USER); + user_string = MetaString(PRV.RDB$USER).toQuotedString(); if (PRV.RDB$GRANT_OPTION) strcpy(with_option, " WITH ADMIN OPTION"); @@ -1195,8 +1125,9 @@ processing_state SHOW_grants2 (const SCHAR* object, default_option = " DEFAULT"; fb_utils::snprintf(Print_buffer, sizeof(Print_buffer), "GRANT%s %s TO %s%s%s%s%s", - default_option, SQL_identifier, - user_string, with_option, granted_by(buf_grantor, PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), + default_option, + role_name.toQuotedString().c_str(), + user_string.c_str(), with_option, granted_by(PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), terminator, NEWLINE); if (first && optional_msg) @@ -1204,18 +1135,18 @@ processing_state SHOW_grants2 (const SCHAR* object, first = false; isqlGlob.prints(Print_buffer); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; - + END_ERROR + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR if (!first) return (SKIP); @@ -1225,70 +1156,54 @@ processing_state SHOW_grants2 (const SCHAR* object, { if (isqlGlob.major_ods >= ODS_VERSION12) { - FOR FIRST 1 P IN RDB$PACKAGES WITH P.RDB$PACKAGE_NAME EQ object + FOR FIRST 1 P IN RDB$PACKAGES + WITH P.RDB$PACKAGE_NAME EQ name.object.c_str() + SORTED BY P.RDB$SCHEMA_NAME + { + if (name.schema.hasData() && name.schema != P.RDB$SCHEMA_NAME) + continue; + FOR PRV IN RDB$USER_PRIVILEGES CROSS PACK IN RDB$PACKAGES WITH PRV.RDB$GRANTOR NOT MISSING AND PRV.RDB$OBJECT_TYPE = obj_package_header AND - PRV.RDB$RELATION_NAME EQ object AND - PACK.RDB$PACKAGE_NAME EQ object AND + PRV.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(P.RDB$SCHEMA_NAME, '') AND + PRV.RDB$RELATION_NAME EQ name.object.c_str() AND + PACK.RDB$SCHEMA_NAME EQUIV PRV.RDB$RELATION_SCHEMA_NAME AND + PACK.RDB$PACKAGE_NAME EQ PRV.RDB$RELATION_NAME AND PRV.RDB$PRIVILEGE EQ 'X' AND PACK.RDB$OWNER_NAME NE PRV.RDB$USER - SORTED BY PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION - + SORTED BY PRV.RDB$USER_SCHEMA_NAME, PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION + { if (first && optional_msg) isqlGlob.prints(optional_msg); first = false; - fb_utils::exact_name(PRV.RDB$USER); - switch (PRV.RDB$USER_TYPE) - { - case obj_relation: - case obj_view: - case obj_trigger: - case obj_procedure: - case obj_udf: - case obj_sql_role: - case obj_package_header: - case obj_user: - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(PRV.RDB$USER, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, PRV.RDB$USER); - break; - default: - strcpy(SQL_identifier, PRV.RDB$USER); - break; - } - - set_grantee(PRV.RDB$USER_TYPE, SQL_identifier, user_string); + set_grantee(PRV.RDB$USER_TYPE, QualifiedMetaString(PRV.RDB$USER, PRV.RDB$USER_SCHEMA_NAME), user_string); if (PRV.RDB$GRANT_OPTION) strcpy(with_option, " WITH GRANT OPTION"); else with_option[0] = '\0'; - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(object, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, object); - isqlGlob.printf("GRANT EXECUTE ON PACKAGE %s TO %s%s%s%s%s", - SQL_identifier, user_string, with_option, - granted_by(buf_grantor, PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), + name.toQuotedString().c_str(), + user_string.c_str(), with_option, + granted_by(PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), terminator, NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; END_ERROR + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR if (!first) return (SKIP); @@ -1300,73 +1215,55 @@ processing_state SHOW_grants2 (const SCHAR* object, if (isqlGlob.major_ods >= ODS_VERSION12) { FOR FIRST 1 F IN RDB$FUNCTIONS - WITH F.RDB$FUNCTION_NAME EQ object AND - F.RDB$PACKAGE_NAME MISSING + WITH F.RDB$FUNCTION_NAME EQ name.object.c_str() AND + F.RDB$PACKAGE_NAME MISSING + SORTED BY F.RDB$SCHEMA_NAME + { + if (name.schema.hasData() && name.schema != F.RDB$SCHEMA_NAME) + continue; FOR PRV IN RDB$USER_PRIVILEGES CROSS FUN IN RDB$FUNCTIONS WITH PRV.RDB$GRANTOR NOT MISSING AND PRV.RDB$OBJECT_TYPE = obj_udf AND - PRV.RDB$RELATION_NAME EQ object AND - FUN.RDB$FUNCTION_NAME EQ object AND + PRV.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(F.RDB$SCHEMA_NAME, '') AND + PRV.RDB$RELATION_NAME EQ name.object.c_str() AND + FUN.RDB$SCHEMA_NAME EQUIV PRV.RDB$RELATION_SCHEMA_NAME AND + FUN.RDB$FUNCTION_NAME EQ PRV.RDB$RELATION_NAME AND FUN.RDB$PACKAGE_NAME MISSING AND PRV.RDB$PRIVILEGE EQ 'X' AND FUN.RDB$OWNER_NAME NE PRV.RDB$USER - SORTED BY PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION - + SORTED BY PRV.RDB$USER_SCHEMA_NAME, PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION + { if (first && optional_msg) isqlGlob.prints(optional_msg); first = false; - fb_utils::exact_name(PRV.RDB$USER); - switch (PRV.RDB$USER_TYPE) - { - case obj_relation: - case obj_view: - case obj_trigger: - case obj_procedure: - case obj_udf: - case obj_sql_role: - case obj_package_header: - case obj_user: - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(PRV.RDB$USER, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, PRV.RDB$USER); - break; - default: - strcpy(SQL_identifier, PRV.RDB$USER); - break; - } - - set_grantee(PRV.RDB$USER_TYPE, SQL_identifier, user_string); + set_grantee(PRV.RDB$USER_TYPE, QualifiedMetaString(PRV.RDB$USER, PRV.RDB$USER_SCHEMA_NAME), user_string); if (PRV.RDB$GRANT_OPTION) strcpy(with_option, " WITH GRANT OPTION"); else with_option[0] = '\0'; - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(object, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, object); - isqlGlob.printf("GRANT EXECUTE ON FUNCTION %s TO %s%s%s%s%s", - SQL_identifier, user_string, with_option, - granted_by(buf_grantor, PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), + name.toQuotedString().c_str(), + user_string.c_str(), with_option, + granted_by(PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), terminator, NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; END_ERROR + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR if (!first) return (SKIP); @@ -1377,70 +1274,54 @@ processing_state SHOW_grants2 (const SCHAR* object, { if (isqlGlob.major_ods >= ODS_VERSION12) { - FOR FIRST 1 G IN RDB$GENERATORS WITH G.RDB$GENERATOR_NAME EQ object + FOR FIRST 1 G IN RDB$GENERATORS + WITH G.RDB$GENERATOR_NAME EQ name.object.c_str() + SORTED BY G.RDB$SCHEMA_NAME + { + if (name.schema.hasData() && name.schema != G.RDB$SCHEMA_NAME) + continue; + FOR PRV IN RDB$USER_PRIVILEGES CROSS GEN IN RDB$GENERATORS WITH PRV.RDB$GRANTOR NOT MISSING AND PRV.RDB$OBJECT_TYPE = obj_generator AND - PRV.RDB$RELATION_NAME EQ object AND - GEN.RDB$GENERATOR_NAME EQ object AND + PRV.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(G.RDB$SCHEMA_NAME, '') AND + PRV.RDB$RELATION_NAME EQ name.object.c_str() AND + GEN.RDB$SCHEMA_NAME EQUIV PRV.RDB$RELATION_SCHEMA_NAME AND + GEN.RDB$GENERATOR_NAME EQ PRV.RDB$RELATION_NAME AND PRV.RDB$PRIVILEGE EQ 'G' AND GEN.RDB$OWNER_NAME NE PRV.RDB$USER - SORTED BY PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION - + SORTED BY PRV.RDB$USER_SCHEMA_NAME, PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION + { if (first && optional_msg) isqlGlob.prints(optional_msg); first = false; - fb_utils::exact_name(PRV.RDB$USER); - switch (PRV.RDB$USER_TYPE) - { - case obj_relation: - case obj_view: - case obj_trigger: - case obj_procedure: - case obj_udf: - case obj_sql_role: - case obj_package_header: - case obj_user: - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(PRV.RDB$USER, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, PRV.RDB$USER); - break; - default: - strcpy(SQL_identifier, PRV.RDB$USER); - break; - } - - set_grantee(PRV.RDB$USER_TYPE, SQL_identifier, user_string); + set_grantee(PRV.RDB$USER_TYPE, QualifiedMetaString(PRV.RDB$USER, PRV.RDB$USER_SCHEMA_NAME), user_string); if (PRV.RDB$GRANT_OPTION) strcpy(with_option, " WITH GRANT OPTION"); else with_option[0] = '\0'; - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(object, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, object); - isqlGlob.printf("GRANT USAGE ON SEQUENCE %s TO %s%s%s%s%s", - SQL_identifier, user_string, with_option, - granted_by(buf_grantor, PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), + name.toQuotedString().c_str(), + user_string.c_str(), with_option, + granted_by(PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), terminator, NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; END_ERROR + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR if (!first) return (SKIP); @@ -1451,65 +1332,49 @@ processing_state SHOW_grants2 (const SCHAR* object, { if (isqlGlob.major_ods >= ODS_VERSION12) { - FOR FIRST 1 E IN RDB$EXCEPTIONS WITH E.RDB$EXCEPTION_NAME EQ object + FOR FIRST 1 E IN RDB$EXCEPTIONS + WITH E.RDB$EXCEPTION_NAME EQ name.object.c_str() + SORTED BY E.RDB$SCHEMA_NAME + { + if (name.schema.hasData() && name.schema != E.RDB$SCHEMA_NAME) + continue; + FOR PRV IN RDB$USER_PRIVILEGES CROSS XCP IN RDB$EXCEPTIONS WITH PRV.RDB$GRANTOR NOT MISSING AND PRV.RDB$OBJECT_TYPE = obj_exception AND - PRV.RDB$RELATION_NAME EQ object AND - XCP.RDB$EXCEPTION_NAME EQ object AND + PRV.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(E.RDB$SCHEMA_NAME, '') AND + PRV.RDB$RELATION_NAME EQ name.object.c_str() AND + XCP.RDB$SCHEMA_NAME EQUIV PRV.RDB$RELATION_SCHEMA_NAME AND + XCP.RDB$EXCEPTION_NAME EQ PRV.RDB$RELATION_NAME AND PRV.RDB$PRIVILEGE EQ 'G' AND XCP.RDB$OWNER_NAME NE PRV.RDB$USER - SORTED BY PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION - + SORTED BY PRV.RDB$USER_SCHEMA_NAME, PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION + { if (first && optional_msg) isqlGlob.prints(optional_msg); first = false; - fb_utils::exact_name(PRV.RDB$USER); - switch (PRV.RDB$USER_TYPE) - { - case obj_relation: - case obj_view: - case obj_trigger: - case obj_procedure: - case obj_udf: - case obj_sql_role: - case obj_package_header: - case obj_user: - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(PRV.RDB$USER, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, PRV.RDB$USER); - break; - default: - strcpy(SQL_identifier, PRV.RDB$USER); - break; - } - - set_grantee(PRV.RDB$USER_TYPE, SQL_identifier, user_string); + set_grantee(PRV.RDB$USER_TYPE, QualifiedMetaString(PRV.RDB$USER, PRV.RDB$USER_SCHEMA_NAME), user_string); if (PRV.RDB$GRANT_OPTION) strcpy(with_option, " WITH GRANT OPTION"); else with_option[0] = '\0'; - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(object, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, object); - isqlGlob.printf("GRANT USAGE ON EXCEPTION %s TO %s%s%s%s%s", - SQL_identifier, user_string, with_option, - granted_by(buf_grantor, PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), + name.toQuotedString().c_str(), + user_string.c_str(), with_option, + granted_by(PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), terminator, NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; END_ERROR + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -1521,240 +1386,20 @@ processing_state SHOW_grants2 (const SCHAR* object, } } - /*** - if (obj_type == obj_field || obj_type == 255) - { - if (isqlGlob.major_ods >= ODS_VERSION12) - { - FOR FIRST 1 F IN RDB$FIELDS WITH F.RDB$FIELD_NAME EQ object - FOR PRV IN RDB$USER_PRIVILEGES CROSS - FLD IN RDB$FIELDS WITH - PRV.RDB$GRANTOR NOT MISSING AND - PRV.RDB$OBJECT_TYPE = obj_field AND - PRV.RDB$RELATION_NAME EQ object AND - FLD.RDB$FIELD_NAME EQ object AND - PRV.RDB$PRIVILEGE EQ 'G' AND - FLD.RDB$OWNER_NAME NE PRV.RDB$USER - SORTED BY PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION - - if (first && optional_msg) - isqlGlob.prints(optional_msg); - - first = false; - fb_utils::exact_name(PRV.RDB$USER); - - switch (PRV.RDB$USER_TYPE) - { - case obj_relation: - case obj_view: - case obj_trigger: - case obj_procedure: - case obj_udf: - case obj_sql_role: - case obj_package_header: - case obj_user: - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(PRV.RDB$USER, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, PRV.RDB$USER); - break; - default: - strcpy(SQL_identifier, PRV.RDB$USER); - break; - } - - set_grantee(PRV.RDB$USER_TYPE, SQL_identifier, user_string); - - if (PRV.RDB$GRANT_OPTION) - strcpy(with_option, " WITH GRANT OPTION"); - else - with_option[0] = '\0'; - - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(object, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, object); - - isqlGlob.printf("GRANT USAGE ON DOMAIN %s TO %s%s%s%s%s", - SQL_identifier, user_string, with_option, - granted_by(buf_grantor, PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), - terminator, NEWLINE); - - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return ps_ERR; - END_ERROR - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return ps_ERR; - END_ERROR; - - if (!first) - return (SKIP); - } - } - - if (obj_type == obj_charset || obj_type == 255) - { - if (isqlGlob.major_ods >= ODS_VERSION12) - { - FOR FIRST 1 C IN RDB$CHARACTER_SETS WITH C.RDB$CHARACTER_SET_NAME EQ object - FOR PRV IN RDB$USER_PRIVILEGES CROSS - CS IN RDB$CHARACTER_SETS WITH - PRV.RDB$GRANTOR NOT MISSING AND - PRV.RDB$OBJECT_TYPE = obj_charset AND - PRV.RDB$RELATION_NAME EQ object AND - CS.RDB$CHARACTER_SET_NAME EQ object AND - PRV.RDB$PRIVILEGE EQ 'G' AND - CS.RDB$OWNER_NAME NE PRV.RDB$USER - SORTED BY PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION - - if (first && optional_msg) - isqlGlob.prints(optional_msg); - - first = false; - fb_utils::exact_name(PRV.RDB$USER); - - switch (PRV.RDB$USER_TYPE) - { - case obj_relation: - case obj_view: - case obj_trigger: - case obj_procedure: - case obj_udf: - case obj_sql_role: - case obj_package_header: - case obj_user: - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(PRV.RDB$USER, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, PRV.RDB$USER); - break; - default: - strcpy(SQL_identifier, PRV.RDB$USER); - break; - } - - set_grantee(PRV.RDB$USER_TYPE, SQL_identifier, user_string); - - if (PRV.RDB$GRANT_OPTION) - strcpy(with_option, " WITH GRANT OPTION"); - else - with_option[0] = '\0'; - - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(object, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, object); - - isqlGlob.printf("GRANT USAGE ON CHARACTER SET %s TO %s%s%s%s%s", - SQL_identifier, user_string, with_option, - granted_by(buf_grantor, PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), - terminator, NEWLINE); - - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return ps_ERR; - END_ERROR - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return ps_ERR; - END_ERROR; - - if (!first) - return (SKIP); - } - } - - if (obj_type == obj_collation || obj_type == 255) - { - if (isqlGlob.major_ods >= ODS_VERSION12) - { - FOR FIRST 1 C IN RDB$COLLATIONS WITH C.RDB$COLLATION_NAME EQ object - FOR PRV IN RDB$USER_PRIVILEGES CROSS - COL IN RDB$COLLATIONS WITH - PRV.RDB$GRANTOR NOT MISSING AND - PRV.RDB$OBJECT_TYPE = obj_collation AND - PRV.RDB$RELATION_NAME EQ object AND - COL.RDB$COLLATION_NAME EQ object AND - PRV.RDB$PRIVILEGE EQ 'G' AND - COL.RDB$OWNER_NAME NE PRV.RDB$USER - SORTED BY PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION - - if (first && optional_msg) - isqlGlob.prints(optional_msg); - - first = false; - fb_utils::exact_name(PRV.RDB$USER); - - switch (PRV.RDB$USER_TYPE) - { - case obj_relation: - case obj_view: - case obj_trigger: - case obj_procedure: - case obj_udf: - case obj_sql_role: - case obj_package_header: - case obj_user: - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(PRV.RDB$USER, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, PRV.RDB$USER); - break; - default: - strcpy(SQL_identifier, PRV.RDB$USER); - break; - } - - set_grantee(PRV.RDB$USER_TYPE, SQL_identifier, user_string); - - if (PRV.RDB$GRANT_OPTION) - strcpy(with_option, " WITH GRANT OPTION"); - else - with_option[0] = '\0'; - - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(object, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, object); - - isqlGlob.printf("GRANT USAGE ON COLLATION %s TO %s%s%s%s%s", - SQL_identifier, user_string, with_option, - granted_by(buf_grantor, PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), - terminator, NEWLINE); - - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return ps_ERR; - END_ERROR - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return ps_ERR; - END_ERROR; - - if (!first) - return (SKIP); - } - } - ***/ + // FIXME: USAGE ON SCHEMA if (isDdlObject(obj_type) || obj_type == obj_any) { + // FIXME: schema if (isqlGlob.major_ods >= ODS_VERSION12) { - FOR PRV IN RDB$USER_PRIVILEGES WITH - PRV.RDB$GRANTOR NOT MISSING AND - PRV.RDB$OBJECT_TYPE >= obj_database AND - PRV.RDB$RELATION_NAME EQ object - SORTED BY PRV.RDB$USER, PRV.RDB$GRANT_OPTION - + FOR PRV IN RDB$USER_PRIVILEGES + WITH PRV.RDB$GRANTOR NOT MISSING AND + PRV.RDB$OBJECT_TYPE >= obj_database AND + // FIXME: schema + PRV.RDB$RELATION_NAME EQ name.object.c_str() + SORTED BY PRV.RDB$USER_SCHEMA_NAME, PRV.RDB$USER, PRV.RDB$GRANT_OPTION + { // Double check if the object is DDL one. if (!isDdlObject(PRV.RDB$OBJECT_TYPE)) continue; @@ -1768,7 +1413,6 @@ processing_state SHOW_grants2 (const SCHAR* object, priv_flags = 0; first = false; - fb_utils::exact_name(PRV.RDB$USER); // Only the first character is used for permissions @@ -1792,27 +1436,7 @@ processing_state SHOW_grants2 (const SCHAR* object, make_priv_string(priv_flags, priv_string, (PRV.RDB$OBJECT_TYPE != obj_database)); - switch (PRV.RDB$USER_TYPE) - { - case obj_relation: - case obj_view: - case obj_trigger: - case obj_procedure: - case obj_udf: - case obj_sql_role: - case obj_package_header: - case obj_user: - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(PRV.RDB$USER, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, PRV.RDB$USER); - break; - default: - strcpy(SQL_identifier, PRV.RDB$USER); - break; - } - - set_grantee(PRV.RDB$USER_TYPE, SQL_identifier, user_string); + set_grantee(PRV.RDB$USER_TYPE, QualifiedMetaString(PRV.RDB$USER, PRV.RDB$USER_SCHEMA_NAME), user_string); strcpy(obj_string, getDdlObjectName(PRV.RDB$OBJECT_TYPE)); @@ -1822,10 +1446,10 @@ processing_state SHOW_grants2 (const SCHAR* object, with_option[0] = '\0'; isqlGlob.printf("GRANT %s %s TO %s%s%s%s%s", - priv_string, obj_string, user_string, with_option, - granted_by(buf_grantor, PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), + priv_string, obj_string, user_string.c_str(), with_option, + granted_by(PRV.RDB$GRANTOR, PRV.RDB$GRANTOR.NULL), terminator, NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -1836,33 +1460,17 @@ processing_state SHOW_grants2 (const SCHAR* object, { FOR PRV IN SEC$DB_CREATORS SORTED BY PRV.SEC$USER_TYPE, PRV.SEC$USER - + { if (first && optional_msg) isqlGlob.prints(optional_msg); first = false; - fb_utils::exact_name(PRV.SEC$USER); - switch (PRV.SEC$USER_TYPE) - { - case obj_sql_role: - case obj_user: - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(PRV.SEC$USER, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, PRV.SEC$USER); - break; - default: - fb_assert(false); - strcpy(SQL_identifier, PRV.SEC$USER); - break; - } - - set_grantee(PRV.SEC$USER_TYPE, SQL_identifier, user_string); + set_grantee(PRV.SEC$USER_TYPE, QualifiedMetaString(PRV.SEC$USER), user_string); isqlGlob.printf("GRANT CREATE DATABASE TO %s%s%s", - user_string, terminator, NEWLINE); - + user_string.c_str(), terminator, NEWLINE); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -1879,25 +1487,8 @@ processing_state SHOW_grants2 (const SCHAR* object, } -void SHOW_grant_roles(const SCHAR* terminator, bool* first) -{ -/************************************** - * - * S H O W _ g r a n t _ r o l e s - * - ************************************** - * - * Functional description - * Placeholder for SHOW_grant_roles2 without additional message. - * - **************************************/ - SHOW_grant_roles2 (terminator, first, 0, false); -} - -void SHOW_grant_roles2 (const SCHAR* terminator, - bool* first, - const TEXT* optional_msg, - bool mangle) +// FIXME: use "extract" +void SHOW_grant_roles(const SCHAR* terminator, bool* first, const TEXT* optional_msg, bool extract) { /************************************** * @@ -1911,7 +1502,6 @@ void SHOW_grant_roles2 (const SCHAR* terminator, * All membership privilege may have the with_admin or/and default options set. * **************************************/ - TEXT SQL_identifier2[BUFFER_LENGTH256]; BASED_ON RDB$USER_PRIVILEGES.RDB$GRANTOR dummy; // used to declare buf_grantor FB_UNUSED_VAR(dummy); // Silence compiler warning about unused variable SCHAR buf_grantor[sizeof(dummy) + 20]; @@ -1925,7 +1515,7 @@ void SHOW_grant_roles2 (const SCHAR* terminator, PRV.RDB$USER_TYPE EQ obj_sql_role) AND PRV.RDB$PRIVILEGE EQ 'M' SORTED BY PRV.RDB$RELATION_NAME, PRV.RDB$USER - + { if (first) { if (*first && optional_msg) { @@ -1934,8 +1524,6 @@ void SHOW_grant_roles2 (const SCHAR* terminator, *first = false; } - const char* user_string = fb_utils::exact_name(PRV.RDB$USER); - const char* with_option = ""; if (PRV.RDB$GRANT_OPTION) with_option = " WITH ADMIN OPTION"; @@ -1943,22 +1531,22 @@ void SHOW_grant_roles2 (const SCHAR* terminator, if (!PRV.RDB$FIELD_NAME.NULL && PRV.RDB$FIELD_NAME[0] == 'D') default_option = " DEFAULT"; - const char* role = fb_utils::exact_name(PRV.RDB$RELATION_NAME); - const char* grantor = fb_utils::exact_name(PRV.RDB$GRANTOR); - if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - IUTILS_copy_SQL_id (PRV.RDB$RELATION_NAME, SQL_identifier, DBL_QUOTE); - role = SQL_identifier; - IUTILS_copy_SQL_id(PRV.RDB$USER, SQL_identifier2, DBL_QUOTE); - user_string = SQL_identifier2; - } - isqlGlob.printf("GRANT%s %s TO %s%s%s%s%s", default_option, role, - user_string, with_option, granted_by(buf_grantor, grantor, false), terminator, NEWLINE); + const MetaString grantor(PRV.RDB$GRANTOR); + isqlGlob.printf( + "GRANT%s %s TO %s%s%s%s%s", + default_option, + MetaString(PRV.RDB$RELATION_NAME).toQuotedString().c_str(), + MetaString(PRV.RDB$USER).toQuotedString().c_str(), + with_option, + granted_by(grantor, false), + terminator, + NEWLINE); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); - END_ERROR; + END_ERROR } @@ -2108,7 +1696,7 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) {0, "SECCLASSES", 6}, // SECCLA {0, "USERS", 0}, {0, "PACKAGES", 4}, // PACK - ///{0, "SCHEMAS", 4}, // SCHE + ///{0, "SCHEMAS", 4}, // SCHE // FIXME: {0, "MAPPINGS", 3}, // MAP {0, "PUBLICATIONS", 3}, // PUB {0, "WIRE_STATISTICS", 9}, // WIRE_STAT @@ -2125,7 +1713,7 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) } int key = 0; - MetaString notFoundName; + QualifiedMetaString notFoundName; const auto ret = std::visit(StdVisitOverloads{ [](const FrontendParser::InvalidNode&) @@ -2144,16 +1732,20 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) [&](const FrontendParser::ShowChecksNode& node) { - const auto ret = show_check((node.name ? node.name->c_str() : "")); + const auto ret = show_check(node.name); if (ret == OBJECT_NOT_FOUND) { if (node.name) { - FOR FIRST 1 R IN RDB$RELATIONS - WITH R.RDB$RELATION_NAME EQ node.name->c_str() + FOR R IN RDB$RELATIONS + WITH R.RDB$RELATION_NAME EQ node.name->object.c_str() { + if (node.name->schema.hasData() && node.name->schema != R.RDB$SCHEMA_NAME) + continue; + key = NO_CHECKS_ON_REL; + break; } END_FOR ON_ERROR @@ -2172,7 +1764,7 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) [&](const FrontendParser::ShowCollationsNode& node) { - const auto ret = show_collations((node.name ? node.name->c_str() : ""), 0); + const auto ret = show_collations(node.name, 0); if (ret == OBJECT_NOT_FOUND) { @@ -2190,7 +1782,7 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) [&](const FrontendParser::ShowCommentsNode&) { - const auto ret = show_comments(cmmShow, 0); + const auto ret = show_comments(cmmShow, nullptr); if (ret == OBJECT_NOT_FOUND) key = NO_COMMENTS; @@ -2206,7 +1798,7 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) [&](const FrontendParser::ShowDependenciesNode& node) { - const auto ret = show_dependencies((node.name ? node.name->c_str() : "")); + const auto ret = show_dependencies(node.name); if (ret == OBJECT_NOT_FOUND) key = NO_DEPENDENCIES; @@ -2216,7 +1808,7 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) [&](const FrontendParser::ShowDomainsNode& node) { - const auto ret = show_domains((node.name ? node.name->c_str() : "")); + const auto ret = show_domains(node.name); if (ret == OBJECT_NOT_FOUND) { @@ -2234,7 +1826,7 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) [&](const FrontendParser::ShowExceptionsNode& node) { - const auto ret = show_exceptions((node.name ? node.name->c_str() : "")); + const auto ret = show_exceptions(node.name); if (ret == OBJECT_NOT_FOUND) { @@ -2252,14 +1844,14 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) [&](const FrontendParser::ShowFiltersNode& node) { - const auto ret = show_filters((node.name ? node.name->c_str() : "")); + const auto ret = show_filters(node.name); if (ret == OBJECT_NOT_FOUND) { if (node.name) { key = NO_FILTER; - notFoundName = node.name.value(); + notFoundName.object = node.name.value(); } else key = NO_FILTERS; @@ -2270,10 +1862,7 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) [&](const FrontendParser::ShowFunctionsNode& node) { - const auto ret = show_functions( - (node.name ? node.name->c_str() : ""), - (node.package ? node.package->c_str() : ""), - false, false); + const auto ret = show_functions(node.name, false, false); if (ret == OBJECT_NOT_FOUND) { @@ -2291,7 +1880,7 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) [&](const FrontendParser::ShowGeneratorsNode& node) { - const auto ret = show_generators((node.name ? node.name->c_str() : "")); + const auto ret = show_generators(node.name); if (ret == OBJECT_NOT_FOUND) { @@ -2312,7 +1901,7 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) processing_state ret; if (node.name) - ret = SHOW_grants(node.name->c_str(), "", obj_any); + ret = SHOW_grants(node.name, "", obj_any); else ret = EXTRACT_list_grants(""); @@ -2320,10 +1909,14 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) { if (node.name) { - FOR FIRST 1 R IN RDB$RELATIONS - WITH R.RDB$RELATION_NAME EQ node.name->c_str() + FOR R IN RDB$RELATIONS + WITH R.RDB$RELATION_NAME EQ node.name->object.c_str() { + if (node.name->schema.hasData() && node.name->schema != R.RDB$SCHEMA_NAME) + continue; + key = NO_GRANT_ON_REL; + break; } END_FOR ON_ERROR @@ -2332,11 +1925,15 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) if (!key) { - FOR FIRST 1 P IN RDB$PROCEDURES - WITH P.RDB$PROCEDURE_NAME EQ node.name->c_str() AND + FOR P IN RDB$PROCEDURES + WITH P.RDB$PROCEDURE_NAME EQ node.name->object.c_str() AND P.RDB$PACKAGE_NAME MISSING { + if (node.name->schema.hasData() && node.name->schema != P.RDB$SCHEMA_NAME) + continue; + key = NO_GRANT_ON_PROC; + break; } END_FOR ON_ERROR @@ -2344,10 +1941,10 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) END_ERROR } - if (!key) + if (!key && node.name->schema.isEmpty()) { FOR FIRST 1 R IN RDB$ROLES - WITH R.RDB$ROLE_NAME EQ node.name->c_str() + WITH R.RDB$ROLE_NAME EQ node.name->object.c_str() { key = NO_GRANT_ON_ROL; } @@ -2359,11 +1956,15 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) if (!key) { - FOR FIRST 1 F IN RDB$FUNCTIONS - WITH F.RDB$FUNCTION_NAME EQ node.name->c_str() AND + FOR F IN RDB$FUNCTIONS + WITH F.RDB$FUNCTION_NAME EQ node.name->object.c_str() AND F.RDB$PACKAGE_NAME MISSING { + if (node.name->schema.hasData() && node.name->schema != F.RDB$SCHEMA_NAME) + continue; + key = NO_GRANT_ON_FUN; + break; } END_FOR ON_ERROR @@ -2373,10 +1974,14 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) if (!key) { - FOR FIRST 1 G IN RDB$GENERATORS - WITH G.RDB$GENERATOR_NAME EQ node.name->c_str() + FOR G IN RDB$GENERATORS + WITH G.RDB$GENERATOR_NAME EQ node.name->object.c_str() { + if (node.name->schema.hasData() && node.name->schema != G.RDB$SCHEMA_NAME) + continue; + key = NO_GRANT_ON_GEN; + break; } END_FOR ON_ERROR @@ -2386,10 +1991,14 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) if (!key) { - FOR FIRST 1 E IN RDB$EXCEPTIONS - WITH E.RDB$EXCEPTION_NAME EQ node.name->c_str() + FOR E IN RDB$EXCEPTIONS + WITH E.RDB$EXCEPTION_NAME EQ node.name->object.c_str() { + if (node.name->schema.hasData() && node.name->schema != E.RDB$SCHEMA_NAME) + continue; + key = NO_GRANT_ON_XCP; + break; } END_FOR ON_ERROR @@ -2399,10 +2008,14 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) if (!key) { - FOR FIRST 1 F IN RDB$FIELDS - WITH F.RDB$FIELD_NAME EQ node.name->c_str() + FOR F IN RDB$FIELDS + WITH F.RDB$FIELD_NAME EQ node.name->object.c_str() { + if (node.name->schema.hasData() && node.name->schema != F.RDB$SCHEMA_NAME) + continue; + key = NO_GRANT_ON_FLD; + break; } END_FOR ON_ERROR @@ -2412,10 +2025,14 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) if (!key) { - FOR FIRST 1 CS IN RDB$CHARACTER_SETS - WITH CS.RDB$CHARACTER_SET_NAME EQ node.name->c_str() + FOR CS IN RDB$CHARACTER_SETS + WITH CS.RDB$CHARACTER_SET_NAME EQ node.name->object.c_str() { + if (node.name->schema.hasData() && node.name->schema != CS.RDB$SCHEMA_NAME) + continue; + key = NO_GRANT_ON_CS; + break; } END_FOR ON_ERROR @@ -2425,10 +2042,14 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) if (!key) { - FOR FIRST 1 C IN RDB$COLLATIONS - WITH C.RDB$COLLATION_NAME EQ node.name->c_str() + FOR C IN RDB$COLLATIONS + WITH C.RDB$COLLATION_NAME EQ node.name->object.c_str() { + if (node.name->schema.hasData() && node.name->schema != C.RDB$SCHEMA_NAME) + continue; + key = NO_GRANT_ON_COLL; + break; } END_FOR ON_ERROR @@ -2438,10 +2059,14 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) if (!key && isqlGlob.major_ods >= ODS_VERSION12) { - FOR FIRST 1 P IN RDB$PACKAGES - WITH P.RDB$PACKAGE_NAME EQ node.name->c_str() + FOR P IN RDB$PACKAGES + WITH P.RDB$PACKAGE_NAME EQ node.name->object.c_str() { + if (node.name->schema.hasData() && node.name->schema != P.RDB$SCHEMA_NAME) + continue; + key = NO_GRANT_ON_PKG; + break; } END_FOR ON_ERROR @@ -2463,16 +2088,20 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) [&](const FrontendParser::ShowIndexesNode& node) { - const auto ret = show_indices((node.name ? node.name->c_str() : "")); + const auto ret = show_indices(node.name); if (ret == OBJECT_NOT_FOUND) { if (node.name) { - FOR FIRST 1 R IN RDB$RELATIONS - WITH R.RDB$RELATION_NAME EQ node.name->c_str() + FOR R IN RDB$RELATIONS + WITH R.RDB$RELATION_NAME EQ node.name->object.c_str() { + if (node.name->schema.hasData() && node.name->schema != R.RDB$SCHEMA_NAME) + continue; + key = NO_INDICES_ON_REL; + break; } END_FOR ON_ERROR @@ -2493,14 +2122,14 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) [&](const FrontendParser::ShowMappingsNode& node) { - const auto ret = SHOW_maps(false, (node.name ? node.name->c_str() : "")); + const auto ret = SHOW_maps(false, node.name); if (ret == OBJECT_NOT_FOUND) { if (node.name) { key = NO_MAP; - notFoundName = node.name.value(); + notFoundName.object = node.name.value(); } else key = NO_MAPS; @@ -2511,7 +2140,7 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) [&](const FrontendParser::ShowPackagesNode& node) { - const auto ret = show_packages((node.name ? node.name->c_str() : ""), false); + const auto ret = show_packages(node.name, false); if (ret == OBJECT_NOT_FOUND) { @@ -2529,10 +2158,7 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) [&](const FrontendParser::ShowProceduresNode& node) { - const auto ret = show_proc( - (node.name ? node.name->c_str() : ""), - (node.package ? node.package->c_str() : ""), - false, false); + const auto ret = show_proc(node.name, false, false); if (ret == OBJECT_NOT_FOUND) { @@ -2550,14 +2176,14 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) [&](const FrontendParser::ShowPublicationsNode& node) { - const auto ret = show_publications((node.name ? node.name->c_str() : ""), false); + const auto ret = show_publications(node.name, false); if (ret == OBJECT_NOT_FOUND) { if (node.name) { key = NO_PUBLICATION; - notFoundName = node.name.value(); + notFoundName.object = node.name.value(); } else key = NO_PUBLICATIONS; @@ -2574,17 +2200,17 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) { if (node.name) { - ret = show_role(node.name->c_str(), false); + ret = show_role(node.name, false); if (ret == OBJECT_NOT_FOUND) { key = NO_ROLE; - notFoundName = node.name.value(); + notFoundName.object = node.name.value(); } } else { - ret = show_role(nullptr, false); + ret = show_role(std::nullopt, false); if (ret == OBJECT_NOT_FOUND) key = NO_ROLES; } @@ -2628,11 +2254,11 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) switch (node.objType.value()) { case obj_collation: - show_collations("", 1); + show_collations(std::nullopt, 1); break; case obj_udf: - show_functions(nullptr, nullptr, false, true); + show_functions(std::nullopt, false, true); break; case obj_relation: @@ -2640,19 +2266,19 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) break; case obj_sql_role: - show_role(nullptr, true); + show_role(std::nullopt, true); break; case obj_procedure: - show_proc(nullptr, nullptr, false, true); + show_proc(std::nullopt, false, true); break; case obj_package_header: - show_packages(nullptr, true); + show_packages(std::nullopt, true); break; case obj_publication: - show_publications(nullptr, true); + show_publications(std::nullopt, true); break; default: @@ -2666,17 +2292,17 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) isqlGlob.printf("%s%s", msg, NEWLINE); show_all_tables(1); IUTILS_msg_get(MSG_FUNCTIONS, msg); - show_functions(nullptr, nullptr, false, true, msg); + show_functions(std::nullopt, false, true, msg); IUTILS_msg_get(MSG_PROCEDURES, msg); - show_proc(nullptr, nullptr, false, true, msg); + show_proc(std::nullopt, false, true, msg); IUTILS_msg_get(MSG_PACKAGES, msg); - show_packages(nullptr, true, msg); + show_packages(std::nullopt, true, msg); IUTILS_msg_get(MSG_COLLATIONS, msg); - show_collations("", 1, msg, true); + show_collations(std::nullopt, 1, msg, true); IUTILS_msg_get(MSG_ROLES, msg); - show_role(nullptr, true, msg); + show_role(std::nullopt, true, msg); IUTILS_msg_get(MSG_PUBLICATIONS, msg); - show_publications(nullptr, true, msg); + show_publications(std::nullopt, true, msg); } return SKIP; @@ -2688,7 +2314,7 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) if (node.name) { - ret = show_table(node.name->c_str(), false); + ret = show_table(node.name.value(), false); if (ret == OBJECT_NOT_FOUND) { @@ -2708,7 +2334,7 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) [&](const FrontendParser::ShowTriggersNode& node) { - const auto ret = show_trigger((node.name ? node.name->c_str() : ""), true, true); + const auto ret = show_trigger(node.name, true, true); if (ret == OBJECT_NOT_FOUND) { @@ -2757,7 +2383,7 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) if (node.name) { - ret = show_table(node.name->c_str(), true); + ret = show_table(node.name.value(), true); if (ret == OBJECT_NOT_FOUND) { @@ -2790,7 +2416,7 @@ processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node) if (ret == OBJECT_NOT_FOUND) { TEXT key_string[MSG_LENGTH]; - IUTILS_msg_get(key, key_string, SafeArg() << notFoundName.c_str()); + IUTILS_msg_get(key, key_string, SafeArg() << notFoundName.toQuotedString().c_str()); STDERROUT(key_string); } @@ -2855,16 +2481,19 @@ static processing_state show_all_tables(SSHORT sys_flag) // Views FOR REL IN RDB$RELATIONS WITH REL.RDB$VIEW_BLR NOT MISSING - SORTED BY REL.RDB$RELATION_NAME + SORTED BY REL.RDB$SCHEMA_NAME, REL.RDB$RELATION_NAME { first = false; - isqlGlob.printf("%s%s", fb_utils::exact_name(REL.RDB$RELATION_NAME), NEWLINE); + + const QualifiedMetaString relationName(REL.RDB$RELATION_NAME, REL.RDB$SCHEMA_NAME); + + isqlGlob.printf("%s%s", relationName.toQuotedString().c_str(), NEWLINE); } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR } else // 23-Apr-2004 (only tables) { @@ -2874,16 +2503,19 @@ static processing_state show_all_tables(SSHORT sys_flag) (REL.RDB$SYSTEM_FLAG EQ sys_flag /*OR (sys_flag == 0 AND REL.RDB$SYSTEM_FLAG MISSING)*/) AND REL.RDB$VIEW_BLR MISSING - SORTED BY REL.RDB$RELATION_NAME + SORTED BY REL.RDB$SCHEMA_NAME, REL.RDB$RELATION_NAME { first = false; - isqlGlob.printf("%s%s", fb_utils::exact_name(REL.RDB$RELATION_NAME), NEWLINE); + + const QualifiedMetaString relationName(REL.RDB$RELATION_NAME, REL.RDB$SCHEMA_NAME); + + isqlGlob.printf("%s%s", relationName.toQuotedString().c_str(), NEWLINE); } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR } if (!first) @@ -2917,29 +2549,37 @@ static void show_charsets(SSHORT char_set_id, SSHORT collation) COL.RDB$CHARACTER_SET_ID EQ CST.RDB$CHARACTER_SET_ID AND COL.RDB$COLLATION_ID EQ collation AND CST.RDB$CHARACTER_SET_ID EQ char_set_id - + { #ifdef DEV_BUILD found = true; #endif - fb_utils::exact_name(CST.RDB$CHARACTER_SET_NAME); - fb_utils::exact_name(COL.RDB$COLLATION_NAME); - fb_utils::exact_name(CST.RDB$DEFAULT_COLLATE_NAME); - if (strcmp(CST.RDB$DEFAULT_COLLATE_NAME, COL.RDB$COLLATION_NAME) == 0 && - strcmp(CST.RDB$CHARACTER_SET_NAME, COL.RDB$COLLATION_NAME) == 0) + const QualifiedMetaString charSetName(CST.RDB$CHARACTER_SET_NAME, CST.RDB$SCHEMA_NAME); + const QualifiedMetaString collationName(COL.RDB$COLLATION_NAME, COL.RDB$SCHEMA_NAME); + const QualifiedMetaString charSetDefaultCollationName( + CST.RDB$DEFAULT_COLLATE_NAME, CST.RDB$DEFAULT_COLLATE_SCHEMA_NAME); + + if (charSetDefaultCollationName == collationName && charSetName == collationName) { // Collation is default and match charset name - do not show it. - isqlGlob.printf(" CHARACTER SET %s", CST.RDB$CHARACTER_SET_NAME); + isqlGlob.printf( + " CHARACTER SET %s", + charSetName.toQuotedString().c_str()); } else { - isqlGlob.printf(" CHARACTER SET %s COLLATE %s", CST.RDB$CHARACTER_SET_NAME, COL.RDB$COLLATION_NAME); + isqlGlob.printf( + " CHARACTER SET %s COLLATE %s", + charSetName.toQuotedString().c_str(), + collationName.toQuotedString().c_str()); } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR + #ifdef DEV_BUILD if (!found) { @@ -2953,7 +2593,7 @@ static void show_charsets(SSHORT char_set_id, SSHORT collation) } -static processing_state show_check(const SCHAR* object) +static processing_state show_check(const std::optional& name) { /************************************** * @@ -2967,41 +2607,49 @@ static processing_state show_check(const SCHAR* object) **************************************/ bool first = true; - if (!*object) + if (!name) return ps_ERR; // Query gets the check clauses for triggers stored for check constraints FOR TRG IN RDB$TRIGGERS CROSS CHK IN RDB$CHECK_CONSTRAINTS WITH TRG.RDB$TRIGGER_TYPE EQ 1 AND + TRG.RDB$SCHEMA_NAME EQUIV CHK.RDB$SCHEMA_NAME AND TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME AND //CHK.RDB$TRIGGER_NAME STARTING WITH "CHECK" AND TRG.RDB$SYSTEM_FLAG EQ int(fb_sysflag_check_constraint) AND - TRG.RDB$RELATION_NAME EQ object - SORTED BY CHK.RDB$CONSTRAINT_NAME + TRG.RDB$RELATION_NAME EQ name->object.c_str() + SORTED BY CHK.RDB$SCHEMA_NAME, CHK.RDB$CONSTRAINT_NAME + { + const QualifiedMetaString constraintName(CHK.RDB$CONSTRAINT_NAME, CHK.RDB$SCHEMA_NAME); + + if (name->schema.hasData() && name->schema != constraintName.schema) + continue; // Use print_blob to print the blob first = false; - isqlGlob.printf("CONSTRAINT %s:%s ", - fb_utils::exact_name(CHK.RDB$CONSTRAINT_NAME), NEWLINE); + isqlGlob.printf("CONSTRAINT %s:%s ", constraintName.object.toQuotedString().c_str(), NEWLINE); if (!TRG.RDB$TRIGGER_SOURCE.NULL) SHOW_print_metadata_text_blob (isqlGlob.Out, &TRG.RDB$TRIGGER_SOURCE); isqlGlob.printf(NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR + if (first) return (OBJECT_NOT_FOUND); + return (SKIP); } -static processing_state show_collations(const SCHAR* object, SSHORT sys_flag, const char* msg, bool compact) +static processing_state show_collations(const std::optional& name, + SSHORT sys_flag, const char* msg, bool compact) { /************************************** * @@ -3017,16 +2665,17 @@ static processing_state show_collations(const SCHAR* object, SSHORT sys_flag, co // Show all collations or named collation FOR CL IN RDB$COLLATIONS CROSS - CS IN RDB$CHARACTER_SETS WITH - CS.RDB$CHARACTER_SET_ID EQ CL.RDB$CHARACTER_SET_ID - SORTED BY CL.RDB$COLLATION_NAME + CS IN RDB$CHARACTER_SETS + WITH CS.RDB$CHARACTER_SET_ID EQ CL.RDB$CHARACTER_SET_ID + SORTED BY CL.RDB$SCHEMA_NAME, CL.RDB$COLLATION_NAME + { + const QualifiedMetaString collationName(CL.RDB$COLLATION_NAME, CL.RDB$SCHEMA_NAME); - fb_utils::exact_name(CL.RDB$COLLATION_NAME); - - if ((!*object && + if ((!name && ((!CL.RDB$SYSTEM_FLAG.NULL && CL.RDB$SYSTEM_FLAG != 0 && sys_flag != 0) || (!(!CL.RDB$SYSTEM_FLAG.NULL && CL.RDB$SYSTEM_FLAG != 0) && sys_flag != 1))) || - strcmp(CL.RDB$COLLATION_NAME, object) == 0) + collationName == name || + (name->schema.isEmpty() && name->object == collationName.object)) { if (!found) { @@ -3037,13 +2686,13 @@ static processing_state show_collations(const SCHAR* object, SSHORT sys_flag, co } if (compact) - isqlGlob.printf("%s%s", CL.RDB$COLLATION_NAME, NEWLINE); + isqlGlob.printf("%s%s", collationName.toQuotedString().c_str(), NEWLINE); else { - isqlGlob.printf("%s", CL.RDB$COLLATION_NAME); + isqlGlob.printf("%s", collationName.toQuotedString().c_str()); - fb_utils::exact_name(CS.RDB$CHARACTER_SET_NAME); - isqlGlob.printf(", CHARACTER SET %s", CS.RDB$CHARACTER_SET_NAME); + const QualifiedMetaString charSetName(CS.RDB$CHARACTER_SET_NAME, CS.RDB$SCHEMA_NAME); + isqlGlob.printf(", CHARACTER SET %s", charSetName.toQuotedString().c_str()); if (!CL.RDB$BASE_COLLATION_NAME.NULL) { @@ -3076,11 +2725,12 @@ static processing_state show_collations(const SCHAR* object, SSHORT sys_flag, co isqlGlob.printf("%s", NEWLINE); } } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR if (!found) return (OBJECT_NOT_FOUND); @@ -3097,7 +2747,7 @@ static processing_state show_collations(const SCHAR* object, SSHORT sys_flag, co // Helper that displays in correct syntax the COMMENT ON command for each object. // It escapes identifiers with embedded double quotes and escapes the comment // itself if it contains single quotes when we are honoring script extraction. -static void show_comment(const char* objtype, char* packageName, char* name1, char* name2, +static void show_comment(const char* objtype, const QualifiedMetaString& name, const MetaString& name2, ISC_QUAD* blobfld, const commentMode showextract, const char* banner) { const bool escape_quotes = showextract == cmmExtract; @@ -3105,52 +2755,18 @@ static void show_comment(const char* objtype, char* packageName, char* name1, ch if (escape_quotes && banner) isqlGlob.prints(banner); - if (packageName) - fb_utils::exact_name(packageName); - if (name1) - fb_utils::exact_name(name1); - if (name2) - fb_utils::exact_name(name2); - - char packageNameBuffer[BUFFER_LENGTH256]; - char SQL_identifier2[BUFFER_LENGTH256]; - - if (escape_quotes && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - { - if (packageName) - { - IUTILS_copy_SQL_id (packageName, packageNameBuffer, DBL_QUOTE); - packageName = packageNameBuffer; - } - - if (name1) - { - IUTILS_copy_SQL_id (name1, SQL_identifier, DBL_QUOTE); - name1 = SQL_identifier; - } - - if (name2) - { - IUTILS_copy_SQL_id (name2, SQL_identifier2, DBL_QUOTE); - name2 = SQL_identifier2; - } - } - const char* quot = escape_quotes ? "'" : ""; isqlGlob.printf("COMMENT ON %-12s", objtype); - if (packageName || name1 || name2) + if (name.object.hasData() || name2.hasData()) isqlGlob.printf(" "); - if (packageName) - isqlGlob.printf("%s.", packageName); + if (name.object.hasData()) + isqlGlob.printf("%s", name.toQuotedString().c_str()); - if (name1) - isqlGlob.printf("%s", name1); - - if (name2) - isqlGlob.printf(".%s", name2); + if (name2.hasData()) + isqlGlob.printf(".%s", name2.toQuotedString().c_str()); isqlGlob.printf(" IS %s", quot); @@ -3188,9 +2804,10 @@ static processing_state show_comments(const commentMode showextract, const char* FOR FIRST 1 DT IN RDB$DATABASE WITH DT.RDB$DESCRIPTION NOT MISSING - - show_comment("DATABASE", NULL, NULL, NULL, &DT.RDB$DESCRIPTION, showextract, first ? banner : 0); + { + show_comment("DATABASE", {}, {}, &DT.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3198,14 +2815,17 @@ static processing_state show_comments(const commentMode showextract, const char* END_ERROR FOR DM IN RDB$FIELDS - WITH DM.RDB$FIELD_NAME NOT MATCHING "RDB$+" USING "+=[0-9][0-9]* *" - AND (DM.RDB$SYSTEM_FLAG EQ 0 OR DM.RDB$SYSTEM_FLAG MISSING) - AND DM.RDB$DESCRIPTION NOT MISSING - SORTED BY DM.RDB$FIELD_NAME + WITH DM.RDB$FIELD_NAME NOT MATCHING "RDB$+" USING "+=[0-9][0-9]* *" AND + (DM.RDB$SYSTEM_FLAG EQ 0 OR DM.RDB$SYSTEM_FLAG MISSING) AND + DM.RDB$DESCRIPTION NOT MISSING + SORTED BY DM.RDB$SCHEMA_NAME, DM.RDB$FIELD_NAME + { + const QualifiedMetaString name(DM.RDB$FIELD_NAME, DM.RDB$SCHEMA_NAME); - show_comment("DOMAIN", NULL, DM.RDB$FIELD_NAME, NULL, &DM.RDB$DESCRIPTION, + show_comment("DOMAIN", name, {}, &DM.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3213,31 +2833,35 @@ static processing_state show_comments(const commentMode showextract, const char* END_ERROR FOR RL IN RDB$RELATIONS - WITH RL.RDB$VIEW_BLR MISSING - AND (RL.RDB$SYSTEM_FLAG EQ 0 OR RL.RDB$SYSTEM_FLAG MISSING) - SORTED BY RL.RDB$RELATION_NAME + WITH RL.RDB$VIEW_BLR MISSING AND + (RL.RDB$SYSTEM_FLAG EQ 0 OR RL.RDB$SYSTEM_FLAG MISSING) + SORTED BY RL.RDB$SCHEMA_NAME, RL.RDB$RELATION_NAME + { + const QualifiedMetaString name(RL.RDB$RELATION_NAME, RL.RDB$SCHEMA_NAME); if (!RL.RDB$DESCRIPTION.NULL && !UserBlob::blobIsNull(RL.RDB$DESCRIPTION)) { - show_comment("TABLE", NULL, RL.RDB$RELATION_NAME, NULL, &RL.RDB$DESCRIPTION, + show_comment("TABLE", name, {}, &RL.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; } FOR RF IN RDB$RELATION_FIELDS - WITH RF.RDB$RELATION_NAME = RL.RDB$RELATION_NAME - AND RF.RDB$DESCRIPTION NOT MISSING + WITH RF.RDB$SCHEMA_NAME EQUIV NULLIF(name.schema.c_str(), '') AND + RF.RDB$RELATION_NAME = RL.RDB$RELATION_NAME AND + RF.RDB$DESCRIPTION NOT MISSING SORTED BY RF.RDB$FIELD_POSITION - - show_comment(" COLUMN", NULL, RL.RDB$RELATION_NAME, RF.RDB$FIELD_NAME, + { + show_comment(" COLUMN", name, RF.RDB$FIELD_NAME, &RF.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; END_ERROR - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3245,31 +2869,35 @@ static processing_state show_comments(const commentMode showextract, const char* END_ERROR FOR VW IN RDB$RELATIONS - WITH VW.RDB$VIEW_BLR NOT MISSING - AND (VW.RDB$SYSTEM_FLAG EQ 0 OR VW.RDB$SYSTEM_FLAG MISSING) - SORTED BY VW.RDB$RELATION_NAME + WITH VW.RDB$VIEW_BLR NOT MISSING AND + (VW.RDB$SYSTEM_FLAG EQ 0 OR VW.RDB$SYSTEM_FLAG MISSING) + SORTED BY VW.RDB$SCHEMA_NAME, VW.RDB$RELATION_NAME + { + const QualifiedMetaString name(VW.RDB$RELATION_NAME, VW.RDB$SCHEMA_NAME); if (!VW.RDB$DESCRIPTION.NULL && !UserBlob::blobIsNull(VW.RDB$DESCRIPTION)) { - show_comment("VIEW", NULL, VW.RDB$RELATION_NAME, NULL, &VW.RDB$DESCRIPTION, + show_comment("VIEW", name, {}, &VW.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; } FOR RF IN RDB$RELATION_FIELDS - WITH RF.RDB$RELATION_NAME = VW.RDB$RELATION_NAME - AND RF.RDB$DESCRIPTION NOT MISSING + WITH RF.RDB$SCHEMA_NAME EQUIV NULLIF(name.schema.c_str(), '') AND + RF.RDB$RELATION_NAME = VW.RDB$RELATION_NAME AND + RF.RDB$DESCRIPTION NOT MISSING SORTED BY RF.RDB$FIELD_POSITION - - show_comment(" COLUMN", NULL, VW.RDB$RELATION_NAME, RF.RDB$FIELD_NAME, + { + show_comment(" COLUMN", name, RF.RDB$FIELD_NAME, &RF.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; END_ERROR - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3278,31 +2906,33 @@ static processing_state show_comments(const commentMode showextract, const char* FOR PR IN RDB$PROCEDURES WITH (PR.RDB$SYSTEM_FLAG EQ 0 OR PR.RDB$SYSTEM_FLAG MISSING) - SORTED BY PR.RDB$PROCEDURE_NAME + SORTED BY PR.RDB$SCHEMA_NAME, PR.RDB$PROCEDURE_NAME + { + const QualifiedMetaString name(PR.RDB$PROCEDURE_NAME, PR.RDB$SCHEMA_NAME, PR.RDB$PACKAGE_NAME); if (!PR.RDB$DESCRIPTION.NULL && !UserBlob::blobIsNull(PR.RDB$DESCRIPTION)) { - show_comment("PROCEDURE", (PR.RDB$PACKAGE_NAME.NULL ? NULL : PR.RDB$PACKAGE_NAME), - PR.RDB$PROCEDURE_NAME, NULL, &PR.RDB$DESCRIPTION, showextract, first ? banner : 0); + show_comment("PROCEDURE", name, {}, &PR.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; } FOR PA IN RDB$PROCEDURE_PARAMETERS - WITH PA.RDB$PROCEDURE_NAME = PR.RDB$PROCEDURE_NAME - AND PA.RDB$PACKAGE_NAME EQUIV NULLIF(PR.RDB$PACKAGE_NAME, '') - AND PA.RDB$DESCRIPTION NOT MISSING + WITH PA.RDB$SCHEMA_NAME EQUIV NULLIF(name.schema.c_str(), '') AND + PA.RDB$PROCEDURE_NAME = PR.RDB$PROCEDURE_NAME AND + PA.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') AND + PA.RDB$DESCRIPTION NOT MISSING SORTED BY PA.RDB$PARAMETER_TYPE, PA.RDB$PARAMETER_NUMBER - - show_comment(" PROCEDURE PARAMETER", - (PR.RDB$PACKAGE_NAME.NULL ? NULL : PR.RDB$PACKAGE_NAME), PR.RDB$PROCEDURE_NAME, + { + show_comment(" PROCEDURE PARAMETER", name, PA.RDB$PARAMETER_NAME, &PA.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; END_ERROR - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3310,13 +2940,16 @@ static processing_state show_comments(const commentMode showextract, const char* END_ERROR FOR TR IN RDB$TRIGGERS - WITH TR.RDB$DESCRIPTION NOT MISSING - AND (TR.RDB$SYSTEM_FLAG EQ 0 OR TR.RDB$SYSTEM_FLAG MISSING) - SORTED BY TR.RDB$TRIGGER_NAME + WITH TR.RDB$DESCRIPTION NOT MISSING AND + (TR.RDB$SYSTEM_FLAG EQ 0 OR TR.RDB$SYSTEM_FLAG MISSING) + SORTED BY TR.RDB$SCHEMA_NAME, TR.RDB$TRIGGER_NAME + { + const QualifiedMetaString name(TR.RDB$TRIGGER_NAME, TR.RDB$SCHEMA_NAME); - show_comment("TRIGGER", NULL, TR.RDB$TRIGGER_NAME, NULL, &TR.RDB$DESCRIPTION, + show_comment("TRIGGER", name, {}, &TR.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3324,35 +2957,38 @@ static processing_state show_comments(const commentMode showextract, const char* END_ERROR FOR UD IN RDB$FUNCTIONS - WITH UD.RDB$DESCRIPTION NOT MISSING - AND (UD.RDB$SYSTEM_FLAG EQ 0 OR UD.RDB$SYSTEM_FLAG MISSING) - SORTED BY UD.RDB$FUNCTION_NAME - + WITH UD.RDB$DESCRIPTION NOT MISSING AND + (UD.RDB$SYSTEM_FLAG EQ 0 OR UD.RDB$SYSTEM_FLAG MISSING) + SORTED BY UD.RDB$SCHEMA_NAME, UD.RDB$FUNCTION_NAME + { // Avoid syntax error when extracting scripts due to an historical bug in gbak. // See CORE-1174. if (UserBlob::blobIsNull(UD.RDB$DESCRIPTION)) continue; - show_comment("FUNCTION", - (UD.RDB$PACKAGE_NAME.NULL ? NULL : UD.RDB$PACKAGE_NAME), UD.RDB$FUNCTION_NAME, NULL, + const QualifiedMetaString name(UD.RDB$FUNCTION_NAME, UD.RDB$SCHEMA_NAME, UD.RDB$PACKAGE_NAME); + + show_comment("FUNCTION", name, {}, &UD.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; FOR ARG IN RDB$FUNCTION_ARGUMENTS - WITH ARG.RDB$FUNCTION_NAME = UD.RDB$FUNCTION_NAME - AND ARG.RDB$PACKAGE_NAME EQUIV NULLIF(UD.RDB$PACKAGE_NAME, '') - AND ARG.RDB$DESCRIPTION NOT MISSING + WITH ARG.RDB$SCHEMA_NAME EQUIV NULLIF(name.schema.c_str(), '') AND + ARG.RDB$FUNCTION_NAME = UD.RDB$FUNCTION_NAME AND + ARG.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') AND + ARG.RDB$DESCRIPTION NOT MISSING SORTED BY ARG.RDB$ARGUMENT_POSITION - - show_comment(" FUNCTION PARAMETER", - (ARG.RDB$PACKAGE_NAME.NULL ? NULL : ARG.RDB$PACKAGE_NAME), ARG.RDB$FUNCTION_NAME, + { + show_comment(" FUNCTION PARAMETER", name, ARG.RDB$ARGUMENT_NAME, &ARG.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; END_ERROR + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3360,13 +2996,16 @@ static processing_state show_comments(const commentMode showextract, const char* END_ERROR FOR BF IN RDB$FILTERS - WITH BF.RDB$DESCRIPTION NOT MISSING - AND (BF.RDB$SYSTEM_FLAG EQ 0 OR BF.RDB$SYSTEM_FLAG MISSING) + WITH BF.RDB$DESCRIPTION NOT MISSING AND + (BF.RDB$SYSTEM_FLAG EQ 0 OR BF.RDB$SYSTEM_FLAG MISSING) SORTED BY BF.RDB$FUNCTION_NAME + { + const QualifiedMetaString name(BF.RDB$FUNCTION_NAME); - show_comment("FILTER", NULL, BF.RDB$FUNCTION_NAME, NULL, &BF.RDB$DESCRIPTION, + show_comment("FILTER", name, {}, &BF.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3374,13 +3013,16 @@ static processing_state show_comments(const commentMode showextract, const char* END_ERROR FOR XC IN RDB$EXCEPTIONS - WITH XC.RDB$DESCRIPTION NOT MISSING - AND (XC.RDB$SYSTEM_FLAG EQ 0 OR XC.RDB$SYSTEM_FLAG MISSING) - SORTED BY XC.RDB$EXCEPTION_NAME + WITH XC.RDB$DESCRIPTION NOT MISSING AND + (XC.RDB$SYSTEM_FLAG EQ 0 OR XC.RDB$SYSTEM_FLAG MISSING) + SORTED BY XC.RDB$SCHEMA_NAME, XC.RDB$EXCEPTION_NAME + { + const QualifiedMetaString name(XC.RDB$EXCEPTION_NAME, XC.RDB$SCHEMA_NAME); - show_comment("EXCEPTION", NULL, XC.RDB$EXCEPTION_NAME, NULL, &XC.RDB$DESCRIPTION, + show_comment("EXCEPTION", name, {}, &XC.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3390,13 +3032,16 @@ static processing_state show_comments(const commentMode showextract, const char* if (isqlGlob.major_ods >= ODS_VERSION11) { FOR GR IN RDB$GENERATORS - WITH GR.RDB$DESCRIPTION NOT MISSING - AND (GR.RDB$SYSTEM_FLAG EQ 0 OR GR.RDB$SYSTEM_FLAG MISSING) - SORTED BY GR.RDB$GENERATOR_NAME + WITH GR.RDB$DESCRIPTION NOT MISSING AND + (GR.RDB$SYSTEM_FLAG EQ 0 OR GR.RDB$SYSTEM_FLAG MISSING) + SORTED BY GR.RDB$SCHEMA_NAME, GR.RDB$GENERATOR_NAME + { + const QualifiedMetaString name(GR.RDB$GENERATOR_NAME, GR.RDB$SCHEMA_NAME); - show_comment("GENERATOR", NULL, GR.RDB$GENERATOR_NAME, NULL, &GR.RDB$DESCRIPTION, + show_comment("GENERATOR", name, {}, &GR.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3405,13 +3050,16 @@ static processing_state show_comments(const commentMode showextract, const char* } FOR IX IN RDB$INDICES - WITH IX.RDB$DESCRIPTION NOT MISSING - AND (IX.RDB$SYSTEM_FLAG EQ 0 OR IX.RDB$SYSTEM_FLAG MISSING) - SORTED BY IX.RDB$INDEX_NAME + WITH IX.RDB$DESCRIPTION NOT MISSING AND + (IX.RDB$SYSTEM_FLAG EQ 0 OR IX.RDB$SYSTEM_FLAG MISSING) + SORTED BY IX.RDB$SCHEMA_NAME, IX.RDB$INDEX_NAME + { + const QualifiedMetaString name(IX.RDB$INDEX_NAME, IX.RDB$SCHEMA_NAME); - show_comment("INDEX", NULL, IX.RDB$INDEX_NAME, NULL, &IX.RDB$DESCRIPTION, + show_comment("INDEX", name, {}, &IX.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3421,13 +3069,16 @@ static processing_state show_comments(const commentMode showextract, const char* if (isqlGlob.major_ods >= ODS_VERSION11) { FOR RO IN RDB$ROLES - WITH RO.RDB$DESCRIPTION NOT MISSING - AND (RO.RDB$SYSTEM_FLAG EQ 0 OR RO.RDB$SYSTEM_FLAG MISSING) + WITH RO.RDB$DESCRIPTION NOT MISSING AND + (RO.RDB$SYSTEM_FLAG EQ 0 OR RO.RDB$SYSTEM_FLAG MISSING) SORTED BY RO.RDB$ROLE_NAME + { + const QualifiedMetaString name(RO.RDB$ROLE_NAME); - show_comment("ROLE", NULL, RO.RDB$ROLE_NAME, NULL, &RO.RDB$DESCRIPTION, + show_comment("ROLE", name, {}, &RO.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3438,13 +3089,16 @@ static processing_state show_comments(const commentMode showextract, const char* if (isqlGlob.major_ods >= ODS_VERSION12) { FOR PACK IN RDB$PACKAGES - WITH PACK.RDB$DESCRIPTION NOT MISSING - AND (PACK.RDB$SYSTEM_FLAG EQ 0 OR PACK.RDB$SYSTEM_FLAG MISSING) - SORTED BY PACK.RDB$PACKAGE_NAME + WITH PACK.RDB$DESCRIPTION NOT MISSING AND + (PACK.RDB$SYSTEM_FLAG EQ 0 OR PACK.RDB$SYSTEM_FLAG MISSING) + SORTED BY PACK.RDB$SCHEMA_NAME, PACK.RDB$PACKAGE_NAME + { + const QualifiedMetaString name(PACK.RDB$PACKAGE_NAME, PACK.RDB$SCHEMA_NAME); - show_comment("PACKAGE", NULL, PACK.RDB$PACKAGE_NAME, NULL, &PACK.RDB$DESCRIPTION, + show_comment("PACKAGE", name, {}, &PACK.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3453,13 +3107,16 @@ static processing_state show_comments(const commentMode showextract, const char* } FOR CH IN RDB$CHARACTER_SETS - WITH CH.RDB$DESCRIPTION NOT MISSING - AND (CH.RDB$SYSTEM_FLAG EQ 0 OR CH.RDB$SYSTEM_FLAG MISSING) - SORTED BY CH.RDB$CHARACTER_SET_NAME + WITH CH.RDB$DESCRIPTION NOT MISSING AND + (CH.RDB$SYSTEM_FLAG EQ 0 OR CH.RDB$SYSTEM_FLAG MISSING) + SORTED BY CH.RDB$SCHEMA_NAME, CH.RDB$CHARACTER_SET_NAME + { + const QualifiedMetaString name(CH.RDB$CHARACTER_SET_NAME, CH.RDB$SCHEMA_NAME); - show_comment("CHARACTER SET", NULL, CH.RDB$CHARACTER_SET_NAME, NULL, + show_comment("CHARACTER SET", name, {}, &CH.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3467,13 +3124,16 @@ static processing_state show_comments(const commentMode showextract, const char* END_ERROR FOR CL IN RDB$COLLATIONS - WITH CL.RDB$DESCRIPTION NOT MISSING - AND (CL.RDB$SYSTEM_FLAG EQ 0 OR CL.RDB$SYSTEM_FLAG MISSING) - SORTED BY CL.RDB$COLLATION_NAME + WITH CL.RDB$DESCRIPTION NOT MISSING AND + (CL.RDB$SYSTEM_FLAG EQ 0 OR CL.RDB$SYSTEM_FLAG MISSING) + SORTED BY CL.RDB$SCHEMA_NAME, CL.RDB$COLLATION_NAME + { + const QualifiedMetaString name(CL.RDB$COLLATION_NAME, CL.RDB$SCHEMA_NAME); - show_comment("COLLATION", NULL, CL.RDB$COLLATION_NAME, NULL, &CL.RDB$DESCRIPTION, + show_comment("COLLATION", name, {}, &CL.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3482,28 +3142,17 @@ static processing_state show_comments(const commentMode showextract, const char* if (isqlGlob.major_ods >= ODS_VERSION12) { - FOR PACK IN RDB$PACKAGES - WITH PACK.RDB$DESCRIPTION NOT MISSING - AND (PACK.RDB$SYSTEM_FLAG EQ 0 OR PACK.RDB$SYSTEM_FLAG MISSING) - SORTED BY PACK.RDB$PACKAGE_NAME - - show_comment("PACKAGE", NULL, PACK.RDB$PACKAGE_NAME, NULL, &PACK.RDB$DESCRIPTION, - showextract, first ? banner : 0); - first = false; - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return ps_ERR; - END_ERROR - FOR M IN RDB$AUTH_MAPPING - WITH M.RDB$DESCRIPTION NOT MISSING - AND (M.RDB$SYSTEM_FLAG EQ 0 OR M.RDB$SYSTEM_FLAG MISSING) + WITH M.RDB$DESCRIPTION NOT MISSING AND + (M.RDB$SYSTEM_FLAG EQ 0 OR M.RDB$SYSTEM_FLAG MISSING) SORTED BY M.RDB$MAP_NAME + { + const QualifiedMetaString name(M.RDB$MAP_NAME); - show_comment("MAPPING", NULL, M.RDB$MAP_NAME, NULL, &M.RDB$DESCRIPTION, + show_comment("MAPPING", name, {}, &M.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -3513,16 +3162,40 @@ static processing_state show_comments(const commentMode showextract, const char* FOR M IN SEC$GLOBAL_AUTH_MAPPING WITH M.SEC$DESCRIPTION NOT MISSING SORTED BY M.SEC$MAP_NAME + { + const QualifiedMetaString name(M.SEC$MAP_NAME); - show_comment("GLOBAL MAPPING", NULL, M.SEC$MAP_NAME, NULL, &M.SEC$DESCRIPTION, + show_comment("GLOBAL MAPPING", name, {}, &M.SEC$DESCRIPTION, showextract, first ? banner : 0); first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; END_ERROR } + + if (isqlGlob.major_ods >= ODS_VERSION14) + { + FOR SCH IN RDB$SCHEMAS + WITH SCH.RDB$DESCRIPTION NOT MISSING AND + (SCH.RDB$SYSTEM_FLAG EQ 0 OR SCH.RDB$SYSTEM_FLAG MISSING) + SORTED BY SCH.RDB$SCHEMA_NAME + { + const QualifiedMetaString name(SCH.RDB$SCHEMA_NAME); + + show_comment("SCHEMA", name, {}, &SCH.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; } @@ -3543,24 +3216,26 @@ static void show_db() // First print the name of the database isqlGlob.printf("Database: %s%s", isqlGlob.global_Db_name, NEWLINE); - // Get the owner name - FOR REL IN RDB$RELATIONS WITH - REL.RDB$RELATION_NAME = "RDB$DATABASE" - if (!REL.RDB$OWNER_NAME.NULL) { - isqlGlob.printf("%sOwner: %s%s", TAB_AS_SPACES, REL.RDB$OWNER_NAME, NEWLINE); - } + // Get the owner name + FOR REL IN RDB$RELATIONS + WITH (REL.RDB$SCHEMA_NAME = SYSTEM_SCHEMA OR REL.RDB$SCHEMA_NAME MISSING) AND + REL.RDB$RELATION_NAME = "RDB$DATABASE" AND + REL.RDB$OWNER_NAME NOT MISSING + { + isqlGlob.printf("%sOwner: %s%s", TAB_AS_SPACES, REL.RDB$OWNER_NAME, NEWLINE); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR // Query for files FOR FIL IN RDB$FILES SORTED BY FIL.RDB$SHADOW_NUMBER, FIL.RDB$FILE_SEQUENCE - + { // reset nulls to zero if (FIL.RDB$FILE_FLAGS.NULL) @@ -3615,12 +3290,12 @@ static void show_db() isqlGlob.printf("Explicit physical backup difference file: \"%s\"%s", FIL.RDB$FILE_NAME, NEWLINE); } - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR // First general database parameters @@ -3630,29 +3305,28 @@ static void show_db() FOR DBB IN RDB$DATABASE CROSS CS IN RDB$CHARACTER_SETS - WITH CS.RDB$CHARACTER_SET_NAME EQ DBB.RDB$CHARACTER_SET_NAME + WITH CS.RDB$SCHEMA_NAME EQUIV DBB.RDB$CHARACTER_SET_SCHEMA_NAME AND + CS.RDB$CHARACTER_SET_NAME EQ DBB.RDB$CHARACTER_SET_NAME + { + const QualifiedMetaString charSetName(CS.RDB$CHARACTER_SET_NAME, CS.RDB$SCHEMA_NAME); + const QualifiedMetaString collationName(CS.RDB$DEFAULT_COLLATE_NAME, CS.RDB$DEFAULT_COLLATE_SCHEMA_NAME); - fb_utils::exact_name(DBB.RDB$CHARACTER_SET_NAME); - fb_utils::exact_name(CS.RDB$DEFAULT_COLLATE_NAME); + isqlGlob.printf("Default Character set: %s", charSetName.toQuotedString().c_str()); - isqlGlob.printf("Default Character set: %s", DBB.RDB$CHARACTER_SET_NAME); - - if (!CS.RDB$DEFAULT_COLLATE_NAME.NULL && - strcmp(CS.RDB$DEFAULT_COLLATE_NAME, DBB.RDB$CHARACTER_SET_NAME) != 0) - { - isqlGlob.printf(" (with Default Collation %s)", CS.RDB$DEFAULT_COLLATE_NAME); - } + if (!CS.RDB$DEFAULT_COLLATE_NAME.NULL && charSetName != collationName) + isqlGlob.printf(" (with Default Collation %s)", collationName.toQuotedString().c_str()); isqlGlob.printf("%s", NEWLINE); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR int pass = 0; FOR DBB2 IN RDB$DATABASE - + { if (!DBB2.RDB$LINGER.NULL && DBB2.RDB$LINGER > 0) isqlGlob.printf("Linger: %d seconds%s", DBB2.RDB$LINGER, NEWLINE); @@ -3661,12 +3335,12 @@ static void show_db() if (++pass > 1) isqlGlob.printf("RDB$DATABASE has more than one record%s", NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR if (isqlGlob.major_ods >= ODS_VERSION13) { @@ -3674,15 +3348,15 @@ static void show_db() FOR PUB IN RDB$PUBLICATIONS WITH PUB.RDB$ACTIVE_FLAG > 0 - + { published = true; break; - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR isqlGlob.printf("Publication: %s%s", published ? "Enabled" : "Disabled", NEWLINE); } @@ -3695,16 +3369,16 @@ static void show_db() // Iterate through all types of objects types (as per jrd/obj.h) calling the // overloaded routine. We try to fetch all possible object types that share // the same name. -static processing_state show_dependencies(const char* object) +static processing_state show_dependencies(const std::optional& name) { - if (!object || !object[0]) + if (!name) return ps_ERR; bool missing = true; for (FB_SIZE_T i = 0; i < FB_NELEM(Object_types); ++i) { - if (show_dependencies(object, i) == SKIP) + if (show_dependencies(name.value(), i) == SKIP) { missing = false; isqlGlob.printf("+++%s", NEWLINE); @@ -3723,52 +3397,76 @@ static processing_state show_dependencies(const char* object) // - objects this object depends on // - if it's table or view, list fields that depend on other objects // - if it's procedure, list parameters that depend on other objects (unlikely for now) -static processing_state show_dependencies(const char* object, int obj_type) +static processing_state show_dependencies(const QualifiedMetaString& name, int obj_type) { - bool missing1 = true; + Array dependsOn; FOR DEP1 IN RDB$DEPENDENCIES - WITH DEP1.RDB$DEPENDED_ON_NAME EQ object AND + WITH DEP1.RDB$DEPENDED_ON_NAME EQ name.object.c_str() AND DEP1.RDB$DEPENDED_ON_TYPE EQ obj_type - if (missing1) - missing1 = false; - else + SORTED BY DEP1.RDB$DEPENDED_ON_SCHEMA_NAME + { + const QualifiedMetaString dependedOnName(DEP1.RDB$DEPENDED_ON_NAME, DEP1.RDB$DEPENDED_ON_SCHEMA_NAME); + + if (name.schema.hasData() && name.schema != dependedOnName.schema) + continue; + + const QualifiedMetaString dependentName(DEP1.RDB$DEPENDENT_NAME, DEP1.RDB$DEPENDENT_SCHEMA_NAME); + + if (dependsOn.hasData()) isqlGlob.prints(", "); - fb_utils::exact_name(DEP1.RDB$DEPENDENT_NAME); + dependsOn.add(dependedOnName); + const char* type_name = Object_types[DEP1.RDB$DEPENDENT_TYPE]; if (DEP1.RDB$FIELD_NAME.NULL) - isqlGlob.printf("%s:%s", DEP1.RDB$DEPENDENT_NAME, type_name); + isqlGlob.printf("%s:%s", dependentName.toQuotedString().c_str(), type_name); else { - fb_utils::exact_name(DEP1.RDB$FIELD_NAME); - isqlGlob.printf("%s:%s->%s", DEP1.RDB$DEPENDENT_NAME, type_name, DEP1.RDB$FIELD_NAME); + isqlGlob.printf( + "%s:%s->%s", + dependentName.toQuotedString().c_str(), + type_name, + MetaString(DEP1.RDB$FIELD_NAME).toQuotedString().c_str()); } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR bool target_done = false; - if (!missing1) + if (dependsOn.hasData()) { - const char* type_name = Object_types[obj_type]; - isqlGlob.printf("%s%s[%s:%s]", NEWLINE, TAB_AS_SPACES, object, type_name); - target_done = true; + for (const auto& dependsOnName : dependsOn) + { + const char* type_name = Object_types[obj_type]; + isqlGlob.printf("%s%s[%s:%s]", NEWLINE, TAB_AS_SPACES, dependsOnName.toQuotedString().c_str(), type_name); + target_done = true; + } } bool missing2 = true; FOR DEP2 IN RDB$DEPENDENCIES - WITH DEP2.RDB$DEPENDENT_NAME EQ object AND + WITH DEP2.RDB$DEPENDENT_NAME EQ name.object.c_str() AND DEP2.RDB$DEPENDENT_TYPE EQ obj_type + SORTED BY DEP2.RDB$DEPENDENT_SCHEMA_NAME + { + const QualifiedMetaString dependentName(DEP2.RDB$DEPENDENT_NAME, DEP2.RDB$DEPENDENT_SCHEMA_NAME); + + if (name.schema.hasData() && name.schema != dependentName.schema) + continue; + + const QualifiedMetaString dependedOnName(DEP2.RDB$DEPENDED_ON_NAME, DEP2.RDB$DEPENDED_ON_SCHEMA_NAME); + if (missing2) { if (!target_done) { const char* type_name = Object_types[obj_type]; - isqlGlob.printf("%s[%s:%s]", TAB_AS_SPACES, object, type_name); + isqlGlob.printf("%s[%s:%s]", TAB_AS_SPACES, dependentName.toQuotedString().c_str(), type_name); target_done = true; } @@ -3778,55 +3476,62 @@ static processing_state show_dependencies(const char* object, int obj_type) else isqlGlob.prints(", "); - fb_utils::exact_name(DEP2.RDB$DEPENDED_ON_NAME); const char* type_name = Object_types[DEP2.RDB$DEPENDED_ON_TYPE]; if (DEP2.RDB$FIELD_NAME.NULL) - isqlGlob.printf("%s:%s", DEP2.RDB$DEPENDED_ON_NAME, type_name); + isqlGlob.printf("%s:%s", dependedOnName.toQuotedString().c_str(), type_name); else { - fb_utils::exact_name(DEP2.RDB$FIELD_NAME); - isqlGlob.printf("%s:%s<-%s", DEP2.RDB$DEPENDED_ON_NAME, type_name, DEP2.RDB$FIELD_NAME); + isqlGlob.printf( + "%s:%s<-%s", + dependedOnName.toQuotedString().c_str(), + type_name, + MetaString(DEP2.RDB$FIELD_NAME).toQuotedString().c_str()); } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; - - bool is_table = false; - - FOR REL IN RDB$RELATIONS - WITH REL.RDB$RELATION_NAME = object AND - REL.RDB$VIEW_BLR MISSING AND - (REL.RDB$DBKEY_LENGTH MISSING OR REL.RDB$DBKEY_LENGTH = 8) - is_table = true; - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return ps_ERR; - END_ERROR; + END_ERROR bool missing3 = true; - if ((obj_type == obj_relation && is_table) || (obj_type == obj_view && !is_table)) + if (obj_type == obj_relation || obj_type == obj_view) { FOR RFR IN RDB$RELATION_FIELDS + CROSS REL IN RDB$RELATIONS CROSS FLD IN RDB$FIELDS CROSS DEP3 IN RDB$DEPENDENCIES - WITH RFR.RDB$RELATION_NAME = object AND + WITH RFR.RDB$RELATION_NAME = name.object.c_str() AND + RFR.RDB$FIELD_SOURCE_SCHEMA_NAME EQUIV FLD.RDB$SCHEMA_NAME AND + REL.RDB$SCHEMA_NAME EQUIV RFR.RDB$SCHEMA_NAME AND + REL.RDB$RELATION_NAME = RFR.RDB$RELATION_NAME AND RFR.RDB$FIELD_SOURCE = FLD.RDB$FIELD_NAME AND + DEP3.RDB$DEPENDENT_SCHEMA_NAME EQUIV RFR.RDB$FIELD_SOURCE_SCHEMA_NAME AND DEP3.RDB$DEPENDENT_NAME = RFR.RDB$FIELD_SOURCE AND DEP3.RDB$DEPENDENT_TYPE EQ obj_computed SORTED BY RFR.RDB$FIELD_POSITION + { + const QualifiedMetaString relationName(RFR.RDB$RELATION_NAME, RFR.RDB$SCHEMA_NAME); - if (FLD.RDB$COMPUTED_BLR.NULL) // redundant + if (name.schema.hasData() && name.schema != relationName.schema) continue; + const bool isTable = REL.RDB$VIEW_BLR.NULL && (REL.RDB$DBKEY_LENGTH.NULL || REL.RDB$DBKEY_LENGTH == 8); + + if ((obj_type == obj_relation && !isTable) || (obj_type == obj_view && isTable) || + FLD.RDB$COMPUTED_BLR.NULL) // redundant + { + continue; + } + + const QualifiedMetaString dependedOnName(DEP3.RDB$DEPENDED_ON_NAME, DEP3.RDB$DEPENDED_ON_SCHEMA_NAME); + if (missing3) { if (!target_done) { const char* type_name = Object_types[obj_type]; - isqlGlob.printf("%s[%s:%s]", TAB_AS_SPACES, object, type_name); + isqlGlob.printf("%s[%s:%s]", TAB_AS_SPACES, relationName.toQuotedString().c_str(), type_name); target_done = true; } @@ -3836,17 +3541,21 @@ static processing_state show_dependencies(const char* object, int obj_type) else isqlGlob.prints(", "); - fb_utils::exact_name(RFR.RDB$FIELD_NAME); - fb_utils::exact_name(FLD.RDB$FIELD_NAME); - fb_utils::exact_name(DEP3.RDB$DEPENDED_ON_NAME); const char* type_name = Object_types[DEP3.RDB$DEPENDED_ON_TYPE]; - isqlGlob.printf("Field-%s(%s):%s->%s:%s", RFR.RDB$FIELD_NAME, FLD.RDB$FIELD_NAME, - Object_types[obj_computed], DEP3.RDB$DEPENDED_ON_NAME, type_name); + + isqlGlob.printf( + "Field-%s(%s):%s->%s:%s", + MetaString(RFR.RDB$FIELD_NAME).toQuotedString().c_str(), + MetaString(FLD.RDB$FIELD_NAME).toQuotedString().c_str(), + Object_types[obj_computed], + dependedOnName.toQuotedString().c_str(), + type_name); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR } else if (obj_type == obj_procedure) { @@ -3854,20 +3563,30 @@ static processing_state show_dependencies(const char* object, int obj_type) FOR PAR IN RDB$PROCEDURE_PARAMETERS CROSS FLD IN RDB$FIELDS CROSS DEP3 IN RDB$DEPENDENCIES - WITH PAR.RDB$PROCEDURE_NAME = object AND + WITH PAR.RDB$PROCEDURE_NAME = name.object.c_str() AND + PAR.RDB$FIELD_SOURCE_SCHEMA_NAME EQUIV FLD.RDB$SCHEMA_NAME AND PAR.RDB$FIELD_SOURCE = FLD.RDB$FIELD_NAME AND + DEP3.RDB$DEPENDENT_SCHEMA_NAME EQUIV PAR.RDB$FIELD_SOURCE_SCHEMA_NAME AND DEP3.RDB$DEPENDENT_NAME = PAR.RDB$FIELD_SOURCE AND DEP3.RDB$DEPENDENT_TYPE EQ obj_computed SORTED BY PAR.RDB$PARAMETER_TYPE, PAR.RDB$PARAMETER_NUMBER + { + const QualifiedMetaString procedureName(PAR.RDB$PROCEDURE_NAME, PAR.RDB$SCHEMA_NAME); + + if (name.schema.hasData() && name.schema != procedureName.schema) + continue; + if (FLD.RDB$COMPUTED_BLR.NULL) // redundant continue; + const QualifiedMetaString dependedOnName(DEP3.RDB$DEPENDED_ON_NAME, DEP3.RDB$DEPENDED_ON_SCHEMA_NAME); + if (missing3) { if (!target_done) { const char* type_name = Object_types[obj_type]; - isqlGlob.printf("%s[%s:%s]", TAB_AS_SPACES, object, type_name); + isqlGlob.printf("%s[%s:%s]", TAB_AS_SPACES, procedureName.toQuotedString().c_str(), type_name); target_done = true; } @@ -3877,21 +3596,24 @@ static processing_state show_dependencies(const char* object, int obj_type) else isqlGlob.prints(", "); - fb_utils::exact_name(PAR.RDB$PARAMETER_NAME); - fb_utils::exact_name(FLD.RDB$FIELD_NAME); - fb_utils::exact_name(DEP3.RDB$DEPENDED_ON_NAME); const char* type_name = Object_types[DEP3.RDB$DEPENDED_ON_TYPE]; - isqlGlob.printf("%s-%s(%s):%s->%s:%s", PAR.RDB$PARAMETER_TYPE ? "Output" : "Input", - PAR.RDB$PARAMETER_NAME, FLD.RDB$FIELD_NAME, - Object_types[obj_computed], DEP3.RDB$DEPENDED_ON_NAME, type_name); + + isqlGlob.printf( + "%s-%s(%s):%s->%s:%s", + (PAR.RDB$PARAMETER_TYPE ? "Output" : "Input"), + MetaString(PAR.RDB$PARAMETER_NAME).toQuotedString().c_str(), + MetaString(FLD.RDB$FIELD_NAME).toQuotedString().c_str(), + Object_types[obj_computed], + dependedOnName.toQuotedString().c_str(), + type_name); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR } - if (!target_done) return OBJECT_NOT_FOUND; @@ -3935,7 +3657,7 @@ static processing_state show_dialect() } -static processing_state show_domains(const SCHAR* domain_name) +static processing_state show_domains(const std::optional& name) { /************************************* * @@ -3948,21 +3670,26 @@ static processing_state show_domains(const SCHAR* domain_name) ************************************/ bool first = true; - if (!*domain_name) + if (!name) { // List all domain names in columns - FOR FLD IN RDB$FIELDS WITH - FLD.RDB$FIELD_NAME NOT MATCHING "RDB$+" USING "+=[0-9][0-9]* *" - AND FLD.RDB$SYSTEM_FLAG NE 1 - SORTED BY FLD.RDB$FIELD_NAME - + FOR FLD IN RDB$FIELDS + WITH FLD.RDB$FIELD_NAME NOT MATCHING "RDB$+" USING "+=[0-9][0-9]* *" AND + FLD.RDB$SYSTEM_FLAG NE 1 + SORTED BY FLD.RDB$SCHEMA_NAME, FLD.RDB$FIELD_NAME + { first = false; - isqlGlob.printf("%s%s", fb_utils::exact_name(FLD.RDB$FIELD_NAME), NEWLINE); + + const QualifiedMetaString fieldName(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME); + + isqlGlob.printf("%s%s", fieldName.toQuotedString().c_str(), NEWLINE); + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR + if (!first) isqlGlob.printf(NEWLINE); } @@ -3971,22 +3698,27 @@ static processing_state show_domains(const SCHAR* domain_name) // List named domain FOR FLD IN RDB$FIELDS WITH - FLD.RDB$FIELD_NAME EQ domain_name; + FLD.RDB$FIELD_NAME EQ name->object.c_str() + SORTED BY FLD.RDB$SCHEMA_NAME + { + const QualifiedMetaString fieldName(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME); + + if (name->schema.hasData() && name->schema != fieldName.schema) + continue; first = false; // Print the name of the domain - fb_utils::exact_name(FLD.RDB$FIELD_NAME); - isqlGlob.printf("%-31s ", FLD.RDB$FIELD_NAME); + isqlGlob.printf("%-31s ", fieldName.toQuotedString().c_str()); // Array dimensions if (!FLD.RDB$DIMENSIONS.NULL) { isqlGlob.printf("ARRAY OF "); - ISQL_array_dimensions (FLD.RDB$FIELD_NAME); + ISQL_array_dimensions(fieldName); isqlGlob.printf("%s ", NEWLINE); } - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, + if (!ISQL_printNumericType(fieldName, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) { return ps_ERR; @@ -3994,7 +3726,7 @@ static processing_state show_domains(const SCHAR* domain_name) // Length for CHARs if ((FLD.RDB$FIELD_TYPE == blr_text) || (FLD.RDB$FIELD_TYPE == blr_varying)) { - isqlGlob.printf("(%d)", ISQL_get_field_length(FLD.RDB$FIELD_NAME)); + isqlGlob.printf("(%d)", ISQL_get_field_length(fieldName)); } // Blob domains @@ -4035,7 +3767,7 @@ static processing_state show_domains(const SCHAR* domain_name) isqlGlob.printf(NEWLINE); ISC_QUAD default_source; - ISQL_get_default_source (NULL, FLD.RDB$FIELD_NAME, &default_source); + ISQL_get_domain_default_source(fieldName, &default_source); if (default_source.gds_quad_high) { isqlGlob.printf(" "); @@ -4049,20 +3781,22 @@ static processing_state show_domains(const SCHAR* domain_name) SHOW_print_metadata_text_blob (isqlGlob.Out, &FLD.RDB$VALIDATION_SOURCE); isqlGlob.printf(NEWLINE); } - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR } + if (first) return (OBJECT_NOT_FOUND); + return (SKIP); } -static processing_state show_exceptions(const SCHAR* object) +static processing_state show_exceptions(const std::optional& name) { /************************************** * @@ -4080,19 +3814,19 @@ static processing_state show_exceptions(const SCHAR* object) bool first = true; SCHAR type[20]; - //fb_utils::exact_name(object); It already comes trimmed. - FOR EXC IN RDB$EXCEPTIONS - SORTED BY EXC.RDB$EXCEPTION_NAME + SORTED BY EXC.RDB$SCHEMA_NAME, EXC.RDB$EXCEPTION_NAME { - fb_utils::exact_name(EXC.RDB$EXCEPTION_NAME); + const QualifiedMetaString exceptionName(EXC.RDB$EXCEPTION_NAME, EXC.RDB$SCHEMA_NAME); // List all objects if none specified, or just the named exception - if (!*object || !strcmp (EXC.RDB$EXCEPTION_NAME, object)) + if (!name || + name == exceptionName || + (name->schema.isEmpty() && name->object == exceptionName.object)) { first = false; - isqlGlob.printf("%s", EXC.RDB$EXCEPTION_NAME); + isqlGlob.printf("%s", exceptionName.toQuotedString().c_str()); if (!EXC.RDB$MESSAGE.NULL && strlen(EXC.RDB$MESSAGE)) isqlGlob.printf("; Msg: %s", EXC.RDB$MESSAGE); @@ -4101,6 +3835,7 @@ static processing_state show_exceptions(const SCHAR* object) bool first_dep = true; FOR DEP IN RDB$DEPENDENCIES WITH DEP.RDB$DEPENDED_ON_TYPE = obj_exception AND + DEP.RDB$DEPENDED_ON_SCHEMA_NAME EQUIV NULLIF(exceptionName.schema.c_str(), '') AND DEP.RDB$DEPENDED_ON_NAME EQ EXC.RDB$EXCEPTION_NAME SORTED BY DEP.RDB$DEPENDENT_TYPE, DEP.RDB$DEPENDENT_NAME { @@ -4112,7 +3847,7 @@ static processing_state show_exceptions(const SCHAR* object) else isqlGlob.printf(", "); - fb_utils::exact_name(DEP.RDB$DEPENDENT_NAME); + const QualifiedMetaString dependentName(DEP.RDB$DEPENDENT_NAME, DEP.RDB$DEPENDENT_SCHEMA_NAME); switch (DEP.RDB$DEPENDENT_TYPE) { @@ -4127,13 +3862,13 @@ static processing_state show_exceptions(const SCHAR* object) break; } - isqlGlob.printf("%s (%s)", DEP.RDB$DEPENDENT_NAME, type); + isqlGlob.printf("%s (%s)", dependentName.toQuotedString().c_str(), type); } END_FOR ON_ERROR ISQL_errmsg (fbStatus); return ps_ERR; - END_ERROR; + END_ERROR isqlGlob.printf(NEWLINE); } @@ -4142,14 +3877,16 @@ static processing_state show_exceptions(const SCHAR* object) ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR + if (first) return (OBJECT_NOT_FOUND); + return (SKIP); } -static processing_state show_filters(const SCHAR* object) +static processing_state show_filters(const std::optional& name) { /************************************** * @@ -4164,20 +3901,21 @@ static processing_state show_filters(const SCHAR* object) bool first = true; // Show all functions - if (!*object) + if (!name) { FOR FIL IN RDB$FILTERS SORTED BY FIL.RDB$FUNCTION_NAME { + const MetaString filterName(FIL.RDB$FUNCTION_NAME); first = false; - fb_utils::exact_name(FIL.RDB$FUNCTION_NAME); - isqlGlob.printf("%s%s", FIL.RDB$FUNCTION_NAME, NEWLINE); + isqlGlob.printf("%s%s", filterName.toQuotedString().c_str(), NEWLINE); } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR + if (!first) { isqlGlob.printf(NEWLINE); @@ -4189,36 +3927,44 @@ static processing_state show_filters(const SCHAR* object) // We have a filter name, so expand on it FOR FIL IN RDB$FILTERS WITH - FIL.RDB$FUNCTION_NAME EQ object + FIL.RDB$FUNCTION_NAME EQ name->c_str() + { + const MetaString filterName(FIL.RDB$FUNCTION_NAME); - first = false; + first = false; - fb_utils::exact_name(FIL.RDB$FUNCTION_NAME); - fb_utils::exact_name(FIL.RDB$MODULE_NAME); - fb_utils::exact_name(FIL.RDB$ENTRYPOINT); + fb_utils::exact_name(FIL.RDB$MODULE_NAME); + fb_utils::exact_name(FIL.RDB$ENTRYPOINT); + + isqlGlob.printf( + "BLOB Filter: %s %s%sInput subtype: %d Output subtype: %d%s", + filterName.toQuotedString().c_str(), + NEWLINE, + TAB_AS_SPACES, + FIL.RDB$INPUT_SUB_TYPE, + FIL.RDB$OUTPUT_SUB_TYPE, + NEWLINE); - isqlGlob.printf("BLOB Filter: %s %s%sInput subtype: %d Output subtype: %d%s", - FIL.RDB$FUNCTION_NAME, NEWLINE, - TAB_AS_SPACES, FIL.RDB$INPUT_SUB_TYPE, FIL.RDB$OUTPUT_SUB_TYPE, NEWLINE); isqlGlob.printf("%sFilter library is %s%s%sEntry point is %s%s%s", TAB_AS_SPACES, FIL.RDB$MODULE_NAME, NEWLINE, TAB_AS_SPACES, FIL.RDB$ENTRYPOINT, NEWLINE, NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR if (first) return (OBJECT_NOT_FOUND); + return (SKIP); } -static processing_state show_functions( - const char* funcname, const char* packname, bool quoted, bool system, const char* msg) +static processing_state show_functions(const std::optional& name, + bool quoted, bool system, const char* msg) { /************************************** * @@ -4234,7 +3980,7 @@ static processing_state show_functions( int systemFlag = system ? 1 : 0; // If no function name was given, just list the functions - if (!funcname || !strlen(funcname)) + if (!name) { bool first = true; @@ -4243,7 +3989,7 @@ static processing_state show_functions( FOR FUN IN RDB$FUNCTIONS WITH FUN.RDB$SYSTEM_FLAG EQ systemFlag - SORTED BY FUN.RDB$PACKAGE_NAME, FUN.RDB$FUNCTION_NAME + SORTED BY FUN.RDB$SCHEMA_NAME, FUN.RDB$PACKAGE_NAME, FUN.RDB$FUNCTION_NAME { if (first) { @@ -4252,10 +3998,10 @@ static processing_state show_functions( isqlGlob.printf("%s%s", msg, NEWLINE); } - MetaString package(FUN.RDB$PACKAGE_NAME); - MetaString function(FUN.RDB$FUNCTION_NAME); + const QualifiedMetaString functionName( + FUN.RDB$FUNCTION_NAME, FUN.RDB$SCHEMA_NAME, FUN.RDB$PACKAGE_NAME); - isqlGlob.printf("%s%s%s", package.c_str(), package.hasData() ? "." : "", function.c_str()); + isqlGlob.printf("%s", functionName.toQuotedString().c_str()); if (!(FUN.RDB$VALID_BLR.NULL || FUN.RDB$VALID_BLR)) isqlGlob.printf("; Invalid"); @@ -4263,12 +4009,16 @@ static processing_state show_functions( if (FUN.RDB$PACKAGE_NAME.NULL) { bool first_dep = true; - FOR DEP IN RDB$DEPENDENCIES WITH - FUN.RDB$FUNCTION_NAME EQ DEP.RDB$DEPENDENT_NAME - REDUCED TO DEP.RDB$DEPENDED_ON_TYPE, DEP.RDB$DEPENDED_ON_NAME - SORTED BY DEP.RDB$DEPENDED_ON_TYPE, DEP.RDB$DEPENDED_ON_NAME + + FOR DEP IN RDB$DEPENDENCIES + WITH DEP.RDB$DEPENDENT_SCHEMA_NAME EQUIV NULLIF(functionName.schema.c_str(), '') AND + DEP.RDB$DEPENDENT_NAME EQ FUN.RDB$FUNCTION_NAME + REDUCED TO DEP.RDB$DEPENDED_ON_SCHEMA_NAME, DEP.RDB$DEPENDED_ON_TYPE, DEP.RDB$DEPENDED_ON_NAME + SORTED BY DEP.RDB$DEPENDED_ON_SCHEMA_NAME, DEP.RDB$DEPENDED_ON_TYPE, DEP.RDB$DEPENDED_ON_NAME { - fb_utils::exact_name(DEP.RDB$DEPENDED_ON_NAME); + const QualifiedMetaString dependendOnName( + DEP.RDB$DEPENDED_ON_NAME, DEP.RDB$DEPENDED_ON_SCHEMA_NAME); + if (first_dep) { @@ -4278,7 +4028,7 @@ static processing_state show_functions( else isqlGlob.printf(", "); - isqlGlob.printf("%s (%s)", fb_utils::exact_name(DEP.RDB$DEPENDED_ON_NAME), + isqlGlob.printf("%s (%s)", dependendOnName.toQuotedString().c_str(), Object_types[DEP.RDB$DEPENDED_ON_TYPE]); } END_FOR @@ -4294,37 +4044,39 @@ static processing_state show_functions( ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR if (first) return OBJECT_NOT_FOUND; + return (SKIP); } processing_state return_state = OBJECT_NOT_FOUND; - const MetaString function(funcname); - const MetaString package(packname); - FOR FUN IN RDB$FUNCTIONS - WITH FUN.RDB$FUNCTION_NAME EQ funcname - AND FUN.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '') + WITH FUN.RDB$FUNCTION_NAME EQ name->object.c_str() AND + FUN.RDB$PACKAGE_NAME EQUIV NULLIF(name->package.c_str(), '') + SORTED BY FUN.RDB$SCHEMA_NAME, FUN.RDB$PACKAGE_NAME + { + const QualifiedMetaString functionName( + FUN.RDB$FUNCTION_NAME, FUN.RDB$SCHEMA_NAME, FUN.RDB$PACKAGE_NAME); + + if (name->schema.hasData() && name->schema != functionName.schema) + continue; if (!FUN.RDB$MODULE_NAME.NULL) - { - fb_assert(package.isEmpty()); - return_state = show_func_legacy(function); - } + return_state = show_func_legacy(functionName); else if (isqlGlob.major_ods >= ODS_VERSION12) - return_state = show_func(package, function); - + return_state = show_func(functionName); + } END_FOR return return_state; } -static processing_state show_func(const MetaString& package, const MetaString& function) +static processing_state show_func(const QualifiedMetaString& name) { /************************************** * @@ -4341,11 +4093,17 @@ static processing_state show_func(const MetaString& package, const MetaString& f bool first = true; FOR FUN IN RDB$FUNCTIONS - WITH FUN.RDB$FUNCTION_NAME EQ function.c_str() - AND FUN.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '') + WITH FUN.RDB$SCHEMA_NAME EQUIV NULLIF(name.schema.c_str(), '') AND + FUN.RDB$FUNCTION_NAME EQ name.object.c_str() AND + FUN.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') + { + const QualifiedMetaString functionName( + FUN.RDB$FUNCTION_NAME, FUN.RDB$SCHEMA_NAME, FUN.RDB$PACKAGE_NAME); first = false; + // FIXME: print functionName + if (!FUN.RDB$DETERMINISTIC_FLAG.NULL && FUN.RDB$DETERMINISTIC_FLAG) isqlGlob.printf("Deterministic function%s", NEWLINE); @@ -4379,20 +4137,22 @@ static processing_state show_func(const MetaString& package, const MetaString& f const SSHORT default_charset = ISQL_get_default_char_set_id(); FOR ARG IN RDB$FUNCTION_ARGUMENTS CROSS - FLD IN RDB$FIELDS WITH - FUN.RDB$FUNCTION_NAME EQ ARG.RDB$FUNCTION_NAME AND - ARG.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '') AND - ARG.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME + FLD IN RDB$FIELDS + WITH ARG.RDB$SCHEMA_NAME EQUIV NULLIF(name.schema.c_str(), '') AND + ARG.RDB$FUNCTION_NAME EQ name.object.c_str() AND + ARG.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') AND + ARG.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME SORTED BY ARG.RDB$ARGUMENT_POSITION - + { if (first_param) { isqlGlob.printf("Parameters:%s", NEWLINE); first_param = false; } - fb_utils::exact_name(ARG.RDB$ARGUMENT_NAME); - isqlGlob.printf("%-33s %s ", ARG.RDB$ARGUMENT_NAME, + isqlGlob.printf( + "%-33s %s ", + MetaString(ARG.RDB$ARGUMENT_NAME).toQuotedString().c_str(), (ARG.RDB$ARGUMENT_POSITION == FUN.RDB$RETURN_ARGUMENT ? "OUTPUT" : "INPUT")); prm_mech_t mechanism = prm_mech_normal; @@ -4408,22 +4168,11 @@ static processing_state show_func(const MetaString& package, const MetaString& f prm_default_source = ARG.RDB$DEFAULT_SOURCE; } - char relationName[BUFFER_LENGTH256] = ""; - char relationField[BUFFER_LENGTH256] = ""; + const QualifiedMetaString relationName(ARG.RDB$RELATION_NAME, ARG.RDB$RELATION_SCHEMA_NAME); + const MetaString relationField(ARG.RDB$FIELD_NAME); + const QualifiedMetaString domainName(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME); - if (!ARG.RDB$RELATION_NAME.NULL) - { - strcpy(relationName, ARG.RDB$RELATION_NAME); - fb_utils::exact_name(relationName); - } - - if (!ARG.RDB$FIELD_NAME.NULL) - { - strcpy(relationField, ARG.RDB$FIELD_NAME); - fb_utils::exact_name(relationField); - } - - const bool basedOnColumn = relationName[0] && relationField[0]; + const bool basedOnColumn = relationName.object.hasData() && relationField.hasData(); // Decide if this is a user-created domain if (!fb_utils::implicit_domain(FLD.RDB$FIELD_NAME) || FLD.RDB$SYSTEM_FLAG == 1 || basedOnColumn) @@ -4431,15 +4180,17 @@ static processing_state show_func(const MetaString& package, const MetaString& f isqlGlob.printf("(%s", (mechanism == prm_mech_type_of ? "TYPE OF " : "")); if (basedOnColumn) - isqlGlob.printf("COLUMN %s.%s) ", relationName, relationField); - else { - fb_utils::exact_name(FLD.RDB$FIELD_NAME); - isqlGlob.printf("%s) ", FLD.RDB$FIELD_NAME); + isqlGlob.printf( + "COLUMN %s.%s) ", + relationName.toQuotedString().c_str(), + relationField.c_str()); } + else + isqlGlob.printf("%s) ", domainName.toQuotedString().c_str()); } - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, + if (!ISQL_printNumericType(domainName, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) { return ps_ERR; @@ -4471,12 +4222,14 @@ static processing_state show_func(const MetaString& package, const MetaString& f if (prm_collation_null) { FOR RFL IN RDB$RELATION_FIELDS - WITH RFL.RDB$RELATION_NAME = ARG.RDB$RELATION_NAME AND - RFL.RDB$FIELD_NAME = ARG.RDB$FIELD_NAME - + WITH RFL.RDB$SCHEMA_NAME EQUIV NULLIF(relationName.schema.c_str(), '') AND + RFL.RDB$RELATION_NAME = relationName.object.c_str() AND + RFL.RDB$FIELD_NAME = ARG.RDB$FIELD_NAME + { prm_collation_null = RFL.RDB$COLLATION_ID.NULL; if (!prm_collation_null) collation = RFL.RDB$COLLATION_ID; + } END_FOR } @@ -4493,7 +4246,7 @@ static processing_state show_func(const MetaString& package, const MetaString& f isqlGlob.printf(" "); SHOW_print_metadata_text_blob(isqlGlob.Out, &prm_default_source); } - else if (fb_utils::implicit_domain(FLD.RDB$FIELD_NAME) && !FLD.RDB$DEFAULT_SOURCE.NULL) + else if (fb_utils::implicit_domain(domainName.object.c_str()) && !FLD.RDB$DEFAULT_SOURCE.NULL) { isqlGlob.printf(" "); SHOW_print_metadata_text_blob(isqlGlob.Out, &FLD.RDB$DEFAULT_SOURCE); @@ -4501,25 +4254,27 @@ static processing_state show_func(const MetaString& package, const MetaString& f } isqlGlob.printf(NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg (fbStatus); return ps_ERR; - END_ERROR; - + END_ERROR + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR + if (first) return (OBJECT_NOT_FOUND); + return (SKIP); } -static processing_state show_func_legacy(const MetaString& function) +static processing_state show_func_legacy(const QualifiedMetaString& name) { /************************************** * @@ -4534,20 +4289,24 @@ static processing_state show_func_legacy(const MetaString& function) bool first = true; FOR FUN IN RDB$FUNCTIONS CROSS - FNA IN RDB$FUNCTION_ARGUMENTS WITH - FUN.RDB$FUNCTION_NAME EQ FNA.RDB$FUNCTION_NAME AND - FNA.RDB$PACKAGE_NAME MISSING AND - FUN.RDB$FUNCTION_NAME EQ function.c_str() AND - FUN.RDB$PACKAGE_NAME MISSING AND - FUN.RDB$MODULE_NAME NOT MISSING + FNA IN RDB$FUNCTION_ARGUMENTS + WITH FNA.RDB$SCHEMA_NAME EQUIV FUN.RDB$SCHEMA_NAME AND + FNA.RDB$FUNCTION_NAME EQ FUN.RDB$FUNCTION_NAME AND + FNA.RDB$PACKAGE_NAME MISSING AND + FUN.RDB$SCHEMA_NAME EQUIV NULLIF(name.schema.c_str(), '') AND + FUN.RDB$FUNCTION_NAME EQ name.object.c_str() AND + FUN.RDB$PACKAGE_NAME MISSING AND + FUN.RDB$MODULE_NAME NOT MISSING SORTED BY FNA.RDB$ARGUMENT_POSITION + { + const QualifiedMetaString functionName(FUN.RDB$FUNCTION_NAME, FUN.RDB$SCHEMA_NAME); - fb_utils::exact_name(FUN.RDB$FUNCTION_NAME); fb_utils::exact_name(FUN.RDB$MODULE_NAME); fb_utils::exact_name(FUN.RDB$ENTRYPOINT); + if (first) { - isqlGlob.printf("%sExternal function %s:%s", NEWLINE, FUN.RDB$FUNCTION_NAME, NEWLINE); + isqlGlob.printf("%sExternal function %s:%s", NEWLINE, functionName.toQuotedString().c_str(), NEWLINE); isqlGlob.printf("Function library is %s%s", FUN.RDB$MODULE_NAME, NEWLINE); isqlGlob.printf("Entry point is %s%s", FUN.RDB$ENTRYPOINT, NEWLINE); } @@ -4610,42 +4369,48 @@ static processing_state show_func_legacy(const MetaString& function) } } + // Print length where appropriate if (FNA.RDB$FIELD_TYPE == blr_text || FNA.RDB$FIELD_TYPE == blr_varying || FNA.RDB$FIELD_TYPE == blr_cstring) { FOR V4FNA IN RDB$FUNCTION_ARGUMENTS CROSS CHARSET IN RDB$CHARACTER_SETS OVER RDB$CHARACTER_SET_ID - WITH V4FNA.RDB$FUNCTION_NAME EQ FNA.RDB$FUNCTION_NAME AND - V4FNA.RDB$PACKAGE_NAME MISSING AND - V4FNA.RDB$ARGUMENT_POSITION EQ FNA.RDB$ARGUMENT_POSITION - - fb_utils::exact_name(CHARSET.RDB$CHARACTER_SET_NAME); - isqlGlob.printf("(%d) CHARACTER SET %s", - (FNA.RDB$FIELD_LENGTH / MAX (1, CHARSET.RDB$BYTES_PER_CHARACTER)), - CHARSET.RDB$CHARACTER_SET_NAME); + WITH V4FNA.RDB$SCHEMA_NAME EQUIV NULLIF(name.schema.c_str(), '') AND + V4FNA.RDB$FUNCTION_NAME EQ name.object.c_str() AND + V4FNA.RDB$PACKAGE_NAME MISSING AND + V4FNA.RDB$ARGUMENT_POSITION EQ FNA.RDB$ARGUMENT_POSITION + { + const QualifiedMetaString charSetName(CHARSET.RDB$CHARACTER_SET_NAME, CHARSET.RDB$SCHEMA_NAME); + isqlGlob.printf( + "(%d) CHARACTER SET %s", + (FNA.RDB$FIELD_LENGTH / MAX (1, CHARSET.RDB$BYTES_PER_CHARACTER)), + charSetName.toQuotedString().c_str()); + } END_FOR ON_ERROR ISQL_errmsg (fbStatus); return ps_ERR; - END_ERROR; + END_ERROR } isqlGlob.printf(NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR + if (first) return (OBJECT_NOT_FOUND); + return (SKIP); } -static processing_state show_generators(const SCHAR* object) +static processing_state show_generators(const std::optional& name) { /************************************** * @@ -4660,8 +4425,6 @@ static processing_state show_generators(const SCHAR* object) * **************************************/ bool found = false; - const char genIdStr[] = "SELECT GEN_ID(%s, 0) FROM RDB$DATABASE"; - TEXT query[sizeof(genIdStr) + QUOTED_NAME_SIZE], gen_name[QUOTED_NAME_SIZE]; Firebird::RefPtr mb(Firebird::REF_NO_INCR, fbMaster->getMetadataBuilder(fbStatus, 1)); @@ -4689,26 +4452,23 @@ static processing_state show_generators(const SCHAR* object) // Show all generators or named generator FOR GEN IN RDB$GENERATORS - SORTED BY GEN.RDB$GENERATOR_NAME + SORTED BY GEN.RDB$SCHEMA_NAME, GEN.RDB$GENERATOR_NAME + { + const QualifiedMetaString genName(GEN.RDB$GENERATOR_NAME, GEN.RDB$SCHEMA_NAME); - fb_utils::exact_name(GEN.RDB$GENERATOR_NAME); - - if ((!*object && (GEN.RDB$SYSTEM_FLAG.NULL || GEN.RDB$SYSTEM_FLAG == 0)) || - !strcmp(GEN.RDB$GENERATOR_NAME, object)) + if ((!name && (GEN.RDB$SYSTEM_FLAG.NULL || GEN.RDB$SYSTEM_FLAG == 0)) || + name == genName || + (name->schema.isEmpty() && name->object == genName.object)) { // Get the current id for each generator - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { - IUTILS_copy_SQL_id (GEN.RDB$GENERATOR_NAME, gen_name, DBL_QUOTE); - } - else { - // If we are extracting in dialect 1, identifiers may cause failures. - strcpy(gen_name, GEN.RDB$GENERATOR_NAME); - } + string query; + query.printf( + "SELECT GEN_ID(%s, 0) FROM %sRDB$DATABASE", + IUTILS_name_to_string(genName).c_str(), + (isqlGlob.major_ods >= ODS_VERSION14 ? "SYSTEM." : "")); - fb_utils::snprintf(query, sizeof(query), genIdStr, gen_name); - - DB->execute(fbStatus, fbTrans, 0, query, isqlGlob.SQL_dialect, + DB->execute(fbStatus, fbTrans, 0, query.c_str(), isqlGlob.SQL_dialect, NULL, NULL, outMetadata, outBuffer); if (ISQL_errmsg (fbStatus)) continue; @@ -4717,38 +4477,43 @@ static processing_state show_generators(const SCHAR* object) ISC_INT64 val = use64 ? *((ISC_INT64*) &outBuffer[off]) : *((SLONG*) &outBuffer[off]); isqlGlob.printf("Generator %s, current value: %" SQUADFORMAT, - GEN.RDB$GENERATOR_NAME, val); + genName.toQuotedString().c_str(), val); + if (isqlGlob.major_ods >= ODS_VERSION12) { FOR G2 IN RDB$GENERATORS - WITH G2.RDB$GENERATOR_NAME = GEN.RDB$GENERATOR_NAME - + WITH G2.RDB$SCHEMA_NAME EQUIV NULLIF(genName.schema.c_str(), '') AND + G2.RDB$GENERATOR_NAME = genName.object.c_str() + { ISC_INT64 initval = !G2.RDB$INITIAL_VALUE.NULL ? G2.RDB$INITIAL_VALUE : 0; isqlGlob.printf(", initial value: %" SQUADFORMAT ", increment: %" SLONGFORMAT, initval, G2.RDB$GENERATOR_INCREMENT); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR } isqlGlob.prints(NEWLINE); } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR + if (!found) return (OBJECT_NOT_FOUND); + return SKIP; } -static void show_index(SCHAR* relation_name, - SCHAR* index_name, +static void show_index(const QualifiedMetaString& relationName, + const QualifiedMetaString& indexName, const SSHORT unique_flag, const SSHORT index_type, const SSHORT inactive) @@ -4766,27 +4531,20 @@ static void show_index(SCHAR* relation_name, * **************************************/ - // Strip trailing blanks - - fb_utils::exact_name(relation_name); - fb_utils::exact_name(index_name); - - isqlGlob.printf("%s%s%s INDEX ON %s", index_name, + isqlGlob.printf("%s%s%s INDEX ON %s", indexName.toQuotedString().c_str(), (unique_flag ? " UNIQUE" : ""), - (index_type == 1 ? " DESCENDING" : ""), relation_name); + (index_type == 1 ? " DESCENDING" : ""), relationName.toQuotedString().c_str()); // Get column names SCHAR collist[BUFFER_LENGTH512]; - if (ISQL_get_index_segments(collist, sizeof(collist), index_name, false)) - { + if (ISQL_get_index_segments(collist, sizeof(collist), indexName, false)) isqlGlob.printf("(%s) %s%s", collist, (inactive ? "(inactive)" : ""), NEWLINE); - } } -static processing_state show_indices(const char* name) +static processing_state show_indices(const std::optional& name) { /************************************** * @@ -4806,17 +4564,24 @@ static processing_state show_indices(const char* name) // The names stored in the database are all upper case - if (*name) + if (name) { - FOR IDX IN RDB$INDICES WITH - IDX.RDB$RELATION_NAME EQ name OR - IDX.RDB$INDEX_NAME EQ name - SORTED BY IDX.RDB$INDEX_NAME + FOR IDX IN RDB$INDICES + WITH IDX.RDB$RELATION_NAME EQ name->object.c_str() OR + IDX.RDB$INDEX_NAME EQ name->object.c_str() + SORTED BY IDX.RDB$SCHEMA_NAME, IDX.RDB$INDEX_NAME + { + const QualifiedMetaString indexName(IDX.RDB$INDEX_NAME, IDX.RDB$SCHEMA_NAME); + + if (name->schema.hasData() && name->schema != indexName.schema) + continue; + + const QualifiedMetaString relationName(IDX.RDB$RELATION_NAME, IDX.RDB$SCHEMA_NAME); if (IDX.RDB$INDEX_INACTIVE.NULL) IDX.RDB$INDEX_INACTIVE = 0; - show_index(IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME, + show_index(relationName, indexName, IDX.RDB$UNIQUE_FLAG, IDX.RDB$INDEX_TYPE, IDX.RDB$INDEX_INACTIVE); if (!IDX.RDB$EXPRESSION_BLR.NULL) @@ -4827,40 +4592,41 @@ static processing_state show_indices(const char* name) isqlGlob.printf(NEWLINE); } - if (ENCODE_ODS(isqlGlob.major_ods, isqlGlob.minor_ods) >= ODS_13_1) + if (!IDX.RDB$CONDITION_SOURCE.NULL) { - FOR IDX2 IN RDB$INDICES WITH - IDX2.RDB$INDEX_NAME = IDX.RDB$INDEX_NAME - AND IDX2.RDB$CONDITION_SOURCE NOT MISSING - { - isqlGlob.printf(" "); - SHOW_print_metadata_text_blob(isqlGlob.Out, &IDX2.RDB$CONDITION_SOURCE); - isqlGlob.printf(NEWLINE); - } - END_FOR + isqlGlob.printf(" "); + SHOW_print_metadata_text_blob(isqlGlob.Out, &IDX.RDB$CONDITION_SOURCE); + isqlGlob.printf(NEWLINE); } first = false; + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR + if (first) return (OBJECT_NOT_FOUND); + return (SKIP); } else { FOR IDX IN RDB$INDICES CROSS - REL IN RDB$RELATIONS OVER RDB$RELATION_NAME WITH - REL.RDB$SYSTEM_FLAG NE 1 OR - REL.RDB$SYSTEM_FLAG MISSING - SORTED BY IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME + REL IN RDB$RELATIONS + WITH REL.RDB$SCHEMA_NAME EQUIV IDX.RDB$SCHEMA_NAME AND + REL.RDB$RELATION_NAME = IDX.RDB$RELATION_NAME AND + (REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) + SORTED BY IDX.RDB$SCHEMA_NAME, IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME + { + const QualifiedMetaString indexName(IDX.RDB$INDEX_NAME, IDX.RDB$SCHEMA_NAME); + const QualifiedMetaString relationName(IDX.RDB$RELATION_NAME, IDX.RDB$SCHEMA_NAME); first = false; - show_index(IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME, + show_index(relationName, indexName, IDX.RDB$UNIQUE_FLAG, IDX.RDB$INDEX_TYPE, IDX.RDB$INDEX_INACTIVE); if (!IDX.RDB$EXPRESSION_BLR.NULL) @@ -4871,32 +4637,28 @@ static processing_state show_indices(const char* name) isqlGlob.printf(NEWLINE); } - if (ENCODE_ODS(isqlGlob.major_ods, isqlGlob.minor_ods) >= ODS_13_1) + if (!IDX.RDB$CONDITION_SOURCE.NULL) { - FOR IDX2 IN RDB$INDICES WITH - IDX2.RDB$INDEX_NAME = IDX.RDB$INDEX_NAME - AND IDX2.RDB$CONDITION_SOURCE NOT MISSING - { - isqlGlob.printf(" "); - SHOW_print_metadata_text_blob(isqlGlob.Out, &IDX2.RDB$CONDITION_SOURCE); - isqlGlob.printf(NEWLINE); - } - END_FOR + isqlGlob.printf(" "); + SHOW_print_metadata_text_blob(isqlGlob.Out, &IDX.RDB$CONDITION_SOURCE); + isqlGlob.printf(NEWLINE); } - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR + if (first) return (OBJECT_NOT_FOUND); + return (SKIP); } } -static processing_state show_packages(const SCHAR* package_name, bool sys, const SCHAR* msg) +static processing_state show_packages(const std::optional& name, bool sys, const SCHAR* msg) { /************************************* * @@ -4912,12 +4674,13 @@ static processing_state show_packages(const SCHAR* package_name, bool sys, const bool first = true; - if (!(package_name && *package_name)) + if (!name) { // List all package names in columns FOR PACK IN RDB$PACKAGES - SORTED BY PACK.RDB$PACKAGE_NAME + SORTED BY PACK.RDB$SCHEMA_NAME, PACK.RDB$PACKAGE_NAME { + const QualifiedMetaString packageName(PACK.RDB$PACKAGE_NAME, PACK.RDB$SCHEMA_NAME); bool system_flag = !PACK.RDB$SYSTEM_FLAG.NULL && PACK.RDB$SYSTEM_FLAG > 0; if (system_flag == sys) @@ -4926,14 +4689,15 @@ static processing_state show_packages(const SCHAR* package_name, bool sys, const isqlGlob.printf("%s%s", msg, NEWLINE); first = false; - isqlGlob.printf("%s%s", fb_utils::exact_name(PACK.RDB$PACKAGE_NAME), NEWLINE); + isqlGlob.printf("%s%s", packageName.toQuotedString().c_str(), NEWLINE); } } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR + if (!first) isqlGlob.printf(NEWLINE); } @@ -4941,13 +4705,19 @@ static processing_state show_packages(const SCHAR* package_name, bool sys, const { // List named package - FOR PACK IN RDB$PACKAGES WITH - PACK.RDB$PACKAGE_NAME EQ package_name + FOR PACK IN RDB$PACKAGES + WITH PACK.RDB$PACKAGE_NAME EQ name->object.c_str() + SORTED BY PACK.RDB$SCHEMA_NAME + { + const QualifiedMetaString packageName(PACK.RDB$PACKAGE_NAME, PACK.RDB$SCHEMA_NAME); + + if (name->schema.hasData() && name->schema != packageName.schema) + continue; first = false; + // Print the name of the package - fb_utils::exact_name(PACK.RDB$PACKAGE_NAME); - isqlGlob.printf("%-31s ", PACK.RDB$PACKAGE_NAME); + isqlGlob.printf("%-31s ", packageName.toQuotedString().c_str()); isqlGlob.printf(NEWLINE); @@ -4975,12 +4745,12 @@ static processing_state show_packages(const SCHAR* package_name, bool sys, const SHOW_print_metadata_text_blob (isqlGlob.Out, &PACK.RDB$PACKAGE_BODY_SOURCE); isqlGlob.printf(NEWLINE); } - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR } if (first) @@ -4990,6 +4760,7 @@ static processing_state show_packages(const SCHAR* package_name, bool sys, const } +// FIXME: static void printIdent(bool quote, char* ident, const char* format = NULL) { fb_utils::exact_name(ident); @@ -5004,7 +4775,7 @@ static void printIdent(bool quote, char* ident, const char* format = NULL) } -static void printMap(bool extract, bool global, char* name, char* usng, char* plugin, char* db, +static void printMap(bool extract, bool global, const MetaString& name, char* usng, char* plugin, char* db, char* fromType, char* from, short toType, char* to) { if (extract) @@ -5013,7 +4784,8 @@ static void printMap(bool extract, bool global, char* name, char* usng, char* pl if (global) isqlGlob.printf("OR ALTER GLOBAL "); } - printIdent(extract, name, extract ? "MAPPING %s " : "%s "); + + isqlGlob.printf("MAPPING %s ", ISQL_name_to_string(name).c_str()); isqlGlob.printf("USING "); switch (usng[0]) @@ -5054,7 +4826,7 @@ static void printMap(bool extract, bool global, char* name, char* usng, char* pl } -processing_state SHOW_maps(bool extract, const SCHAR* map_name) +processing_state SHOW_maps(bool extract, const std::optional& name) { /************************************* * @@ -5074,38 +4846,37 @@ processing_state SHOW_maps(bool extract, const SCHAR* map_name) FOR M IN RDB$AUTH_MAPPING WITH (M.RDB$SYSTEM_FLAG NE 1 OR M.RDB$SYSTEM_FLAG MISSING) SORTED BY M.RDB$MAP_NAME + { + const MetaString mapName(M.RDB$MAP_NAME); - Firebird::NoCaseString nm = M.RDB$MAP_NAME; - nm.trim(); - - if ((!*map_name) || (nm == map_name)) + if (!name || mapName == name) { if (first && extract) isqlGlob.printf("%s/* Mapping security objects for this database */%s", NEWLINE, NEWLINE); first = false; - printMap(extract, false, M.RDB$MAP_NAME, M.RDB$MAP_USING, + printMap(extract, false, mapName, M.RDB$MAP_USING, (M.RDB$MAP_PLUGIN.NULL ? NULL : M.RDB$MAP_PLUGIN), (M.RDB$MAP_DB.NULL ? NULL : M.RDB$MAP_DB), M.RDB$MAP_FROM_TYPE, M.RDB$MAP_FROM, M.RDB$MAP_TO_TYPE, (M.RDB$MAP_TO.NULL ? NULL : M.RDB$MAP_TO)); } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR bool firstGlobal = true; // List global mappings FOR M IN SEC$GLOBAL_AUTH_MAPPING SORTED BY M.SEC$MAP_NAME + { + const MetaString mapName(M.SEC$MAP_NAME); - Firebird::NoCaseString nm = M.SEC$MAP_NAME; - nm.trim(); - - if ((!*map_name) || (nm == map_name)) + if (!name || mapName == name) { if (firstGlobal) { @@ -5117,23 +4888,24 @@ processing_state SHOW_maps(bool extract, const SCHAR* map_name) first = false; - printMap(extract, true, M.SEC$MAP_NAME, M.SEC$MAP_USING, + printMap(extract, true, mapName, M.SEC$MAP_USING, (M.SEC$MAP_PLUGIN.NULL ? NULL : M.SEC$MAP_PLUGIN), (M.SEC$MAP_DB.NULL ? NULL : M.SEC$MAP_DB), M.SEC$MAP_FROM_TYPE, M.SEC$MAP_FROM, M.SEC$MAP_TO_TYPE, (M.SEC$MAP_TO.NULL ? NULL : M.SEC$MAP_TO)); } + } END_FOR ON_ERROR if (!extract) ISQL_errmsg(fbStatus); // report error but not return error on it - END_ERROR; + END_ERROR return first ? OBJECT_NOT_FOUND : SKIP; } -static processing_state show_proc(const char* procname, const char* packname, bool quoted, bool sys, const char* msg) +static processing_state show_proc(const std::optional& name, bool quoted, bool sys, const char* msg) { /************************************** * @@ -5151,7 +4923,7 @@ static processing_state show_proc(const char* procname, const char* packname, bo // If no procedure name was given, just list the procedures - if (!procname || !strlen(procname)) + if (!name) { // This query gets the procedure name; the next query // gets all the dependencies if any @@ -5159,7 +4931,7 @@ static processing_state show_proc(const char* procname, const char* packname, bo bool first_proc = true; FOR PRC IN RDB$PROCEDURES - SORTED BY PRC.RDB$PACKAGE_NAME, PRC.RDB$PROCEDURE_NAME + SORTED BY PRC.RDB$SCHEMA_NAME, PRC.RDB$PACKAGE_NAME, PRC.RDB$PROCEDURE_NAME { bool system_flag = !PRC.RDB$SYSTEM_FLAG.NULL && PRC.RDB$SYSTEM_FLAG > 0; @@ -5172,11 +4944,10 @@ static processing_state show_proc(const char* procname, const char* packname, bo first_proc = false; } - // Strip trailing blanks - MetaString package(PRC.RDB$PACKAGE_NAME); - MetaString procedure(PRC.RDB$PROCEDURE_NAME); + const QualifiedMetaString procedureName( + PRC.RDB$PROCEDURE_NAME, PRC.RDB$SCHEMA_NAME, PRC.RDB$PACKAGE_NAME); - isqlGlob.printf("%s%s%s", package.c_str(), package.hasData() ? "." : "", procedure.c_str()); + isqlGlob.printf("%s", procedureName.toQuotedString().c_str()); if (!(PRC.RDB$VALID_BLR.NULL || PRC.RDB$VALID_BLR)) isqlGlob.printf("; Invalid"); @@ -5184,12 +4955,14 @@ static processing_state show_proc(const char* procname, const char* packname, bo if (PRC.RDB$PACKAGE_NAME.NULL) { bool first_dep = true; - FOR DEP IN RDB$DEPENDENCIES WITH - PRC.RDB$PROCEDURE_NAME EQ DEP.RDB$DEPENDENT_NAME - REDUCED TO DEP.RDB$DEPENDED_ON_TYPE, DEP.RDB$DEPENDED_ON_NAME - SORTED BY DEP.RDB$DEPENDED_ON_TYPE, DEP.RDB$DEPENDED_ON_NAME + FOR DEP IN RDB$DEPENDENCIES + WITH DEP.RDB$DEPENDENT_SCHEMA_NAME EQUIV NULLIF(procedureName.schema.c_str(), '') AND + DEP.RDB$DEPENDENT_NAME EQ procedureName.object.c_str() + REDUCED TO DEP.RDB$DEPENDED_ON_SCHEMA_NAME, DEP.RDB$DEPENDED_ON_TYPE, DEP.RDB$DEPENDED_ON_NAME + SORTED BY DEP.RDB$DEPENDED_ON_SCHEMA_NAME, DEP.RDB$DEPENDED_ON_TYPE, DEP.RDB$DEPENDED_ON_NAME { - fb_utils::exact_name(DEP.RDB$DEPENDED_ON_NAME); + const QualifiedMetaString dependendOnName( + DEP.RDB$DEPENDED_ON_NAME, DEP.RDB$DEPENDED_ON_SCHEMA_NAME); if (first_dep) { @@ -5199,14 +4972,16 @@ static processing_state show_proc(const char* procname, const char* packname, bo else isqlGlob.printf(", "); - isqlGlob.printf("%s (%s)", fb_utils::exact_name(DEP.RDB$DEPENDED_ON_NAME), - Object_types[DEP.RDB$DEPENDED_ON_TYPE]); + isqlGlob.printf( + "%s (%s)", + dependendOnName.toQuotedString().c_str(), + Object_types[DEP.RDB$DEPENDED_ON_TYPE]); } END_FOR ON_ERROR ISQL_errmsg (fbStatus); return ps_ERR; - END_ERROR; + END_ERROR } isqlGlob.printf(NEWLINE); @@ -5229,15 +5004,21 @@ static processing_state show_proc(const char* procname, const char* packname, bo bool first = true; - const MetaString procedure(procname); - const MetaString package(packname); - FOR PRC IN RDB$PROCEDURES WITH - PRC.RDB$PROCEDURE_NAME EQ procedure.c_str() AND - PRC.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '') + PRC.RDB$PROCEDURE_NAME EQ name->object.c_str() AND + PRC.RDB$PACKAGE_NAME EQUIV NULLIF(name->package.c_str(), '') + SORTED BY PRC.RDB$SCHEMA_NAME + { + const QualifiedMetaString procedureName( + PRC.RDB$PROCEDURE_NAME, PRC.RDB$SCHEMA_NAME, PRC.RDB$PACKAGE_NAME); + + if (name->schema.hasData() && name->schema != procedureName.schema) + continue; first = false; + // FIXME: Print procedureName + if (!PRC.RDB$ENTRYPOINT.NULL) { fb_utils::exact_name(PRC.RDB$ENTRYPOINT); @@ -5267,21 +5048,23 @@ static processing_state show_proc(const char* procname, const char* packname, bo bool first_param = true; FOR PRM IN RDB$PROCEDURE_PARAMETERS CROSS - FLD IN RDB$FIELDS WITH - PRM.RDB$PROCEDURE_NAME EQ PRC.RDB$PROCEDURE_NAME AND - PRM.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '') AND - PRM.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME + FLD IN RDB$FIELDS + WITH PRM.RDB$SCHEMA_NAME EQUIV NULLIF(procedureName.schema.c_str(), '') AND + PRM.RDB$PACKAGE_NAME EQUIV NULLIF(procedureName.package.c_str(), '') AND + PRM.RDB$PROCEDURE_NAME EQ procedureName.object.c_str() AND + PRM.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME SORTED BY PRM.RDB$PARAMETER_TYPE, PRM.RDB$PARAMETER_NUMBER - + { if (first_param) { isqlGlob.printf("Parameters:%s", NEWLINE); first_param = false; } - fb_utils::exact_name(PRM.RDB$PARAMETER_NAME); - isqlGlob.printf("%-33s %s ", PRM.RDB$PARAMETER_NAME, - (PRM.RDB$PARAMETER_TYPE ? "OUTPUT" : "INPUT")); + isqlGlob.printf( + "%-33s %s ", + MetaString(PRM.RDB$PARAMETER_NAME).toQuotedString().c_str(), + (PRM.RDB$PARAMETER_TYPE ? "OUTPUT" : "INPUT")); prm_mech_t mechanism = prm_mech_normal; bool prm_default_source_null = true; @@ -5303,37 +5086,28 @@ static processing_state show_proc(const char* procname, const char* packname, bo if (!prm_collation_null) collation = PRM.RDB$COLLATION_ID; - char relationName[BUFFER_LENGTH256] = ""; - char relationField[BUFFER_LENGTH256] = ""; + const QualifiedMetaString domainName(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME); + const QualifiedMetaString relationName(PRM.RDB$RELATION_NAME, PRM.RDB$RELATION_SCHEMA_NAME); + const MetaString relationField(PRM.RDB$FIELD_NAME); - if (!PRM.RDB$RELATION_NAME.NULL) - { - strcpy(relationName, PRM.RDB$RELATION_NAME); - fb_utils::exact_name(relationName); - } - - if (!PRM.RDB$FIELD_NAME.NULL) - { - strcpy(relationField, PRM.RDB$FIELD_NAME); - fb_utils::exact_name(relationField); - } - - if (prm_collation_null) + if (prm_collation_null && relationName.object.hasData()) { FOR RFL IN RDB$RELATION_FIELDS - WITH RFL.RDB$RELATION_NAME = PRM.RDB$RELATION_NAME AND + WITH RFL.RDB$SCHEMA_NAME EQUIV NULLIF(relationName.schema.c_str(), '') AND + RFL.RDB$RELATION_NAME = relationName.object.c_str() AND RFL.RDB$FIELD_NAME = PRM.RDB$FIELD_NAME - + { prm_collation_null = RFL.RDB$COLLATION_ID.NULL; if (!prm_collation_null) collation = RFL.RDB$COLLATION_ID; + } END_FOR } if (prm_collation_null && !FLD.RDB$COLLATION_ID.NULL) collation = FLD.RDB$COLLATION_ID; - const bool basedOnColumn = relationName[0] && relationField[0]; + const bool basedOnColumn = relationName.object.hasData() && relationField.hasData(); // Decide if this is a user-created domain if (!fb_utils::implicit_domain(FLD.RDB$FIELD_NAME) || FLD.RDB$SYSTEM_FLAG == 1 || basedOnColumn) @@ -5341,15 +5115,17 @@ static processing_state show_proc(const char* procname, const char* packname, bo isqlGlob.printf("(%s", (mechanism == prm_mech_type_of ? "TYPE OF " : "")); if (basedOnColumn) - isqlGlob.printf("COLUMN %s.%s) ", relationName, relationField); - else { - fb_utils::exact_name(FLD.RDB$FIELD_NAME); - isqlGlob.printf("%s) ", FLD.RDB$FIELD_NAME); + isqlGlob.printf( + "COLUMN %s.%s) ", + relationName.toQuotedString().c_str(), + relationField.c_str()); } + else + isqlGlob.printf("%s) ", domainName.toQuotedString().c_str()); } - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, + if (!ISQL_printNumericType(domainName, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) { return ps_ERR; @@ -5391,23 +5167,27 @@ static processing_state show_proc(const char* procname, const char* packname, bo } isqlGlob.printf(NEWLINE); + } END_FOR ON_ERROR ISQL_errmsg (fbStatus); return ps_ERR; - END_ERROR; + END_ERROR + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR + if (first) return (OBJECT_NOT_FOUND); + return (SKIP); } -static processing_state show_publications(const SCHAR* pub_name, bool sys, const SCHAR* msg) +static processing_state show_publications(const std::optional& name, bool sys, const SCHAR* msg) { /************************************** * @@ -5424,17 +5204,18 @@ static processing_state show_publications(const SCHAR* pub_name, bool sys, const bool first = true; - if (pub_name && *pub_name) + if (name) { // List named publication FOR PUB IN RDB$PUBLICATIONS WITH - PUB.RDB$PUBLICATION_NAME EQ pub_name + PUB.RDB$PUBLICATION_NAME EQ name->c_str() + { + const MetaString publicationName(PUB.RDB$PUBLICATION_NAME); first = false; - fb_utils::exact_name(PUB.RDB$PUBLICATION_NAME); - isqlGlob.printf("%s: ", PUB.RDB$PUBLICATION_NAME); + isqlGlob.printf("%s: ", publicationName.toQuotedString().c_str()); const bool active_flag = (!PUB.RDB$ACTIVE_FLAG.NULL && PUB.RDB$ACTIVE_FLAG > 0); isqlGlob.printf("%s", active_flag ? "Enabled" : "Disabled"); @@ -5443,12 +5224,12 @@ static processing_state show_publications(const SCHAR* pub_name, bool sys, const isqlGlob.printf(", Auto-enable"); isqlGlob.printf(NEWLINE); - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR } else { @@ -5456,7 +5237,8 @@ static processing_state show_publications(const SCHAR* pub_name, bool sys, const FOR PUB IN RDB$PUBLICATIONS SORTED BY PUB.RDB$PUBLICATION_NAME - + { + const MetaString publicationName(PUB.RDB$PUBLICATION_NAME); const bool system_flag = (!PUB.RDB$SYSTEM_FLAG.NULL && PUB.RDB$SYSTEM_FLAG > 0); if (system_flag == sys) @@ -5466,14 +5248,14 @@ static processing_state show_publications(const SCHAR* pub_name, bool sys, const first = false; - isqlGlob.printf("%s%s", fb_utils::exact_name(PUB.RDB$PUBLICATION_NAME), NEWLINE); + isqlGlob.printf("%s%s", publicationName.toQuotedString().c_str(), NEWLINE); } - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR if (!first) isqlGlob.printf(NEWLINE); @@ -5486,7 +5268,7 @@ static processing_state show_publications(const SCHAR* pub_name, bool sys, const } -static void show_pub_table(const SCHAR* table_name) +static void show_pub_table(const QualifiedMetaString& name) { /************************************** * @@ -5503,34 +5285,35 @@ static void show_pub_table(const SCHAR* table_name) bool first = true; - if (table_name && *table_name) + // TODO: remove block and indendation { FOR PTAB IN RDB$PUBLICATION_TABLES CROSS - PUB IN RDB$PUBLICATIONS OVER RDB$PUBLICATION_NAME WITH - PTAB.RDB$TABLE_NAME EQ table_name + PUB IN RDB$PUBLICATIONS OVER RDB$PUBLICATION_NAME + WITH PTAB.RDB$TABLE_SCHEMA_NAME EQUIV NULLIF(name.schema.c_str(), '') AND + PTAB.RDB$TABLE_NAME EQ name.object.c_str() SORTED BY DESCENDING PUB.RDB$SYSTEM_FLAG, PUB.RDB$PUBLICATION_NAME - - const auto pub_name = fb_utils::exact_name(PUB.RDB$PUBLICATION_NAME); + { + const MetaString publicationName(PUB.RDB$PUBLICATION_NAME); if (first) { TEXT msg[MSG_LENGTH]; IUTILS_msg_get(MSG_PUBLICATIONS, msg); - isqlGlob.printf("%s %s", msg, pub_name); + isqlGlob.printf("%s %s", msg, publicationName.toQuotedString().c_str()); } else - isqlGlob.printf(", %s", pub_name); + isqlGlob.printf(", %s", publicationName.toQuotedString().c_str()); const bool active_flag = (!PUB.RDB$ACTIVE_FLAG.NULL && PUB.RDB$ACTIVE_FLAG > 0); isqlGlob.printf(" (%s)", active_flag ? "Enabled" : "Disabled"); first = false; - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return; - END_ERROR; + END_ERROR } if (!first) @@ -5538,12 +5321,12 @@ static void show_pub_table(const SCHAR* table_name) } -bool SHOW_system_privileges(const char* role, const char* prefix, bool lf) +bool SHOW_system_privileges(const MetaString& name, const char* prefix, bool lf) { bool first = true; FOR X IN RDB$ROLES WITH - X.RDB$ROLE_NAME EQ role + X.RDB$ROLE_NAME EQ name.c_str() { if (!X.RDB$SYSTEM_PRIVILEGES.NULL) { @@ -5580,18 +5363,18 @@ bool SHOW_system_privileges(const char* role, const char* prefix, bool lf) ON_ERROR ISQL_errmsg(fbStatus); return false; - END_ERROR; + END_ERROR return !first; } -static processing_state show_role(const SCHAR* object, bool system, const char* msg) +static processing_state show_role(const std::optional& name, bool system, const char* msg) { if (isqlGlob.major_ods < ODS_VERSION9) return OBJECT_NOT_FOUND; - if (object == NULL) + if (!name) { // show role with no parameters, show all roles // ************************************** @@ -5606,6 +5389,7 @@ static processing_state show_role(const SCHAR* object, bool system, const char* X.RDB$ROLE_NAME NOT MISSING SORTED BY X.RDB$ROLE_NAME { + const MetaString roleName(X.RDB$ROLE_NAME); bool system_flag = !X.RDB$SYSTEM_FLAG.NULL && X.RDB$SYSTEM_FLAG > 0; if (system_flag == system) @@ -5614,7 +5398,7 @@ static processing_state show_role(const SCHAR* object, bool system, const char* isqlGlob.printf("%s%s", msg, NEWLINE); first = false; - isqlGlob.printf("%s%s", fb_utils::exact_name(X.RDB$ROLE_NAME), NEWLINE); + isqlGlob.printf("%s%s", roleName.toQuotedString().c_str(), NEWLINE); /*** if (SHOW_system_privileges(X.RDB$ROLE_NAME, "System privileges:", !odd)) @@ -5629,7 +5413,7 @@ static processing_state show_role(const SCHAR* object, bool system, const char* ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR if (!first) { @@ -5641,35 +5425,31 @@ static processing_state show_role(const SCHAR* object, bool system, const char* } // show role with role supplied, display users and other roles granted this role - SCHAR role_name[BUFFER_LENGTH256]; bool first = true; - FOR FIRST 1 R IN RDB$ROLES WITH R.RDB$ROLE_NAME EQ object - + FOR FIRST 1 R IN RDB$ROLES + WITH R.RDB$ROLE_NAME EQ name->c_str() + { FOR PRV IN RDB$USER_PRIVILEGES WITH PRV.RDB$OBJECT_TYPE EQ obj_sql_role AND (PRV.RDB$USER_TYPE EQ obj_user OR PRV.RDB$USER_TYPE EQ obj_sql_role) AND - PRV.RDB$RELATION_NAME EQ object AND + PRV.RDB$RELATION_NAME EQ name->c_str() AND PRV.RDB$PRIVILEGE EQ 'M' SORTED BY PRV.RDB$USER - + { if (first) { first = false; - fb_utils::exact_name(PRV.RDB$RELATION_NAME); - strcpy(role_name, PRV.RDB$RELATION_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(role_name, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, role_name); - isqlGlob.printf("Role %s is granted to:%s", SQL_identifier, NEWLINE); + isqlGlob.printf( + "Role %s is granted to:%s", + MetaString(PRV.RDB$RELATION_NAME).toQuotedString().c_str(), + NEWLINE); } - fb_utils::exact_name(PRV.RDB$USER); - isqlGlob.printf("%s%s", PRV.RDB$USER, NEWLINE); - + isqlGlob.printf("%s%s", MetaString(PRV.RDB$USER).toQuotedString().c_str(), NEWLINE); + } END_FOR ON_ERROR ISQL_errmsg (fbStatus); @@ -5678,17 +5458,14 @@ static processing_state show_role(const SCHAR* object, bool system, const char* if (first) { - first = false; - fb_utils::exact_name(R.RDB$ROLE_NAME); - strcpy(role_name, R.RDB$ROLE_NAME); - if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) - IUTILS_copy_SQL_id(role_name, SQL_identifier, DBL_QUOTE); - else - strcpy(SQL_identifier, role_name); + first = false; - isqlGlob.printf("Role %s isn't granted to anyone.%s", SQL_identifier, NEWLINE); + isqlGlob.printf( + "Role %s isn't granted to anyone.%s", + MetaString(R.RDB$ROLE_NAME).toQuotedString().c_str(), + NEWLINE); } - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -5697,7 +5474,7 @@ static processing_state show_role(const SCHAR* object, bool system, const char* if (first) return (OBJECT_NOT_FOUND); - else if (SHOW_system_privileges(object, "System privileges:", false)) + else if (SHOW_system_privileges(name.value(), "System privileges:", false)) isqlGlob.printf("%s", NEWLINE); return (SKIP); @@ -5710,7 +5487,7 @@ static processing_state show_role(const SCHAR* object, bool system, const char* // Show low-level, GDML security for an object. It may be table/view or procedure. // Using SHOW SECCLASS DET[AIL] will print the contents of the sec blob. // Using SHOW SECCLASS * DET[AIL] will print the db-wide sec class in rdb$database. -static processing_state show_secclass(const std::optional& object, bool detail) +static processing_state show_secclass(const std::optional& name, bool detail) { IsqlVar var; memset(&var, 0, sizeof(var)); @@ -5718,11 +5495,12 @@ static processing_state show_secclass(const std::optional& object, b int count = 0; - if (!object) + if (!name) { FOR D IN RDB$DATABASE - CROSS SC IN RDB$SECURITY_CLASSES - OVER RDB$SECURITY_CLASS + CROSS SC IN RDB$SECURITY_CLASSES + OVER RDB$SECURITY_CLASS + { ++count; isqlGlob.printf("Database-wide's sec class %s%s", fb_utils::exact_name(SC.RDB$SECURITY_CLASS), NEWLINE); @@ -5731,6 +5509,7 @@ static processing_state show_secclass(const std::optional& object, b var.value.setPtr = &SC.RDB$ACL; ISQL_print_item_blob(isqlGlob.Out, &var, fbTrans, isc_blob_acl); } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -5741,9 +5520,16 @@ static processing_state show_secclass(const std::optional& object, b } FOR REL IN RDB$RELATIONS - CROSS SC IN RDB$SECURITY_CLASSES - OVER RDB$SECURITY_CLASS - WITH REL.RDB$RELATION_NAME EQ object->c_str() + CROSS SC IN RDB$SECURITY_CLASSES + OVER RDB$SECURITY_CLASS + WITH REL.RDB$RELATION_NAME EQ name->object.c_str() + SORTED BY REL.RDB$SCHEMA_NAME + { + const QualifiedMetaString relationName(REL.RDB$RELATION_NAME, REL.RDB$SCHEMA_NAME); + + if (name->schema.hasData() && name->schema != relationName.schema) + continue; + ++count; isqlGlob.printf("%s's main sec class %s%s", REL.RDB$VIEW_BLR.NULL ? "Table" : "View", @@ -5753,6 +5539,7 @@ static processing_state show_secclass(const std::optional& object, b var.value.asChar = reinterpret_cast(&SC.RDB$ACL); ISQL_print_item_blob(isqlGlob.Out, &var, fbTrans, isc_blob_acl); } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -5760,9 +5547,16 @@ static processing_state show_secclass(const std::optional& object, b END_ERROR FOR REL2 IN RDB$RELATIONS - CROSS SC IN RDB$SECURITY_CLASSES - WITH REL2.RDB$RELATION_NAME EQ object->c_str() - AND REL2.RDB$DEFAULT_CLASS EQ SC.RDB$SECURITY_CLASS + CROSS SC IN RDB$SECURITY_CLASSES + WITH REL2.RDB$RELATION_NAME EQ name->object.c_str() AND + REL2.RDB$DEFAULT_CLASS EQ SC.RDB$SECURITY_CLASS + SORTED BY REL2.RDB$SCHEMA_NAME + { + const QualifiedMetaString relationName(REL2.RDB$RELATION_NAME, REL2.RDB$SCHEMA_NAME); + + if (name->schema.hasData() && name->schema != relationName.schema) + continue; + ++count; isqlGlob.printf("%s's default sec class %s%s", REL2.RDB$VIEW_BLR.NULL ? "Table" : "View", @@ -5772,6 +5566,7 @@ static processing_state show_secclass(const std::optional& object, b var.value.asChar = reinterpret_cast(&SC.RDB$ACL); ISQL_print_item_blob(isqlGlob.Out, &var, fbTrans, isc_blob_acl); } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -5779,18 +5574,28 @@ static processing_state show_secclass(const std::optional& object, b END_ERROR FOR RF IN RDB$RELATION_FIELDS - CROSS SC IN RDB$SECURITY_CLASSES - OVER RDB$SECURITY_CLASS - WITH RF.RDB$RELATION_NAME EQ object->c_str() - SORTED BY RF.RDB$FIELD_POSITION + CROSS SC IN RDB$SECURITY_CLASSES + OVER RDB$SECURITY_CLASS + WITH RF.RDB$RELATION_NAME EQ name->object.c_str() + SORTED BY RF.RDB$SCHEMA_NAME, RF.RDB$FIELD_POSITION + { + const QualifiedMetaString relationName(RF.RDB$RELATION_NAME, RF.RDB$SCHEMA_NAME); + + if (name->schema.hasData() && name->schema != relationName.schema) + continue; + ++count; - isqlGlob.printf(" Field %s - sec class %s%s", fb_utils::exact_name(RF.RDB$FIELD_NAME), + isqlGlob.printf( + " Field %s - sec class %s%s", + MetaString(RF.RDB$FIELD_NAME).toQuotedString().c_str(), SC.RDB$SECURITY_CLASS, NEWLINE); + if (detail) { var.value.asChar = reinterpret_cast(&SC.RDB$ACL); ISQL_print_item_blob(isqlGlob.Out, &var, fbTrans, isc_blob_acl); } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -5798,10 +5603,17 @@ static processing_state show_secclass(const std::optional& object, b END_ERROR FOR PR IN RDB$PROCEDURES - CROSS SC IN RDB$SECURITY_CLASSES - OVER RDB$SECURITY_CLASS - WITH PR.RDB$PROCEDURE_NAME EQ object->c_str() AND - PR.RDB$PACKAGE_NAME MISSING + CROSS SC IN RDB$SECURITY_CLASSES + OVER RDB$SECURITY_CLASS + WITH PR.RDB$PROCEDURE_NAME EQ name->object.c_str() AND + PR.RDB$PACKAGE_NAME MISSING + SORTED BY PR.RDB$SCHEMA_NAME + { + const QualifiedMetaString procedureName(PR.RDB$PROCEDURE_NAME, PR.RDB$SCHEMA_NAME); + + if (name->schema.hasData() && name->schema != procedureName.schema) + continue; + ++count; isqlGlob.printf("Procedure's sec class %s%s", fb_utils::exact_name(SC.RDB$SECURITY_CLASS), NEWLINE); @@ -5810,6 +5622,7 @@ static processing_state show_secclass(const std::optional& object, b var.value.asChar = reinterpret_cast(&SC.RDB$ACL); ISQL_print_item_blob(isqlGlob.Out, &var, fbTrans, isc_blob_acl); } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -5819,10 +5632,17 @@ static processing_state show_secclass(const std::optional& object, b if (isqlGlob.major_ods >= ODS_VERSION12) { FOR FUN IN RDB$FUNCTIONS - CROSS SC IN RDB$SECURITY_CLASSES - OVER RDB$SECURITY_CLASS - WITH FUN.RDB$FUNCTION_NAME EQ object->c_str() AND - FUN.RDB$PACKAGE_NAME MISSING + CROSS SC IN RDB$SECURITY_CLASSES + OVER RDB$SECURITY_CLASS + WITH FUN.RDB$FUNCTION_NAME EQ name->object.c_str() AND + FUN.RDB$PACKAGE_NAME MISSING + SORTED BY FUN.RDB$SCHEMA_NAME + { + const QualifiedMetaString functionName(FUN.RDB$FUNCTION_NAME, FUN.RDB$SCHEMA_NAME); + + if (name->schema.hasData() && name->schema != functionName.schema) + continue; + ++count; isqlGlob.printf("Function's sec class %s%s", fb_utils::exact_name(SC.RDB$SECURITY_CLASS), NEWLINE); @@ -5831,6 +5651,7 @@ static processing_state show_secclass(const std::optional& object, b var.value.asChar = reinterpret_cast(&SC.RDB$ACL); ISQL_print_item_blob(isqlGlob.Out, &var, fbTrans, isc_blob_acl); } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -5838,9 +5659,16 @@ static processing_state show_secclass(const std::optional& object, b END_ERROR FOR PKG IN RDB$PACKAGES - CROSS SC IN RDB$SECURITY_CLASSES - OVER RDB$SECURITY_CLASS - WITH PKG.RDB$PACKAGE_NAME EQ object->c_str() + CROSS SC IN RDB$SECURITY_CLASSES + OVER RDB$SECURITY_CLASS + WITH PKG.RDB$PACKAGE_NAME EQ name->object.c_str() + SORTED BY PKG.RDB$SCHEMA_NAME + { + const QualifiedMetaString packageName(PKG.RDB$PACKAGE_NAME, PKG.RDB$SCHEMA_NAME); + + if (name->schema.hasData() && name->schema != packageName.schema) + continue; + ++count; isqlGlob.printf("Package's sec class %s%s", fb_utils::exact_name(SC.RDB$SECURITY_CLASS), NEWLINE); @@ -5849,6 +5677,7 @@ static processing_state show_secclass(const std::optional& object, b var.value.asChar = reinterpret_cast(&SC.RDB$ACL); ISQL_print_item_blob(isqlGlob.Out, &var, fbTrans, isc_blob_acl); } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -5856,9 +5685,16 @@ static processing_state show_secclass(const std::optional& object, b END_ERROR FOR GEN IN RDB$GENERATORS - CROSS SC IN RDB$SECURITY_CLASSES - OVER RDB$SECURITY_CLASS - WITH GEN.RDB$GENERATOR_NAME EQ object->c_str() + CROSS SC IN RDB$SECURITY_CLASSES + OVER RDB$SECURITY_CLASS + WITH GEN.RDB$GENERATOR_NAME EQ name->object.c_str() + SORTED BY GEN.RDB$SCHEMA_NAME + { + const QualifiedMetaString generatorName(GEN.RDB$GENERATOR_NAME, GEN.RDB$SCHEMA_NAME); + + if (name->schema.hasData() && name->schema != generatorName.schema) + continue; + ++count; isqlGlob.printf("Sequence's sec class %s%s", fb_utils::exact_name(SC.RDB$SECURITY_CLASS), NEWLINE); @@ -5867,6 +5703,7 @@ static processing_state show_secclass(const std::optional& object, b var.value.asChar = reinterpret_cast(&SC.RDB$ACL); ISQL_print_item_blob(isqlGlob.Out, &var, fbTrans, isc_blob_acl); } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -5874,9 +5711,16 @@ static processing_state show_secclass(const std::optional& object, b END_ERROR FOR XCP IN RDB$EXCEPTIONS - CROSS SC IN RDB$SECURITY_CLASSES - OVER RDB$SECURITY_CLASS - WITH XCP.RDB$EXCEPTION_NAME EQ object->c_str() + CROSS SC IN RDB$SECURITY_CLASSES + OVER RDB$SECURITY_CLASS + WITH XCP.RDB$EXCEPTION_NAME EQ name->object.c_str() + SORTED BY XCP.RDB$SCHEMA_NAME + { + const QualifiedMetaString exceptionName(XCP.RDB$EXCEPTION_NAME, XCP.RDB$SCHEMA_NAME); + + if (name->schema.hasData() && name->schema != exceptionName.schema) + continue; + ++count; isqlGlob.printf("Exception's sec class %s%s", fb_utils::exact_name(SC.RDB$SECURITY_CLASS), NEWLINE); @@ -5885,6 +5729,30 @@ static processing_state show_secclass(const std::optional& object, b var.value.asChar = reinterpret_cast(&SC.RDB$ACL); ISQL_print_item_blob(isqlGlob.Out, &var, fbTrans, isc_blob_acl); } + } + END_FOR + ON_ERROR + ISQL_errmsg(fbStatus); + return ps_ERR; + END_ERROR + } + + if (isqlGlob.major_ods >= ODS_VERSION14 && name->schema.isEmpty()) + { + FOR SCH IN RDB$SCHEMAS + CROSS SC IN RDB$SECURITY_CLASSES + OVER RDB$SECURITY_CLASS + WITH SCH.RDB$SCHEMA_NAME EQ name->object.c_str() + { + ++count; + isqlGlob.printf("Schema's sec class %s%s", + fb_utils::exact_name(SC.RDB$SECURITY_CLASS), NEWLINE); + if (detail) + { + var.value.asChar = reinterpret_cast(&SC.RDB$ACL); + ISQL_print_item_blob(isqlGlob.Out, &var, fbTrans, isc_blob_acl); + } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -5896,7 +5764,7 @@ static processing_state show_secclass(const std::optional& object, b } -static processing_state show_table(const SCHAR* relation_name, bool isView) +static processing_state show_table(const QualifiedMetaString& name, bool isView) { /************************************** * @@ -5910,7 +5778,7 @@ static processing_state show_table(const SCHAR* relation_name, bool isView) * Use a SQL query to get the info and print it. * This also shows integrity constraints and triggers * - * relation_name -- Name of table to investigate + * name -- Name of table to investigate * **************************************/ bool first = true; @@ -5919,67 +5787,59 @@ static processing_state show_table(const SCHAR* relation_name, bool isView) // REL.RDB$VIEW_BLR NOT MISSING FOR REL IN RDB$RELATIONS - WITH REL.RDB$RELATION_NAME EQ relation_name - if (first) - { - if (!REL.RDB$SQL_SECURITY.NULL) - { - const char* ss = REL.RDB$SQL_SECURITY ? "DEFINER" : "INVOKER"; - isqlGlob.printf("SQL SECURITY: %s%s", ss, NEWLINE); - } + WITH REL.RDB$RELATION_NAME EQ name.object.c_str() + SORTED BY REL.RDB$SCHEMA_NAME + { + const QualifiedMetaString relationName(REL.RDB$RELATION_NAME, REL.RDB$SCHEMA_NAME); + + if (name.schema.hasData() && name.schema != relationName.schema) + continue; - if (!REL.RDB$EXTERNAL_FILE.NULL) - isqlGlob.printf("External file: %s%s", REL.RDB$EXTERNAL_FILE, NEWLINE); - } - first = false; if ((isView && REL.RDB$VIEW_BLR.NULL) || (!isView && !REL.RDB$VIEW_BLR.NULL)) - first = true; - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return ps_ERR; - END_ERROR; + continue; - if (first) - return (OBJECT_NOT_FOUND); + first = false; - /* - FOR RFR IN RDB$RELATION_FIELDS CROSS - REL IN RDB$RELATIONS CROSS - FLD IN RDB$FIELDS WITH - RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND - RFR.RDB$RELATION_NAME EQ relation_name AND - REL.RDB$RELATION_NAME EQ RFR.RDB$RELATION_NAME - SORTED BY RFR.RDB$FIELD_POSITION, RFR.RDB$FIELD_NAME - */ + // FIXME: print name + + if (!REL.RDB$SQL_SECURITY.NULL) + { + const char* ss = REL.RDB$SQL_SECURITY ? "DEFINER" : "INVOKER"; + isqlGlob.printf("SQL SECURITY: %s%s", ss, NEWLINE); + } + + if (!REL.RDB$EXTERNAL_FILE.NULL) + isqlGlob.printf("External file: %s%s", REL.RDB$EXTERNAL_FILE, NEWLINE); + + // TODO: indent FOR RFR IN RDB$RELATION_FIELDS CROSS - FLD IN RDB$FIELDS WITH - RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND - RFR.RDB$RELATION_NAME EQ relation_name + FLD IN RDB$FIELDS + WITH FLD.RDB$SCHEMA_NAME EQUIV RFR.RDB$FIELD_SOURCE_SCHEMA_NAME AND + FLD.RDB$FIELD_NAME EQ RFR.RDB$FIELD_SOURCE AND + RFR.RDB$SCHEMA_NAME EQUIV NULLIF(relationName.schema.c_str(), '') AND + RFR.RDB$RELATION_NAME EQ relationName.object.c_str() SORTED BY RFR.RDB$FIELD_POSITION, RFR.RDB$FIELD_NAME + { + const QualifiedMetaString domainName(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME); + const MetaString columnName(RFR.RDB$FIELD_NAME); // Get length of colname to align columns for printing - fb_utils::exact_name(RFR.RDB$FIELD_NAME); - // Print the column name in first column - isqlGlob.printf("%-31s ", RFR.RDB$FIELD_NAME); + isqlGlob.printf("%-31s ", columnName.toQuotedString().c_str()); // Decide if this is a user-created domain if (!(fb_utils::implicit_domain(FLD.RDB$FIELD_NAME) && FLD.RDB$SYSTEM_FLAG != 1)) - { - fb_utils::exact_name(FLD.RDB$FIELD_NAME); - isqlGlob.printf("(%s) ", FLD.RDB$FIELD_NAME); - } + isqlGlob.printf("(%s) ", domainName.toQuotedString().c_str()); // Detect the existence of arrays if (!FLD.RDB$DIMENSIONS.NULL) { isqlGlob.printf("ARRAY OF "); - ISQL_array_dimensions (FLD.RDB$FIELD_NAME); + ISQL_array_dimensions(domainName); isqlGlob.printf("%s ", NEWLINE); } @@ -5994,7 +5854,7 @@ static processing_state show_table(const SCHAR* relation_name, bool isView) continue; } - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, + if (!ISQL_printNumericType(domainName, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) { return ps_ERR; @@ -6010,8 +5870,9 @@ static processing_state show_table(const SCHAR* relation_name, bool isView) else if (!FLD.RDB$COLLATION_ID.NULL) collation = FLD.RDB$COLLATION_ID; - if ((FLD.RDB$FIELD_TYPE == blr_text) || (FLD.RDB$FIELD_TYPE == blr_varying)) { - isqlGlob.printf("(%d)", ISQL_get_field_length(FLD.RDB$FIELD_NAME)); + if ((FLD.RDB$FIELD_TYPE == blr_text) || (FLD.RDB$FIELD_TYPE == blr_varying)) + { + isqlGlob.printf("(%d)", ISQL_get_field_length(domainName)); if (FLD.RDB$FIELD_SUB_TYPE != fb_text_subtype_binary) { @@ -6050,7 +5911,7 @@ static processing_state show_table(const SCHAR* relation_name, bool isView) // The null flag is either 1 or null (for nullable) if (RFR.RDB$NULL_FLAG == 1 || FLD.RDB$NULL_FLAG == 1 || - (!RFR.RDB$BASE_FIELD.NULL && !ISQL_get_null_flag (relation_name, RFR.RDB$FIELD_NAME))) + (!RFR.RDB$BASE_FIELD.NULL && !ISQL_get_null_flag(relationName, columnName))) { isqlGlob.printf(" Not Null "); } @@ -6081,30 +5942,21 @@ static processing_state show_table(const SCHAR* relation_name, bool isView) SHOW_print_metadata_text_blob (isqlGlob.Out, &FLD.RDB$VALIDATION_SOURCE); isqlGlob.printf(NEWLINE); } - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR // If this is a view and there were columns, print the view text - if (!first) + if (!REL.RDB$VIEW_BLR.NULL) { - FOR REL IN RDB$RELATIONS WITH - REL.RDB$RELATION_NAME EQ relation_name AND - REL.RDB$VIEW_BLR NOT MISSING - - isqlGlob.printf("View Source:%s==== ======%s", NEWLINE, NEWLINE); - if (!REL.RDB$VIEW_SOURCE.NULL) - SHOW_print_metadata_text_blob (isqlGlob.Out, &REL.RDB$VIEW_SOURCE); - isqlGlob.printf(NEWLINE); - END_FOR - ON_ERROR - ISQL_errmsg(fbStatus); - return ps_ERR; - END_ERROR; + isqlGlob.printf("View Source:%s==== ======%s", NEWLINE, NEWLINE); + if (!REL.RDB$VIEW_SOURCE.NULL) + SHOW_print_metadata_text_blob (isqlGlob.Out, &REL.RDB$VIEW_SOURCE); + isqlGlob.printf(NEWLINE); } // Handle any referential or primary constraint on this table @@ -6113,42 +5965,48 @@ static processing_state show_table(const SCHAR* relation_name, bool isView) // Static queries for obtaining referential constraints - FOR RELC1 IN RDB$RELATION_CONSTRAINTS WITH - RELC1.RDB$RELATION_NAME EQ relation_name + FOR RELC1 IN RDB$RELATION_CONSTRAINTS + WITH RELC1.RDB$SCHEMA_NAME EQUIV NULLIF(relationName.schema.c_str(), '') AND + RELC1.RDB$RELATION_NAME EQ relationName.object.c_str() SORTED BY RELC1.RDB$CONSTRAINT_TYPE, RELC1.RDB$CONSTRAINT_NAME + { + const QualifiedMetaString indexName1(RELC1.RDB$INDEX_NAME, RELC1.RDB$SCHEMA_NAME); + const MetaString constraintName(RELC1.RDB$CONSTRAINT_NAME); - fb_utils::exact_name(RELC1.RDB$CONSTRAINT_NAME); - fb_utils::exact_name(RELC1.RDB$INDEX_NAME); - ISQL_get_index_segments (collist, sizeof(collist), RELC1.RDB$INDEX_NAME, false); + ISQL_get_index_segments(collist, sizeof(collist), indexName1, false); bool isPK = false; bool isUK = false; if (!strncmp (RELC1.RDB$CONSTRAINT_TYPE, "PRIMARY", 7)) { isPK = true; - isqlGlob.printf("CONSTRAINT %s:%s", RELC1.RDB$CONSTRAINT_NAME, NEWLINE); + isqlGlob.printf("CONSTRAINT %s:%s", constraintName.toQuotedString().c_str(), NEWLINE); isqlGlob.printf(" Primary key (%s)", collist); } else if (!strncmp (RELC1.RDB$CONSTRAINT_TYPE, "UNIQUE", 6)) { isUK = true; - isqlGlob.printf("CONSTRAINT %s:%s", RELC1.RDB$CONSTRAINT_NAME, NEWLINE); + isqlGlob.printf("CONSTRAINT %s:%s", constraintName.toQuotedString().c_str(), NEWLINE); isqlGlob.printf(" Unique key (%s)", collist); } else if (!strncmp (RELC1.RDB$CONSTRAINT_TYPE, "FOREIGN", 7)) { - isqlGlob.printf("CONSTRAINT %s:%s", RELC1.RDB$CONSTRAINT_NAME, NEWLINE); + isqlGlob.printf("CONSTRAINT %s:%s", constraintName.toQuotedString().c_str(), NEWLINE); isqlGlob.printf(" Foreign key (%s)", collist); FOR RELC2 IN RDB$RELATION_CONSTRAINTS CROSS - REFC IN RDB$REF_CONSTRAINTS WITH - RELC2.RDB$CONSTRAINT_NAME EQ REFC.RDB$CONST_NAME_UQ AND - REFC.RDB$CONSTRAINT_NAME EQ RELC1.RDB$CONSTRAINT_NAME + REFC IN RDB$REF_CONSTRAINTS + WITH RELC2.RDB$SCHEMA_NAME EQUIV NULLIF(REFC.RDB$CONST_SCHEMA_NAME_UQ, '') AND + RELC2.RDB$CONSTRAINT_NAME EQ REFC.RDB$CONST_NAME_UQ AND + REFC.RDB$SCHEMA_NAME EQUIV NULLIF(RELC1.RDB$SCHEMA_NAME, '') AND + REFC.RDB$CONSTRAINT_NAME EQ RELC1.RDB$CONSTRAINT_NAME + { + const QualifiedMetaString indexName2(RELC2.RDB$INDEX_NAME, RELC2.RDB$SCHEMA_NAME); + const QualifiedMetaString referencesName(RELC2.RDB$RELATION_NAME, RELC2.RDB$SCHEMA_NAME); - ISQL_get_index_segments (collist, sizeof(collist), RELC2.RDB$INDEX_NAME, false); - fb_utils::exact_name(RELC2.RDB$RELATION_NAME); + ISQL_get_index_segments(collist, sizeof(collist), indexName2, false); - isqlGlob.printf(" References %s (%s)", RELC2.RDB$RELATION_NAME, collist); + isqlGlob.printf(" References %s (%s)", referencesName.toQuotedString().c_str(), collist); if (!REFC.RDB$UPDATE_RULE.NULL) { @@ -6163,33 +6021,7 @@ static processing_state show_table(const SCHAR* relation_name, bool isView) } isqlGlob.printf(NEWLINE); - - END_FOR - ON_ERROR - ISQL_errmsg (fbStatus); - return ps_ERR; - END_ERROR; - } - - if (isPK || isUK) // Special handling for PRIMARY KEY and UNIQUE constraints. - { - FOR IDX IN RDB$INDICES - WITH IDX.RDB$INDEX_NAME = RELC1.RDB$INDEX_NAME - // Yes, the same RDB$... naming convention is used for both domains and indices. - const bool explicit_index = - ((isPK && !fb_utils::implicit_pk(IDX.RDB$INDEX_NAME)) || - (isUK && !fb_utils::implicit_domain(RELC1.RDB$INDEX_NAME))) && - strcmp(RELC1.RDB$CONSTRAINT_NAME, RELC1.RDB$INDEX_NAME); - const bool descending_index = !IDX.RDB$INDEX_TYPE.NULL && IDX.RDB$INDEX_TYPE == 1; - if (explicit_index || descending_index) - { - isqlGlob.printf(" uses explicit %s index", - descending_index ? "descending" : "ascending"); - } - if (explicit_index) - isqlGlob.printf(" %s", RELC1.RDB$INDEX_NAME); - - isqlGlob.prints(NEWLINE); + } END_FOR ON_ERROR ISQL_errmsg (fbStatus); @@ -6197,6 +6029,36 @@ static processing_state show_table(const SCHAR* relation_name, bool isView) END_ERROR } + if (isPK || isUK) // Special handling for PRIMARY KEY and UNIQUE constraints. + { + FOR IDX IN RDB$INDICES + WITH IDX.RDB$SCHEMA_NAME EQUIV NULLIF(indexName1.schema.c_str(), '') AND + IDX.RDB$INDEX_NAME = indexName1.object.c_str() + { + // Yes, the same RDB$... naming convention is used for both domains and indices. + const bool explicit_index = + ((isPK && !fb_utils::implicit_pk(IDX.RDB$INDEX_NAME)) || + (isUK && !fb_utils::implicit_domain(indexName1.object.c_str()))) && + constraintName != indexName1.object; + const bool descending_index = !IDX.RDB$INDEX_TYPE.NULL && IDX.RDB$INDEX_TYPE == 1; + if (explicit_index || descending_index) + { + isqlGlob.printf(" uses explicit %s index", + descending_index ? "descending" : "ascending"); + } + + if (explicit_index) + isqlGlob.printf(" %s", indexName1.toQuotedString().c_str()); + + isqlGlob.prints(NEWLINE); + } + END_FOR + ON_ERROR + ISQL_errmsg (fbStatus); + return ps_ERR; + END_ERROR + } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -6205,42 +6067,58 @@ static processing_state show_table(const SCHAR* relation_name, bool isView) FOR R_C IN RDB$RELATION_CONSTRAINTS CROSS C_C IN RDB$CHECK_CONSTRAINTS - WITH R_C.RDB$RELATION_NAME EQ relation_name - AND R_C.RDB$CONSTRAINT_TYPE EQ 'NOT NULL' - AND R_C.RDB$CONSTRAINT_NAME EQ C_C.RDB$CONSTRAINT_NAME - + WITH R_C.RDB$SCHEMA_NAME EQUIV NULLIF(relationName.schema.c_str(), '') AND + R_C.RDB$RELATION_NAME EQ relationName.object.c_str() AND + R_C.RDB$CONSTRAINT_TYPE EQ 'NOT NULL' AND + R_C.RDB$SCHEMA_NAME EQUIV C_C.RDB$SCHEMA_NAME AND + R_C.RDB$CONSTRAINT_NAME EQ C_C.RDB$CONSTRAINT_NAME + { if (!fb_utils::implicit_integrity(R_C.RDB$CONSTRAINT_NAME)) { - fb_utils::exact_name(C_C.RDB$TRIGGER_NAME); - fb_utils::exact_name(R_C.RDB$CONSTRAINT_NAME); - isqlGlob.printf("CONSTRAINT %s:%s", R_C.RDB$CONSTRAINT_NAME, NEWLINE); - isqlGlob.printf(" Not Null Column (%s)%s", C_C.RDB$TRIGGER_NAME, NEWLINE); + isqlGlob.printf( + "CONSTRAINT %s:%s", + MetaString(R_C.RDB$CONSTRAINT_NAME).toQuotedString().c_str(), + NEWLINE); + + isqlGlob.printf( + " Not Null Column (%s)%s", + MetaString(C_C.RDB$TRIGGER_NAME).toQuotedString().c_str(), + NEWLINE); } + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR // Do check constraints - show_check(relation_name); + show_check(relationName); // Do triggers - show_trigger(relation_name, false, false); + show_trigger(relationName, false, false); // Do publications - show_pub_table(relation_name); + show_pub_table(relationName); + } + END_FOR + ON_ERROR + ISQL_errmsg(fbStatus); + return ps_ERR; + END_ERROR if (first) return (OBJECT_NOT_FOUND); + return SKIP; } -static processing_state show_trigger(const SCHAR* object, bool show_source, bool isTriggerName) +static processing_state show_trigger(const std::optional& name, + bool show_source, bool isTriggerName) { /************************************** * @@ -6255,7 +6133,7 @@ static processing_state show_trigger(const SCHAR* object, bool show_source, bool bool first = true; // Show all triggers - if (!*object) + if (!name) { bool has_dbtrig = false; @@ -6264,14 +6142,14 @@ static processing_state show_trigger(const SCHAR* object, bool show_source, bool FOR TRG IN RDB$TRIGGERS WITH (TRG.RDB$SYSTEM_FLAG EQ 0 OR TRG.RDB$SYSTEM_FLAG MISSING) AND TRG.RDB$RELATION_NAME MISSING - SORTED BY TRG.RDB$TRIGGER_NAME + SORTED BY TRG.RDB$SCHEMA_NAME, TRG.RDB$TRIGGER_NAME { + const QualifiedMetaString triggerName(TRG.RDB$TRIGGER_NAME, TRG.RDB$SCHEMA_NAME); + if (!has_dbtrig) has_dbtrig = true; - fb_utils::exact_name(TRG.RDB$TRIGGER_NAME); - - isqlGlob.printf("%s", TRG.RDB$TRIGGER_NAME); + isqlGlob.printf("%s", triggerName.toQuotedString().c_str()); if (TRG.RDB$SYSTEM_FLAG == 1) isqlGlob.printf("; System"); @@ -6285,16 +6163,18 @@ static processing_state show_trigger(const SCHAR* object, bool show_source, bool ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR } - FOR TRG IN RDB$TRIGGERS CROSS REL IN RDB$RELATIONS + FOR TRG IN RDB$TRIGGERS CROSS + REL IN RDB$RELATIONS //WITH (REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND //NOT (ANY CHK IN RDB$CHECK_CONSTRAINTS WITH // TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME) WITH (TRG.RDB$SYSTEM_FLAG EQ 0 OR TRG.RDB$SYSTEM_FLAG MISSING) AND - TRG.RDB$RELATION_NAME = REL.RDB$RELATION_NAME - SORTED BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_NAME + TRG.RDB$SCHEMA_NAME EQUIV REL.RDB$SCHEMA_NAME AND + TRG.RDB$RELATION_NAME = REL.RDB$RELATION_NAME + SORTED BY TRG.RDB$SCHEMA_NAME, TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_NAME { if (first) { @@ -6304,13 +6184,12 @@ static processing_state show_trigger(const SCHAR* object, bool show_source, bool first = false; } - fb_utils::exact_name(TRG.RDB$TRIGGER_NAME); - fb_utils::exact_name(TRG.RDB$RELATION_NAME); + const QualifiedMetaString triggerName(TRG.RDB$TRIGGER_NAME, TRG.RDB$SCHEMA_NAME); - isqlGlob.printf("%s", TRG.RDB$TRIGGER_NAME); + isqlGlob.printf("%s", triggerName.toQuotedString().c_str()); if (!TRG.RDB$RELATION_NAME.NULL) - isqlGlob.printf("; Table: %s", TRG.RDB$RELATION_NAME); + isqlGlob.printf("; Table: %s", MetaString(TRG.RDB$RELATION_NAME).toQuotedString().c_str()); if (TRG.RDB$SYSTEM_FLAG == 1) isqlGlob.printf("; System"); @@ -6324,7 +6203,7 @@ static processing_state show_trigger(const SCHAR* object, bool show_source, bool ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR if (first && !has_dbtrig) return OBJECT_NOT_FOUND; @@ -6334,49 +6213,31 @@ static processing_state show_trigger(const SCHAR* object, bool show_source, bool // Show triggers for the named object // and avoid check constraints - BASED_ON RDB$TRIGGERS.RDB$TRIGGER_NAME triggerName; - BASED_ON RDB$TRIGGERS.RDB$RELATION_NAME relationName; + MetaString triggerNameFilter, relationNameFilter; if (isTriggerName) - { - sprintf(triggerName, "%s", object); - relationName[0] = '\0'; - } + triggerNameFilter = name->object; else + relationNameFilter = name->object; + + FOR TRG IN RDB$TRIGGERS + WITH (TRG.RDB$RELATION_NAME EQ relationNameFilter.c_str() OR TRG.RDB$TRIGGER_NAME EQ triggerNameFilter.c_str()) AND + (TRG.RDB$SYSTEM_FLAG EQ 0 OR TRG.RDB$SYSTEM_FLAG MISSING) + SORTED BY TRG.RDB$SCHEMA_NAME, TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE, + TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME { - sprintf(relationName, "%s", object); - triggerName[0] = '\0'; - } + const QualifiedMetaString triggerName(TRG.RDB$TRIGGER_NAME, TRG.RDB$SCHEMA_NAME); - FOR TRG IN RDB$TRIGGERS WITH - (TRG.RDB$RELATION_NAME EQ relationName OR - TRG.RDB$TRIGGER_NAME EQ triggerName) AND - (TRG.RDB$SYSTEM_FLAG EQ 0 OR TRG.RDB$SYSTEM_FLAG MISSING) - SORTED BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE, - TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME - - //bool skip = false; - // Skip triggers for check constraints - //FOR FIRST 1 CHK IN RDB$CHECK_CONSTRAINTS WITH - // TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME - // skip = true; - //END_FOR - //ON_ERROR - // ISQL_errmsg (fbStatus); - // return ps_ERR; - //END_ERROR; - - //if (skip) - // continue; - fb_utils::exact_name(TRG.RDB$TRIGGER_NAME); + if (name->schema.hasData() && name->schema != triggerName.schema) + continue; if (first) { if (!TRG.RDB$RELATION_NAME.NULL) { - fb_utils::exact_name(TRG.RDB$RELATION_NAME); + const QualifiedMetaString relationName(TRG.RDB$RELATION_NAME, TRG.RDB$SCHEMA_NAME); - isqlGlob.printf("%sTriggers on Table %s:%s", NEWLINE, TRG.RDB$RELATION_NAME, NEWLINE); + isqlGlob.printf("%sTriggers on Table %s:%s", NEWLINE, relationName.toQuotedString().c_str(), NEWLINE); } first = false; @@ -6386,7 +6247,7 @@ static processing_state show_trigger(const SCHAR* object, bool show_source, bool (TRG.RDB$SQL_SECURITY ? ", SQL SECURITY DEFINER" : ", SQL SECURITY INVOKER"); isqlGlob.printf("%s, Sequence: %d, Type: %s, %s%s%s", - TRG.RDB$TRIGGER_NAME, + triggerName.toQuotedString().c_str(), TRG.RDB$TRIGGER_SEQUENCE, SHOW_trigger_action(TRG.RDB$TRIGGER_TYPE).c_str(), (TRG.RDB$TRIGGER_INACTIVE ? "Inactive" : "Active"), @@ -6417,14 +6278,16 @@ static processing_state show_trigger(const SCHAR* object, bool show_source, bool isqlGlob.printf("%s=============================================================================%s", NEWLINE, NEWLINE); } } - + } END_FOR ON_ERROR ISQL_errmsg(fbStatus); return ps_ERR; - END_ERROR; + END_ERROR + if (first) return OBJECT_NOT_FOUND; + return SKIP; } @@ -6441,13 +6304,17 @@ static processing_state show_users12() * **************************************/ - const char* getusers = "select " + string sql; + sql.printf( + "select " "case when coalesce(MON$USER, SEC$USER_NAME) = current_user then '#' " "when SEC$USER_NAME is distinct from null then ' ' else '-' end, " "coalesce(MON$USER, SEC$USER_NAME), count(MON$USER) " - "from mon$attachments m full join sec$users u on m.MON$USER = u.SEC$USER_NAME " + "from %smon$attachments m full join %ssec$users u on m.MON$USER = u.SEC$USER_NAME " "where coalesce(MON$SYSTEM_FLAG, 0) = 0 " - "group by MON$USER, SEC$USER_NAME order by coalesce(MON$USER, SEC$USER_NAME)"; + "group by MON$USER, SEC$USER_NAME order by coalesce(MON$USER, SEC$USER_NAME)", + (isqlGlob.major_ods >= ODS_VERSION14 ? "SYSTEM." : ""), + (isqlGlob.major_ods >= ODS_VERSION14 ? "SYSTEM." : "")); Firebird::RefPtr mb(Firebird::REF_NO_INCR, fbMaster->getMetadataBuilder(fbStatus, 3)); @@ -6490,7 +6357,7 @@ static processing_state show_users12() if (ISQL_errmsg (fbStatus)) return ps_ERR; - Firebird::IResultSet* rs = DB->openCursor(fbStatus, fbTrans, 0, getusers, isqlGlob.SQL_dialect, + Firebird::IResultSet* rs = DB->openCursor(fbStatus, fbTrans, 0, sql.c_str(), isqlGlob.SQL_dialect, NULL, NULL, outMetadata, NULL, 0); if (ISQL_errmsg (fbStatus)) return ps_ERR; @@ -6566,9 +6433,11 @@ static processing_state show_users() return ps_ERR; vary* my_user = (vary*) &outBuffer[off]; - const char* getuser = isqlGlob.major_ods < ODS_VERSION10 ? - "select user from rdb$database" : "select current_user from rdb$database"; - DB->execute(fbStatus, fbTrans, 0, getuser, isqlGlob.SQL_dialect, + string getuser; + getuser.printf( + "select current_user from %srdb$database", + (isqlGlob.major_ods >= ODS_VERSION14 ? "SYSTEM." : "")); + DB->execute(fbStatus, fbTrans, 0, getuser.c_str(), isqlGlob.SQL_dialect, NULL, NULL, outMetadata, outBuffer); if (ISQL_errmsg (fbStatus)) return OBJECT_NOT_FOUND; diff --git a/src/isql/show_proto.h b/src/isql/show_proto.h index bbbe704e8e..bb35050db3 100644 --- a/src/isql/show_proto.h +++ b/src/isql/show_proto.h @@ -25,22 +25,23 @@ #define ISQL_SHOW_PROTO_H #include "../common/classes/fb_string.h" +#include "../common/classes/QualifiedMetaString.h" #include #include "../isql/FrontendParser.h" #include "../jrd/obj.h" +#include void SHOW_comments(bool force); void SHOW_dbb_parameters (Firebird::IAttachment*, const UCHAR*, unsigned, bool, const char*); -processing_state SHOW_grants (const SCHAR*, const SCHAR*, ObjectType); -processing_state SHOW_grants2 (const SCHAR*, const SCHAR*, ObjectType, const TEXT*, bool); -void SHOW_grant_roles (const SCHAR*, bool*); -void SHOW_grant_roles2 (const SCHAR*, bool*, const TEXT*, bool); +processing_state SHOW_grants(const std::optional&, const SCHAR*, ObjectType); +processing_state SHOW_grants2(const Firebird::QualifiedMetaString&, const SCHAR*, ObjectType, const TEXT*, bool); +void SHOW_grant_roles(const SCHAR*, bool*, const TEXT*, bool); void SHOW_print_metadata_text_blob(FILE*, ISC_QUAD*, bool escape_squote = false, bool avoid_end_in_single_line_comment = false); processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node); void SHOW_read_owner(); const Firebird::string SHOW_trigger_action(SINT64); -processing_state SHOW_maps(bool extract, const SCHAR* map_name); -bool SHOW_system_privileges(const char* role, const char* prfx, bool lf); +processing_state SHOW_maps(bool extract, const std::optional& name); +bool SHOW_system_privileges(const Firebird::MetaString& name, const char* prfx, bool lf); #endif // ISQL_SHOW_PROTO_H diff --git a/src/isql/tests/FrontendParserTest.cpp b/src/isql/tests/FrontendParserTest.cpp index 61a571dfdb..399f38cf04 100644 --- a/src/isql/tests/FrontendParserTest.cpp +++ b/src/isql/tests/FrontendParserTest.cpp @@ -40,9 +40,9 @@ BOOST_AUTO_TEST_CASE(ParseCommandTest) BOOST_TEST(std::holds_alternative(FrontendParser::parse( "add", parserOptions))); BOOST_TEST((std::get(FrontendParser::parse( - "add table1", parserOptions)).tableName == "TABLE1")); + "add table1", parserOptions)).tableName == QualifiedMetaString("TABLE1"))); BOOST_TEST((std::get(FrontendParser::parse( - "add \"table2\"", parserOptions)).tableName == "table2")); + "add \"table2\"", parserOptions)).tableName == QualifiedMetaString("table2"))); BOOST_TEST(std::holds_alternative(FrontendParser::parse( "blobdump", parserOptions))); @@ -91,8 +91,8 @@ BOOST_AUTO_TEST_CASE(ParseCommandTest) { const auto copy1 = std::get(FrontendParser::parse( "copy source \"destination\" localhost:/tmp/database.fdb", parserOptions)); - BOOST_TEST((copy1.source == "SOURCE")); - BOOST_TEST((copy1.destination == "destination")); + BOOST_TEST((copy1.source == QualifiedMetaString("SOURCE"))); + BOOST_TEST((copy1.destination == QualifiedMetaString("destination"))); BOOST_TEST(copy1.database == "localhost:/tmp/database.fdb"); } @@ -300,7 +300,7 @@ BOOST_AUTO_TEST_CASE(ParseSetTest) BOOST_TEST(!std::get(parseSet( "set names")).name.has_value()); BOOST_TEST((std::get(parseSet( - "set names utf8")).name == "UTF8")); + "set names utf8")).name == QualifiedMetaString("UTF8"))); BOOST_TEST(std::holds_alternative(FrontendParser::parse( "set names utf8 x", parserOptions))); @@ -489,17 +489,17 @@ BOOST_AUTO_TEST_CASE(ParseShowTest) BOOST_TEST(!std::get(parseShow( "show check")).name); BOOST_TEST((std::get(parseShow( - "show check name")).name == "NAME")); + "show check name")).name == QualifiedMetaString("NAME"))); BOOST_TEST(!std::get(parseShow( "show collate")).name); BOOST_TEST((std::get(parseShow( - "show collate name")).name == "NAME")); + "show collate name")).name == QualifiedMetaString("NAME"))); BOOST_TEST(!std::get(parseShow( "show collation")).name); BOOST_TEST((std::get(parseShow( - "show collation name")).name == "NAME")); + "show collation name")).name == QualifiedMetaString("NAME"))); BOOST_TEST(std::holds_alternative(parseShow( "show comments"))); @@ -507,17 +507,17 @@ BOOST_AUTO_TEST_CASE(ParseShowTest) BOOST_TEST(!std::get(parseShow( "show depen")).name); BOOST_TEST((std::get(parseShow( - "show depen name")).name == "NAME")); + "show depen name")).name == QualifiedMetaString("NAME"))); BOOST_TEST(!std::get(parseShow( "show domain")).name); BOOST_TEST((std::get(parseShow( - "show domain name")).name == "NAME")); + "show domain name")).name == QualifiedMetaString("NAME"))); BOOST_TEST(!std::get(parseShow( "show excep")).name); BOOST_TEST((std::get(parseShow( - "show excep name")).name == "NAME")); + "show excep name")).name == QualifiedMetaString("NAME"))); BOOST_TEST(!std::get(parseShow( "show filter")).name); @@ -527,23 +527,25 @@ BOOST_AUTO_TEST_CASE(ParseShowTest) BOOST_TEST(!std::get(parseShow( "show func")).name); BOOST_TEST((std::get(parseShow( - "show func name")).name == "NAME")); + "show func name")).name == QualifiedMetaString("NAME"))); + /* FIXME: BOOST_TEST((std::get(parseShow( "show func package.name")).package == "PACKAGE")); BOOST_TEST((std::get(parseShow( - "show func package.name")).name == "NAME")); + "show func package.name")).name == QualifiedMetaString("NAME"))); + */ BOOST_TEST(!std::get(parseShow( "show ind")).name); BOOST_TEST((std::get(parseShow( - "show index name")).name == "NAME")); + "show index name")).name == QualifiedMetaString("NAME"))); BOOST_TEST((std::get(parseShow( - "show indices name")).name == "NAME")); + "show indices name")).name == QualifiedMetaString("NAME"))); BOOST_TEST(!std::get(parseShow( "show gen")).name); BOOST_TEST((std::get(parseShow( - "show generator name")).name == "NAME")); + "show generator name")).name == QualifiedMetaString("NAME"))); BOOST_TEST(!std::get(parseShow( "show map")).name); @@ -553,16 +555,18 @@ BOOST_AUTO_TEST_CASE(ParseShowTest) BOOST_TEST(!std::get(parseShow( "show pack")).name); BOOST_TEST((std::get(parseShow( - "show package name")).name == "NAME")); + "show package name")).name == QualifiedMetaString("NAME"))); BOOST_TEST(!std::get(parseShow( "show proc")).name); BOOST_TEST((std::get(parseShow( - "show proc name")).name == "NAME")); + "show proc name")).name == QualifiedMetaString("NAME"))); + /* FIXME: BOOST_TEST((std::get(parseShow( "show proc package.name")).package == "PACKAGE")); BOOST_TEST((std::get(parseShow( - "show proc package.name")).name == "NAME")); + "show proc package.name")).name == QualifiedMetaString("NAME"))); + */ BOOST_TEST(!std::get(parseShow( "show pub")).name); @@ -583,31 +587,31 @@ BOOST_AUTO_TEST_CASE(ParseShowTest) BOOST_TEST(!std::get(parseShow( "show seccla * detail")).name); BOOST_TEST((std::get(parseShow( - "show secclasses name")).name == "NAME")); + "show secclasses name")).name == QualifiedMetaString("NAME"))); BOOST_TEST((!std::get(parseShow( "show system")).objType.has_value())); BOOST_TEST((!std::get(parseShow( "show system table")).objType == obj_relation)); BOOST_TEST((std::get(parseShow( - "show table \"test\"")).name == "test")); + "show table \"test\"")).name == QualifiedMetaString("test"))); BOOST_TEST((std::get(parseShow( - "show table \"te\"\"st\"")).name == "te\"st")); + "show table \"te\"\"st\"")).name == QualifiedMetaString("te\"st"))); BOOST_TEST(!std::get(parseShow( "show table")).name); BOOST_TEST((std::get(parseShow( - "show tables name")).name == "NAME")); + "show tables name")).name == QualifiedMetaString("NAME"))); BOOST_TEST(!std::get(parseShow( "show trig")).name); BOOST_TEST((std::get(parseShow( - "show triggers name")).name == "NAME")); + "show triggers name")).name == QualifiedMetaString("NAME"))); BOOST_TEST(!std::get(parseShow( "show view")).name); BOOST_TEST((std::get(parseShow( - "show views name")).name == "NAME")); + "show views name")).name == QualifiedMetaString("NAME"))); BOOST_TEST(std::holds_alternative(parseShow( "show wire_stat"))); diff --git a/src/jrd/Attachment.cpp b/src/jrd/Attachment.cpp index a30facf742..1b57bf1e45 100644 --- a/src/jrd/Attachment.cpp +++ b/src/jrd/Attachment.cpp @@ -258,6 +258,7 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb, JProvider* provider att_dest_bind(&att_bindings), att_original_timezone(TimeZoneUtil::getSystemTimeZone()), att_current_timezone(att_original_timezone), + att_schema_search_path(FB_NEW_POOL(*pool) AnyRef>(*pool)), att_parallel_workers(0), att_repl_appliers(*pool), att_utility(UTIL_NONE), @@ -368,31 +369,6 @@ MetaName Jrd::Attachment::nameToUserCharSet(thread_db* tdbb, const MetaName& nam } -string Jrd::Attachment::stringToMetaCharSet(thread_db* tdbb, const string& str, - const char* charSet) -{ - USHORT charSetId = att_charset; - - if (charSet) - { - if (!MET_get_char_coll_subtype(tdbb, &charSetId, (const UCHAR*) charSet, - static_cast(strlen(charSet)))) - { - (Arg::Gds(isc_charset_not_found) << Arg::Str(charSet)).raise(); - } - } - - if (charSetId == CS_METADATA || charSetId == CS_NONE) - return str; - - HalfStaticArray buffer(str.length() * sizeof(ULONG)); - ULONG len = INTL_convert_bytes(tdbb, CS_METADATA, buffer.begin(), buffer.getCapacity(), - charSetId, (const BYTE*) str.c_str(), str.length(), ERR_post); - - return string((char*) buffer.begin(), len); -} - - string Jrd::Attachment::stringToUserCharSet(thread_db* tdbb, const string& str) { if (att_charset == CS_METADATA || att_charset == CS_NONE) @@ -1231,3 +1207,36 @@ void Attachment::releaseProfilerManager(thread_db* tdbb) else att_profiler_manager.reset(); } + +bool Attachment::qualifyNewName(thread_db* tdbb, QualifiedName& name, ObjectsArray* schemaSearchPath) +{ + if (!schemaSearchPath) + schemaSearchPath = att_schema_search_path; + + if (name.schema.isEmpty() && schemaSearchPath->hasData()) + { + for (const auto& searchSchema : *schemaSearchPath) + { + if (MET_check_schema_exists(tdbb, searchSchema)) + { + name.schema = searchSchema; + return true; + } + } + } + + return MET_check_schema_exists(tdbb, name.schema); +} + +void Attachment::qualifyExistingName(thread_db* tdbb, QualifiedName& name, ObjectType objType, + ObjectsArray* schemaSearchPath) +{ + if (name.object.hasData()) + { + if (name.schema.isEmpty()) + { + if (!MET_qualify_existing_name(tdbb, name, objType, schemaSearchPath)) + qualifyNewName(tdbb, name, schemaSearchPath); + } + } +} diff --git a/src/jrd/Attachment.h b/src/jrd/Attachment.h index c5cd453876..db27c0bc7b 100644 --- a/src/jrd/Attachment.h +++ b/src/jrd/Attachment.h @@ -116,7 +116,7 @@ struct DSqlCacheItem } Firebird::string key; - Firebird::GenericMap > > obsoleteMap; + Firebird::LeftPooledMap obsoleteMap; Lock* lock; bool locked; }; @@ -139,9 +139,9 @@ struct DdlTriggerContext Firebird::string eventType; Firebird::string objectType; - MetaName objectName; - MetaName oldObjectName; - MetaName newObjectName; + QualifiedName objectName; + QualifiedName oldObjectName; + QualifiedName newObjectName; Firebird::string sqlText; }; @@ -173,6 +173,7 @@ const ULONG ATT_repl_reset = 0x200000L; // Replication set has been reset const ULONG ATT_replicating = 0x400000L; // Replication is active const ULONG ATT_resetting = 0x800000L; // Session reset is in progress const ULONG ATT_worker = 0x1000000L; // Worker attachment, managed by the engine +const ULONG ATT_gbak_restore_has_schema = 0x2000000L; const ULONG ATT_NO_CLEANUP = (ATT_no_cleanup | ATT_notify_gc); @@ -443,14 +444,14 @@ public: : m_objects(pool) {} - void store(SLONG id, const MetaName& name) + void store(SLONG id, const QualifiedName& name) { fb_assert(id >= 0); - fb_assert(name.hasData()); + fb_assert(name.object.hasData()); if (id < (int) m_objects.getCount()) { - fb_assert(m_objects[id].isEmpty()); + fb_assert(m_objects[id].object.isEmpty()); m_objects[id] = name; } else @@ -460,9 +461,9 @@ public: } } - bool lookup(SLONG id, MetaName& name) + bool lookup(SLONG id, QualifiedName& name) { - if (id < (int) m_objects.getCount() && m_objects[id].hasData()) + if (id < (int) m_objects.getCount() && m_objects[id].object.hasData()) { name = m_objects[id]; return true; @@ -471,7 +472,7 @@ public: return false; } - SLONG lookup(const MetaName& name) + SLONG lookup(const QualifiedName& name) { FB_SIZE_T pos; @@ -482,14 +483,17 @@ public: } private: - Firebird::Array m_objects; + Firebird::Array m_objects; }; class InitialOptions { public: - InitialOptions(MemoryPool& p) - : bindings(p) + InitialOptions(MemoryPool& pool) + : bindings(pool), + schemaSearchPath(FB_NEW_POOL(pool) Firebird::AnyRef>(pool)), + blrRequestSchemaSearchPath( + FB_NEW_POOL(pool) Firebird::AnyRef>(pool)) { } @@ -510,7 +514,8 @@ public: private: Firebird::DecimalStatus decFloatStatus = Firebird::DecimalStatus::DEFAULT; CoercionArray bindings; - + Firebird::RefPtr>> schemaSearchPath; + Firebird::RefPtr>> blrRequestSchemaSearchPath; USHORT originalTimeZone = Firebird::TimeZoneUtil::GMT_ZONE; }; @@ -642,6 +647,8 @@ public: CoercionArray* att_dest_bind; USHORT att_original_timezone; USHORT att_current_timezone; + Firebird::RefPtr>> att_schema_search_path; + Firebird::RefPtr>> att_blr_request_schema_search_path; int att_parallel_workers; Firebird::TriState att_opt_first_rows; @@ -673,8 +680,7 @@ public: Request* findSystemRequest(thread_db* tdbb, USHORT id, USHORT which); Firebird::Array att_charsets; // intl character set descriptions - Firebird::GenericMap > > att_charset_ids; // Character set ids + Firebird::GenericMap>> att_charset_ids; // Character set ids void releaseIntlObjects(thread_db* tdbb); // defined in intl.cpp void destroyIntlObjects(thread_db* tdbb); // defined in intl.cpp @@ -725,8 +731,6 @@ public: MetaName nameToMetaCharSet(thread_db* tdbb, const MetaName& name); MetaName nameToUserCharSet(thread_db* tdbb, const MetaName& name); - Firebird::string stringToMetaCharSet(thread_db* tdbb, const Firebird::string& str, - const char* charSet = NULL); Firebird::string stringToUserCharSet(thread_db* tdbb, const Firebird::string& str); void storeMetaDataBlob(thread_db* tdbb, jrd_tra* transaction, @@ -857,6 +861,12 @@ public: return att_provider; } + bool qualifyNewName(thread_db* tdbb, QualifiedName& name, + Firebird::ObjectsArray* schemaSearchPath = nullptr); + + void qualifyExistingName(thread_db* tdbb, QualifiedName& name, ObjectType objType, + Firebird::ObjectsArray* schemaSearchPath = nullptr); + private: Attachment(MemoryPool* pool, Database* dbb, JProvider* provider); ~Attachment(); diff --git a/src/jrd/Database.cpp b/src/jrd/Database.cpp index c88b61171d..ad3de52010 100644 --- a/src/jrd/Database.cpp +++ b/src/jrd/Database.cpp @@ -412,7 +412,7 @@ namespace Jrd Lock(tdbb, 0, LCK_repl_state, this, replStateAst); } - dbb_repl_state = MET_get_repl_state(tdbb, ""); + dbb_repl_state = MET_get_repl_state(tdbb, {}); fb_assert(dbb_repl_lock->lck_logical == LCK_none); LCK_lock(tdbb, dbb_repl_lock, LCK_SR, LCK_WAIT); diff --git a/src/jrd/DbCreators.cpp b/src/jrd/DbCreators.cpp index d075b4ed21..471909bc8c 100644 --- a/src/jrd/DbCreators.cpp +++ b/src/jrd/DbCreators.cpp @@ -138,7 +138,7 @@ CreateGrant checkCreateDatabaseGrant(const MetaString& userName, const MetaStrin UserId::makeRoleName(role, dialect); // We need to check is role granted to userName in security DB - const char* sql = "select count(*) from RDB$USER_PRIVILEGES " + const char* sql = "select count(*) from SYSTEM.RDB$USER_PRIVILEGES " "where RDB$USER = ? and RDB$RELATION_NAME = ? and RDB$PRIVILEGE = 'M'"; Message prm; @@ -189,7 +189,7 @@ CreateGrant checkCreateDatabaseGrant(const MetaString& userName, const MetaStrin Field cnt(result); att->execute(&st, tra, 0, - "select count(*) from RDB$DB_CREATORS" + "select count(*) from SYSTEM.RDB$DB_CREATORS" " where (RDB$USER_TYPE = ? and RDB$USER = ?) or (RDB$USER_TYPE = ? and RDB$USER = ?)", SQL_DIALECT_V6, gr.getMetadata(), gr.getBuffer(), result.getMetadata(), result.getBuffer()); if (st->getState() & IStatus::STATE_ERRORS) @@ -222,17 +222,17 @@ CreateGrant checkCreateDatabaseGrant(const MetaString& userName, const MetaStrin const char* sql = "with recursive role_tree as ( " - " select rdb$relation_name as nm, 0 as ur from rdb$user_privileges " + " select rdb$relation_name as nm, 0 as ur from system.rdb$user_privileges " " where rdb$privilege = 'M' and rdb$field_name = 'D' and rdb$user_type = ? and rdb$user = ? " " union all " - " select rdb$role_name as nm, 1 as ur from rdb$roles " + " select rdb$role_name as nm, 1 as ur from system.rdb$roles " " where rdb$role_name = ? " " union all " - " select p.rdb$relation_name as nm, t.ur from rdb$user_privileges p " + " select p.rdb$relation_name as nm, t.ur from system.rdb$user_privileges p " " join role_tree t on t.nm = p.rdb$user " " where p.rdb$privilege = 'M' and (p.rdb$field_name = 'D' or t.ur = 1)) " "select r.rdb$system_privileges " - " from role_tree t join rdb$roles r on t.nm = r.rdb$role_name "; + " from role_tree t join system.rdb$roles r on t.nm = r.rdb$role_name "; RefPtr rs(REF_NO_INCR, att->openCursor(&st, tra, 0, sql, SQL_DIALECT_V6, par2.getMetadata(), par2.getBuffer(), res2.getMetadata(), NULL, 0)); check("IAttachment::execute", &st); @@ -304,7 +304,7 @@ RecordBuffer* DbCreatorsList::getList(thread_db* tdbb, jrd_rel* relation) FbLocalStatus st; RefPtr curs(REF_NO_INCR, att->openCursor(&st, tra, 0, - "select RDB$USER_TYPE, RDB$USER from RDB$DB_CREATORS", + "select RDB$USER_TYPE, RDB$USER from SYSTEM.RDB$DB_CREATORS", SQL_DIALECT_V6, NULL, NULL, gr.getMetadata(), NULL, 0)); if (st->getState() & IStatus::STATE_ERRORS) diff --git a/src/jrd/ExtEngineManager.cpp b/src/jrd/ExtEngineManager.cpp index 8f28a59fcc..5a282974b3 100644 --- a/src/jrd/ExtEngineManager.cpp +++ b/src/jrd/ExtEngineManager.cpp @@ -141,19 +141,19 @@ namespace const Parameter* param = parameters[index / 2]; if (param->prm_mechanism != prm_mech_type_of && - !fb_utils::implicit_domain(param->prm_field_source.c_str())) + !fb_utils::implicit_domain(param->prm_field_source.object.c_str())) { - MetaNamePair namePair(param->prm_field_source, ""); + QualifiedNameMetaNamePair entry(param->prm_field_source, {}); FieldInfo fieldInfo; - bool exist = csb->csb_map_field_info.get(namePair, fieldInfo); + bool exist = csb->csb_map_field_info.get(entry, fieldInfo); MET_get_domain(tdbb, csb->csb_pool, param->prm_field_source, desc, (exist ? NULL : &fieldInfo)); if (!exist) - csb->csb_map_field_info.put(namePair, fieldInfo); + csb->csb_map_field_info.put(entry, fieldInfo); - itemInfo->field = namePair; + itemInfo->field = entry; itemInfo->nullable = fieldInfo.nullable; itemInfo->fullDomain = true; } @@ -226,12 +226,12 @@ namespace const auto parameter = parameters[paramIndex]; if (parameter->prm_mechanism != prm_mech_type_of && - !fb_utils::implicit_domain(parameter->prm_field_source.c_str())) + !fb_utils::implicit_domain(parameter->prm_field_source.object.c_str())) { - MetaNamePair namePair(parameter->prm_field_source, ""); + QualifiedNameMetaNamePair entry(parameter->prm_field_source, {}); FieldInfo fieldInfo; - bool exist = csb->csb_map_field_info.get(namePair, fieldInfo); + bool exist = csb->csb_map_field_info.get(entry, fieldInfo); if (exist && fieldInfo.defaultValue) defaultValuesNode->items[paramIndex] = CMP_clone_node(tdbb, csb, fieldInfo.defaultValue); @@ -583,24 +583,29 @@ private: if (!obj) return; - char charSetName[MAX_SQL_IDENTIFIER_SIZE]; + QualifiedName charSetName; { // scope + char charSetNameBuffer[MAX_QUALIFIED_NAME_TO_STRING_LEN]; + EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine)); FbLocalStatus status; - obj->getCharSet(&status, attInfo->context, charSetName, MAX_SQL_IDENTIFIER_LEN); + obj->getCharSet(&status, attInfo->context, charSetNameBuffer, sizeof(charSetNameBuffer)); status.check(); - charSetName[MAX_SQL_IDENTIFIER_LEN] = '\0'; + charSetNameBuffer[sizeof(charSetNameBuffer) - 1] = '\0'; + + if (charSetNameBuffer[0]) + { + charSetName = QualifiedName::parseSchemaObject(charSetNameBuffer); + attachment->qualifyExistingName(tdbb, charSetName, obj_charset); + } } USHORT charSetId; - if (!MET_get_char_coll_subtype(tdbb, &charSetId, - reinterpret_cast(charSetName), static_cast(strlen(charSetName)))) - { - status_exception::raise(Arg::Gds(isc_charset_not_found) << Arg::Str(charSetName)); - } + if (!MET_get_char_coll_subtype(tdbb, &charSetId, charSetName)) + status_exception::raise(Arg::Gds(isc_charset_not_found) << charSetName.toQuotedString()); attachment->att_charset = charSetId; } @@ -808,19 +813,19 @@ ExtEngineManager::Function::Function(thread_db* tdbb, MemoryPool& pool, Compiler ItemInfo itemInfo; if (param->prm_mechanism != prm_mech_type_of && - !fb_utils::implicit_domain(param->prm_field_source.c_str())) + !fb_utils::implicit_domain(param->prm_field_source.object.c_str())) { - const MetaNamePair namePair(param->prm_field_source, ""); - const bool exist = csb->csb_map_field_info.get(namePair, fieldInfo); + const QualifiedNameMetaNamePair entry(param->prm_field_source, {}); + const bool exist = csb->csb_map_field_info.get(entry, fieldInfo); if (!exist) { dsc dummyDesc; MET_get_domain(tdbb, csb->csb_pool, param->prm_field_source, &dummyDesc, &fieldInfo); - csb->csb_map_field_info.put(namePair, fieldInfo); + csb->csb_map_field_info.put(entry, fieldInfo); } - itemInfo.field = namePair; + itemInfo.field = entry; itemInfo.nullable = fieldInfo.nullable; itemInfo.fullDomain = true; } @@ -847,16 +852,16 @@ ExtEngineManager::Function::Function(thread_db* tdbb, MemoryPool& pool, Compiler ItemInfo itemInfo; if (param->prm_mechanism != prm_mech_type_of && - !fb_utils::implicit_domain(param->prm_field_source.c_str())) + !fb_utils::implicit_domain(param->prm_field_source.object.c_str())) { - const MetaNamePair namePair(param->prm_field_source, ""); - const bool exist = csb->csb_map_field_info.get(namePair, fieldInfo); + const QualifiedNameMetaNamePair entry(param->prm_field_source, {}); + const bool exist = csb->csb_map_field_info.get(entry, fieldInfo); if (!exist) { dsc dummyDesc; MET_get_domain(tdbb, csb->csb_pool, param->prm_field_source, &dummyDesc, &fieldInfo); - csb->csb_map_field_info.put(namePair, fieldInfo); + csb->csb_map_field_info.put(entry, fieldInfo); } if (fieldInfo.defaultValue) @@ -865,7 +870,7 @@ ExtEngineManager::Function::Function(thread_db* tdbb, MemoryPool& pool, Compiler impl->outDefaults.push(param->prm_number); } - itemInfo.field = namePair; + itemInfo.field = entry; itemInfo.nullable = fieldInfo.nullable; itemInfo.fullDomain = true; } @@ -923,12 +928,12 @@ void ExtEngineManager::Function::execute(thread_db* tdbb, Request* request, jrd_ for (const auto paramNumber : impl->outDefaults) { const auto param = udf->getOutputFields()[paramNumber]; - const MetaNamePair namePair(param->prm_field_source, ""); + const QualifiedNameMetaNamePair entry(param->prm_field_source, {}); FieldInfo fieldInfo; dsc* defaultValue = nullptr; - if (request->getStatement()->mapFieldInfo.get(namePair, fieldInfo) && fieldInfo.defaultValue) + if (request->getStatement()->mapFieldInfo.get(entry, fieldInfo) && fieldInfo.defaultValue) defaultValue = EVL_expr(tdbb, request, fieldInfo.defaultValue); const auto& paramDesc = udf->getOutputFormat()->fmt_desc[paramNumber * 2]; @@ -962,8 +967,8 @@ void ExtEngineManager::Function::execute(thread_db* tdbb, Request* request, jrd_ const MetaString& userName = udf->invoker ? udf->invoker->getUserName() : ""; ContextManager ctxManager(tdbb, attInfo, function, (udf->getName().package.isEmpty() ? - CallerName(obj_udf, udf->getName().identifier, userName) : - CallerName(obj_package_header, udf->getName().package, userName))); + CallerName(obj_udf, udf->getName(), userName) : + CallerName(obj_package_header, QualifiedName(udf->getName().package, udf->getName().schema), userName))); EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine)); @@ -1044,8 +1049,9 @@ ExtEngineManager::ResultSet::ResultSet(thread_db* tdbb, UCHAR* inMsg, UCHAR* out const MetaString& userName = procedure->prc->invoker ? procedure->prc->invoker->getUserName() : ""; ContextManager ctxManager(tdbb, attInfo, procedure->procedure, (procedure->prc->getName().package.isEmpty() ? - CallerName(obj_procedure, procedure->prc->getName().identifier, userName) : - CallerName(obj_package_header, procedure->prc->getName().package, userName))); + CallerName(obj_procedure, procedure->prc->getName(), userName) : + CallerName(obj_package_header, + QualifiedName(procedure->prc->getName().package, procedure->prc->getName().schema), userName))); charSet = attachment->att_charset; @@ -1078,8 +1084,9 @@ bool ExtEngineManager::ResultSet::fetch(thread_db* tdbb) const MetaString& userName = procedure->prc->invoker ? procedure->prc->invoker->getUserName() : ""; ContextManager ctxManager(tdbb, attInfo, charSet, (procedure->prc->getName().package.isEmpty() ? - CallerName(obj_procedure, procedure->prc->getName().identifier, userName) : - CallerName(obj_package_header, procedure->prc->getName().package, userName))); + CallerName(obj_procedure, procedure->prc->getName(), userName) : + CallerName(obj_package_header, + QualifiedName(procedure->prc->getName().package, procedure->prc->getName().schema), userName))); EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine)); @@ -1546,14 +1553,13 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd:: const MetaString& userName = udf->invoker ? udf->invoker->getUserName() : ""; ContextManager ctxManager(tdbb, attInfo, attInfo->adminCharSet, (udf->getName().package.isEmpty() ? - CallerName(obj_udf, udf->getName().identifier, userName) : - CallerName(obj_package_header, udf->getName().package, userName))); + CallerName(obj_udf, udf->getName(), userName) : + CallerName(obj_package_header, QualifiedName(udf->getName().package, udf->getName().schema), userName))); MemoryPool& pool = *tdbb->getAttachment()->att_pool; AutoPtr metadata(FB_NEW_POOL(pool) RoutineMetadata(pool)); - metadata->package = udf->getName().package; - metadata->name = udf->getName().identifier; + metadata->name = udf->getName(); metadata->entryPoint = entryPointTrimmed; metadata->body = body; metadata->inputParameters.assignRefNoIncr(Routine::createMetadata(udf->getInputFields(), true)); @@ -1586,7 +1592,7 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd:: if (!externalFunction) { status_exception::raise( - Arg::Gds(isc_eem_func_not_returned) << udf->getName().toString() << engine); + Arg::Gds(isc_eem_func_not_returned) << udf->getName().toQuotedString() << engine); } } catch (const Exception&) @@ -1635,14 +1641,14 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_ const MetaString& userName = prc->invoker ? prc->invoker->getUserName() : ""; ContextManager ctxManager(tdbb, attInfo, attInfo->adminCharSet, (prc->getName().package.isEmpty() ? - CallerName(obj_procedure, prc->getName().identifier, userName) : - CallerName(obj_package_header, prc->getName().package, userName))); + CallerName(obj_procedure, prc->getName(), userName) : + CallerName(obj_package_header, + QualifiedName(prc->getName().package, prc->getName().schema), userName))); MemoryPool& pool = *tdbb->getAttachment()->att_pool; AutoPtr metadata(FB_NEW_POOL(pool) RoutineMetadata(pool)); - metadata->package = prc->getName().package; - metadata->name = prc->getName().identifier; + metadata->name = prc->getName(); metadata->entryPoint = entryPointTrimmed; metadata->body = body; metadata->inputParameters.assignRefNoIncr(Routine::createMetadata(prc->getInputFields(), true)); @@ -1676,7 +1682,7 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_ { status_exception::raise( Arg::Gds(isc_eem_proc_not_returned) << - prc->getName().toString() << engine); + prc->getName().toQuotedString() << engine); } } catch (const Exception&) @@ -1832,7 +1838,7 @@ void ExtEngineManager::makeTrigger(thread_db* tdbb, CompilerScratch* csb, Jrd::T if (!externalTrigger) { status_exception::raise( - Arg::Gds(isc_eem_trig_not_returned) << trg->name << engine); + Arg::Gds(isc_eem_trig_not_returned) << trg->name.toQuotedString() << engine); } if (relation) @@ -1994,22 +2000,23 @@ void ExtEngineManager::setupAdminCharSet(thread_db* tdbb, IExternalEngine* engin { ContextManager ctxManager(tdbb, attInfo, CS_UTF8); - char charSetName[MAX_SQL_IDENTIFIER_SIZE] = "NONE"; + QualifiedName charSetName; + char charSetNameBuffer[MAX_QUALIFIED_NAME_TO_STRING_LEN] = DEFAULT_DB_CHARACTER_SET_NAME; FbLocalStatus status; - engine->open(&status, attInfo->context, charSetName, MAX_SQL_IDENTIFIER_LEN); + engine->open(&status, attInfo->context, charSetNameBuffer, sizeof(charSetNameBuffer)); status.check(); - charSetName[MAX_SQL_IDENTIFIER_LEN] = '\0'; + charSetNameBuffer[sizeof(charSetNameBuffer) - 1] = '\0'; - if (!MET_get_char_coll_subtype(tdbb, &attInfo->adminCharSet, - reinterpret_cast(charSetName), - static_cast(strlen(charSetName)))) + if (charSetNameBuffer[0]) { - status_exception::raise( - Arg::Gds(isc_charset_not_found) << - Arg::Str(charSetName)); + charSetName = QualifiedName::parseSchemaObject(charSetNameBuffer); + tdbb->getAttachment()->qualifyExistingName(tdbb, charSetName, obj_charset); } + + if (!MET_get_char_coll_subtype(tdbb, &attInfo->adminCharSet, charSetName)) + status_exception::raise(Arg::Gds(isc_charset_not_found) << charSetName.toQuotedString()); } diff --git a/src/jrd/ExtEngineManager.h b/src/jrd/ExtEngineManager.h index c75db6a6fc..92a0c3341b 100644 --- a/src/jrd/ExtEngineManager.h +++ b/src/jrd/ExtEngineManager.h @@ -32,6 +32,7 @@ #include "../common/classes/fb_string.h" #include "../common/classes/GenericMap.h" #include "../jrd/MetaName.h" +#include "../jrd/QualifiedName.h" #include "../common/classes/NestConst.h" #include "../common/classes/auto.h" #include "../common/classes/rwlock.h" @@ -74,7 +75,6 @@ private: public: explicit RoutineMetadata(MemoryPool& pool) : PermanentStorage(pool), - package(pool), name(pool), entryPoint(pool), body(pool), @@ -85,12 +85,12 @@ private: const char* getPackage(Firebird::CheckStatusWrapper* /*status*/) const { - return package.nullStr(); + return name.package.nullStr(); } const char* getName(Firebird::CheckStatusWrapper* /*status*/) const { - return name.c_str(); + return name.object.c_str(); } const char* getEntryPoint(Firebird::CheckStatusWrapper* /*status*/) const @@ -120,7 +120,7 @@ private: const char* getTriggerTable(Firebird::CheckStatusWrapper* /*status*/) const { - return triggerTable.c_str(); + return triggerTable.object.c_str(); } unsigned getTriggerType(Firebird::CheckStatusWrapper* /*status*/) const @@ -128,15 +128,19 @@ private: return triggerType; } + const char* getSchema(Firebird::CheckStatusWrapper* /*status*/) const + { + return name.schema.c_str(); + } + public: - MetaName package; - MetaName name; + QualifiedName name; Firebird::string entryPoint; Firebird::string body; Firebird::RefPtr inputParameters; Firebird::RefPtr outputParameters; Firebird::RefPtr triggerFields; - MetaName triggerTable; + QualifiedName triggerTable; unsigned triggerType; private: diff --git a/src/jrd/Function.epp b/src/jrd/Function.epp index e6531a10ce..6d8d7e1480 100644 --- a/src/jrd/Function.epp +++ b/src/jrd/Function.epp @@ -147,7 +147,7 @@ Function* Function::lookup(thread_db* tdbb, const QualifiedName& name, bool nosc FOR(REQUEST_HANDLE request) X IN RDB$FUNCTIONS - WITH X.RDB$FUNCTION_NAME EQ name.identifier.c_str() AND + WITH X.RDB$FUNCTION_NAME EQ name.object.c_str() AND X.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') { function = loadMetadata(tdbb, X.RDB$FUNCTION_ID, noscan, 0); @@ -218,35 +218,34 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT FOR(REQUEST_HANDLE request_fun) X IN RDB$FUNCTIONS - WITH X.RDB$FUNCTION_ID EQ id + CROSS SCH IN RDB$SCHEMAS + WITH X.RDB$FUNCTION_ID EQ id AND + SCH.RDB$SCHEMA_NAME EQ X.RDB$SCHEMA_NAME { - function->setName(QualifiedName(X.RDB$FUNCTION_NAME, + function->setName(QualifiedName(X.RDB$FUNCTION_NAME, X.RDB$SCHEMA_NAME, (X.RDB$PACKAGE_NAME.NULL ? NULL : X.RDB$PACKAGE_NAME))); function->owner = X.RDB$OWNER_NAME; TriState ssDefiner; if (!X.RDB$SECURITY_CLASS.NULL) - { - function->setSecurityName(X.RDB$SECURITY_CLASS); - } + function->setSecurityName(QualifiedName(X.RDB$SECURITY_CLASS, SCH.RDB$SECURITY_CLASS)); else if (!X.RDB$PACKAGE_NAME.NULL) { AutoCacheRequest requestHandle(tdbb, irq_l_procedure_pkg_class, IRQ_REQUESTS); FOR (REQUEST_HANDLE requestHandle) PKG IN RDB$PACKAGES - WITH PKG.RDB$PACKAGE_NAME EQ X.RDB$PACKAGE_NAME - + WITH PKG.RDB$SCHEMA_NAME EQ SCH.RDB$SCHEMA_NAME AND + PKG.RDB$PACKAGE_NAME EQ X.RDB$PACKAGE_NAME + { if (!PKG.RDB$SECURITY_CLASS.NULL) - { - function->setSecurityName(PKG.RDB$SECURITY_CLASS); - } + function->setSecurityName(QualifiedName(PKG.RDB$SECURITY_CLASS, SCH.RDB$SECURITY_CLASS)); // SQL SECURITY of function must be the same if it's defined in package if (!PKG.RDB$SQL_SECURITY.NULL) ssDefiner = (bool) PKG.RDB$SQL_SECURITY; - + } END_FOR } @@ -274,7 +273,8 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT FOR(REQUEST_HANDLE request_arg) Y IN RDB$FUNCTION_ARGUMENTS - WITH Y.RDB$FUNCTION_NAME EQ function->getName().identifier.c_str() AND + WITH Y.RDB$SCHEMA_NAME EQ function->getName().schema.c_str() AND + Y.RDB$FUNCTION_NAME EQ function->getName().object.c_str() AND Y.RDB$PACKAGE_NAME EQUIV NULLIF(function->getName().package.c_str(), '') SORTED BY Y.RDB$ARGUMENT_POSITION { @@ -310,13 +310,14 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT if (!Y.RDB$FIELD_SOURCE.NULL) { - parameter->prm_field_source = Y.RDB$FIELD_SOURCE; + parameter->prm_field_source = QualifiedName(Y.RDB$FIELD_SOURCE, Y.RDB$FIELD_SOURCE_SCHEMA_NAME); AutoCacheRequest request_arg_fld(tdbb, irq_l_arg_fld, IRQ_REQUESTS); FOR(REQUEST_HANDLE request_arg_fld) F IN RDB$FIELDS - WITH F.RDB$FIELD_NAME = Y.RDB$FIELD_SOURCE + WITH F.RDB$SCHEMA_NAME EQUIV Y.RDB$FIELD_SOURCE_SCHEMA_NAME AND + F.RDB$FIELD_NAME = Y.RDB$FIELD_SOURCE { DSC_make_descriptor(¶meter->prm_desc, F.RDB$FIELD_TYPE, F.RDB$FIELD_SCALE, F.RDB$FIELD_LENGTH, @@ -349,7 +350,7 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT } if (!Y.RDB$RELATION_NAME.NULL) - parameter->prm_type_of_table = Y.RDB$RELATION_NAME; + parameter->prm_type_of_table = QualifiedName(Y.RDB$RELATION_NAME, Y.RDB$RELATION_SCHEMA_NAME); if (!Y.RDB$FIELD_NAME.NULL) parameter->prm_type_of_column = Y.RDB$FIELD_NAME; @@ -364,7 +365,7 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT try { parameter->prm_default_value = static_cast(MET_parse_blob( - tdbb, NULL, &default_value, NULL, NULL, false, false)); + tdbb, &function->getName().schema, NULL, &default_value, NULL, NULL, false, false)); } catch (const Exception&) { @@ -396,7 +397,7 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT // causes an exception. This is done at this time to save us from preparing // (thus allocating) this message every time the function is called. function->fun_exception_message.printf(EXCEPTION_MESSAGE, - function->getName().toString().c_str(), X.RDB$ENTRYPOINT, X.RDB$MODULE_NAME); + function->getName().toQuotedString().c_str(), X.RDB$ENTRYPOINT, X.RDB$MODULE_NAME); if (!X.RDB$DETERMINISTIC_FLAG.NULL) function->fun_deterministic = (X.RDB$DETERMINISTIC_FLAG != 0); @@ -455,7 +456,7 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT } else if (!X.RDB$FUNCTION_BLR.NULL) { - const string name = function->getName().toString(); + const string name = function->getName().toQuotedString(); try { @@ -608,7 +609,7 @@ bool Function::reload(thread_db* tdbb) StaticStatusVector temp_status; ex.stuffException(temp_status); - const string name = this->getName().toString(); + const string name = this->getName().toQuotedString(); (Arg::Gds(isc_bad_fun_BLR) << Arg::Str(name) << Arg::StatusVector(temp_status.begin())).raise(); } diff --git a/src/jrd/Function.h b/src/jrd/Function.h index 289a28fc9b..29aa6be0d9 100644 --- a/src/jrd/Function.h +++ b/src/jrd/Function.h @@ -24,13 +24,13 @@ #include "../common/classes/array.h" #include "../common/dsc.h" #include "../common/classes/NestConst.h" +#include "../jrd/QualifiedName.h" #include "../jrd/val.h" #include "../dsql/Nodes.h" namespace Jrd { class ValueListNode; - class QualifiedName; class Function final : public Routine { diff --git a/src/jrd/IntlManager.cpp b/src/jrd/IntlManager.cpp index 765038bcc3..9a699eb263 100644 --- a/src/jrd/IntlManager.cpp +++ b/src/jrd/IntlManager.cpp @@ -96,9 +96,10 @@ struct ExternalInfo string configInfo; }; +using CharSetCollationName = FullPooledPair; static GlobalPtr modules; -static GlobalPtr > > > charSetCollations; +static GlobalPtr> charSetCollations; const IntlManager::CharSetDefinition IntlManager::defaultCharSets[] = @@ -417,7 +418,7 @@ const IntlManager::CollationDefinition IntlManager::defaultCollations[] = bool IntlManager::initialize() { bool ok = true; - ObjectsArray conflicts; + ObjectsArray conflicts; string builtinConfig; PathName intlPath = fb_utils::getPrefix(Firebird::IConfigManager::DIR_INTL, ""); @@ -449,7 +450,10 @@ bool IntlManager::initialize() continue; } - const ConfigFile::String charSetName = ch->value; + QualifiedMetaString charSetName = QualifiedMetaString::parseSchemaObject(ch->value); + if (charSetName.schema.isEmpty()) + charSetName.schema = SYSTEM_SCHEMA; + PathName filename; string configInfo; @@ -459,15 +463,11 @@ bool IntlManager::initialize() (objModule = configFile.findParameter("intl_module", module->value.c_str()))) { if (!objModule->sub) - { fatal_exception::raiseFmt("Missing parameters for intl_module %s\n", module->value.c_str()); - } const ConfigFile::Parameter* fname = objModule->sub->findParameter("filename"); if (!fname) - { fatal_exception::raiseFmt("Missing parameter 'filename' for intl_module %s\n", module->value.c_str()); - } filename = fname->value.ToPathName(); configInfo = getConfigInfo(objModule); @@ -542,26 +542,30 @@ bool IntlManager::initialize() for (FB_SIZE_T coll = 0; coll < sub.getCount(); ++coll) { if (sub[coll].name != "collation") - { continue; + + const auto& collationStr = sub[coll].value; + string collationName; + string externalName; + + if (const auto pos = collationStr.find(' '); + pos != ConfigFile::String::npos) + { + collationName = collationStr.substr(0, pos); + externalName = collationStr.substr(pos).ToString(); + } + else + { + collationName = collationStr; + externalName = collationName; } - ConfigFile::String collationName = sub[coll].value; - ConfigFile::String externalName; - FB_SIZE_T pos = collationName.find(' '); - if (pos != ConfigFile::String::npos) - { - externalName = collationName.substr(pos); - externalName.ltrim(" \t"); - collationName = collationName.substr(0, pos); - } - const ConfigFile::String charSetCollation = charSetName + ":" + collationName; + externalName.trim(" \t"); - if (!registerCharSetCollation(charSetCollation.ToString(), filename, - (externalName.hasData() ? externalName : collationName).ToString(), - configInfo)) + if (!registerCharSetCollation(charSetName, collationName, filename, + externalName.c_str(), configInfo)) { - conflicts.add(charSetCollation); + conflicts.add({charSetName, collationName}); ok = false; } } @@ -576,45 +580,56 @@ bool IntlManager::initialize() ok = false; } - registerCharSetCollation("NONE:NONE", "", "NONE", builtinConfig); - registerCharSetCollation("OCTETS:OCTETS", "", "OCTETS", builtinConfig); - registerCharSetCollation("ASCII:ASCII", "", "ASCII", builtinConfig); - registerCharSetCollation("UNICODE_FSS:UNICODE_FSS", "", "UNICODE_FSS", builtinConfig); - registerCharSetCollation("UTF8:UTF8", "", "UTF8", builtinConfig); - registerCharSetCollation("UTF8:UCS_BASIC", "", "UCS_BASIC", builtinConfig); - registerCharSetCollation("UTF8:UNICODE", "", "UNICODE", builtinConfig); + registerCharSetCollation(QualifiedMetaString("NONE", SYSTEM_SCHEMA), + "NONE", "", "NONE", builtinConfig); + registerCharSetCollation(QualifiedMetaString("OCTETS", SYSTEM_SCHEMA), + "OCTETS", "", "OCTETS", builtinConfig); + registerCharSetCollation(QualifiedMetaString("ASCII", SYSTEM_SCHEMA), + "ASCII", "", "ASCII", builtinConfig); + registerCharSetCollation(QualifiedMetaString("UNICODE_FSS", SYSTEM_SCHEMA), + "UNICODE_FSS", "", "UNICODE_FSS", builtinConfig); + registerCharSetCollation(QualifiedMetaString("UTF8", SYSTEM_SCHEMA), + "UTF8", "", "UTF8", builtinConfig); + registerCharSetCollation(QualifiedMetaString("UTF8", SYSTEM_SCHEMA), + "UCS_BASIC", "", "UCS_BASIC", builtinConfig); + registerCharSetCollation(QualifiedMetaString("UTF8", SYSTEM_SCHEMA), + "UNICODE", "", "UNICODE", builtinConfig); - registerCharSetCollation("UTF16:UTF16", "", "UTF16", builtinConfig); + registerCharSetCollation(QualifiedMetaString("UTF16", SYSTEM_SCHEMA), + "UTF16", "", "UTF16", builtinConfig); #ifdef FB_NEW_INTL_ALLOW_NOT_READY - registerCharSetCollation("UTF16:UCS_BASIC", "", "UCS_BASIC", builtinConfig); - registerCharSetCollation("UTF32:UTF32", "", "UTF32", builtinConfig); - registerCharSetCollation("UTF32:UCS_BASIC", "", "UCS_BASIC", builtinConfig); + registerCharSetCollation(QualifiedMetaString("UTF16", SYSTEM_SCHEMA), + "UCS_BASIC", "", "UCS_BASIC", builtinConfig); + registerCharSetCollation(QualifiedMetaString("UTF32", SYSTEM_SCHEMA), + "UTF32", "", "UTF32", builtinConfig); + registerCharSetCollation(QualifiedMetaString("UTF32", SYSTEM_SCHEMA), + "UCS_BASIC", "", "UCS_BASIC", builtinConfig); #endif - for (ObjectsArray::const_iterator name(conflicts.begin()); name != conflicts.end(); ++name) - charSetCollations->remove(name->ToString()); + for (const auto& conflict : conflicts) + charSetCollations->remove(conflict); return ok; } -bool IntlManager::charSetInstalled(const string& charSetName) +bool IntlManager::charSetInstalled(const QualifiedMetaString& charSetName) { - return charSetCollations->exist(charSetName + ":" + charSetName); + return charSetCollations->exist({charSetName, charSetName.object}); } -bool IntlManager::collationInstalled(const string& collationName, const string& charSetName) +bool IntlManager::collationInstalled(const string& collationName, const QualifiedMetaString& charSetName) { - return charSetCollations->exist(charSetName + ":" + collationName); + return charSetCollations->exist({charSetName, collationName}); } -bool IntlManager::lookupCharSet(const string& charSetName, charset* cs) +bool IntlManager::lookupCharSet(const QualifiedMetaString& charSetName, charset* cs) { ExternalInfo externalInfo; - if (charSetCollations->get(charSetName + ":" + charSetName, externalInfo)) + if (charSetCollations->get({charSetName, charSetName.object}, externalInfo)) { pfn_INTL_lookup_charset lookupFunction = NULL; @@ -640,7 +655,7 @@ bool IntlManager::lookupCharSet(const string& charSetName, charset* cs) void IntlManager::lookupCollation(const string& collationName, - const string& charSetName, + const QualifiedMetaString& charSetName, USHORT attributes, const UCHAR* specificAttributes, ULONG specificAttributesLen, bool ignoreAttributes, texttype* tt) @@ -649,8 +664,8 @@ void IntlManager::lookupCollation(const string& collationName, ExternalInfo collationExternalInfo; char statusBuffer[BUFFER_LARGE] = ""; - if (charSetCollations->get(charSetName + ":" + charSetName, charSetExternalInfo) && - charSetCollations->get(charSetName + ":" + collationName, collationExternalInfo)) + if (charSetCollations->get({charSetName, charSetName.object}, charSetExternalInfo) && + charSetCollations->get({charSetName, collationName}, collationExternalInfo)) { ModuleLoader::Module* module = nullptr; @@ -691,17 +706,17 @@ void IntlManager::lookupCollation(const string& collationName, if (statusBuffer[0]) { - (Arg::Gds(isc_collation_not_installed) << collationName << charSetName << + (Arg::Gds(isc_collation_not_installed) << collationName << charSetName.toQuotedString() << Arg::Gds(isc_random) << statusBuffer ).raise(); } else - (Arg::Gds(isc_collation_not_installed) << collationName << charSetName).raise(); + (Arg::Gds(isc_collation_not_installed) << collationName << charSetName.toQuotedString()).raise(); } bool IntlManager::setupCollationAttributes( - const string& collationName, const string& charSetName, + const string& collationName, const QualifiedMetaString& charSetName, const string& specificAttributes, string& newSpecificAttributes) { ExternalInfo charSetExternalInfo; @@ -709,8 +724,8 @@ bool IntlManager::setupCollationAttributes( newSpecificAttributes = specificAttributes; - if (charSetCollations->get(charSetName + ":" + charSetName, charSetExternalInfo) && - charSetCollations->get(charSetName + ":" + collationName, collationExternalInfo)) + if (charSetCollations->get({charSetName, charSetName.object}, charSetExternalInfo) && + charSetCollations->get({charSetName, collationName}, collationExternalInfo)) { pfn_INTL_setup_attributes attributesFunction = NULL; @@ -793,32 +808,33 @@ string IntlManager::getConfigInfo(const ConfigFile::Parameter* confObj) } -bool IntlManager::registerCharSetCollation(const string& name, const PathName& filename, - const string& externalName, const string& configInfo +bool IntlManager::registerCharSetCollation(const QualifiedMetaString& charSetName, + const string& collationName, const PathName& filename, const string& externalName, + const string& configInfo ) { ExternalInfo conflict; - if (charSetCollations->get(name, conflict)) + if (charSetCollations->get({charSetName, collationName}, conflict)) { - gds__log((string("INTL plugin conflict: ") + name + " defined in " + - (conflict.moduleName.isEmpty() ? "" : conflict.moduleName.c_str()) + + gds__log((string("INTL plugin conflict: ") + charSetName.toQuotedString() + ":" + collationName + + " defined in " + (conflict.moduleName.isEmpty() ? "" : conflict.moduleName.c_str()) + " and " + filename.c_str()).c_str()); return false; } - charSetCollations->put(name, ExternalInfo(filename, externalName, configInfo)); + charSetCollations->put({charSetName, collationName}, ExternalInfo(filename, externalName, configInfo)); return true; } -bool IntlManager::validateCharSet(const string& charSetName, charset* cs) +bool IntlManager::validateCharSet(const QualifiedMetaString& charSetName, charset* cs) { bool valid = true; string s; string unsupportedMsg; - unsupportedMsg.printf("Unsupported character set %s.", charSetName.c_str()); + unsupportedMsg.printf("Unsupported character set %s.", charSetName.toQuotedString().c_str()); if (!(cs->charset_flags & CHARSET_ASCII_BASED)) { diff --git a/src/jrd/IntlManager.h b/src/jrd/IntlManager.h index c35ecf9705..17fc97d9c0 100644 --- a/src/jrd/IntlManager.h +++ b/src/jrd/IntlManager.h @@ -28,6 +28,8 @@ #define JRD_INTLMANAGER_H #include "../common/classes/fb_string.h" +#include "../common/classes/MetaString.h" +#include "../common/classes/QualifiedMetaString.h" #include "../common/config/config_file.h" struct charset; @@ -40,21 +42,21 @@ class IntlManager public: static bool initialize(); - static bool charSetInstalled(const Firebird::string& charSetName); + static bool charSetInstalled(const Firebird::QualifiedMetaString& charSetName); static bool collationInstalled(const Firebird::string& collationName, - const Firebird::string& charSetName); + const Firebird::QualifiedMetaString& charSetName); - static bool lookupCharSet(const Firebird::string& charSetName, charset* cs); + static bool lookupCharSet(const Firebird::QualifiedMetaString& charSetName, charset* cs); static void lookupCollation(const Firebird::string& collationName, - const Firebird::string& charSetName, + const Firebird::QualifiedMetaString& charSetName, USHORT attributes, const UCHAR* specificAttributes, ULONG specificAttributesLen, bool ignoreAttributes, texttype* tt); static bool setupCollationAttributes( - const Firebird::string& collationName, const Firebird::string& charSetName, + const Firebird::string& collationName, const Firebird::QualifiedMetaString& charSetName, const Firebird::string& specificAttributes, Firebird::string& newSpecificAttributes); public: @@ -88,11 +90,11 @@ public: private: static Firebird::string getConfigInfo(const ConfigFile::Parameter* par); - static bool registerCharSetCollation(const Firebird::string& name, - const Firebird::PathName& filename, const Firebird::string& externalName, - const Firebird::string& configInfo); + static bool registerCharSetCollation(const Firebird::QualifiedMetaString& charSetName, + const Firebird::string& collationName, const Firebird::PathName& filename, + const Firebird::string& externalName, const Firebird::string& configInfo); - static bool validateCharSet(const Firebird::string& charSetName, charset* cs); + static bool validateCharSet(const Firebird::QualifiedMetaString& charSetName, charset* cs); }; } // namespace Jrd diff --git a/src/jrd/Mapping.cpp b/src/jrd/Mapping.cpp index dba426c3bd..4c44296501 100644 --- a/src/jrd/Mapping.cpp +++ b/src/jrd/Mapping.cpp @@ -347,7 +347,7 @@ bool Mapping::Cache::populate(IAttachment *att) curs = att->openCursor(&st, tra, 0, "SELECT RDB$MAP_USING, RDB$MAP_PLUGIN, RDB$MAP_DB, RDB$MAP_FROM_TYPE, " " RDB$MAP_FROM, RDB$MAP_TO_TYPE, RDB$MAP_TO " - "FROM RDB$AUTH_MAPPING", + "FROM SYSTEM.RDB$AUTH_MAPPING", 3, nullptr, nullptr, mMap.getMetadata(), nullptr, 0); if (st->getState() & IStatus::STATE_ERRORS) { @@ -998,26 +998,26 @@ void setupIpc() const char* roleSql = "with recursive role_tree as ( " -" select rdb$role_name as nm from rdb$roles " +" select rdb$role_name as nm from system.rdb$roles " " where rdb$role_name = ? " " union all " -" select p.rdb$relation_name as nm from rdb$user_privileges p " +" select p.rdb$relation_name as nm from system.rdb$user_privileges p " " join role_tree t on t.nm = p.rdb$user " " where p.rdb$privilege = 'M') " "select r.rdb$system_privileges from role_tree t " -" join rdb$roles r on t.nm = r.rdb$role_name " +" join system.rdb$roles r on t.nm = r.rdb$role_name " ; const char* userSql = "with recursive role_tree as ( " -" select rdb$relation_name as nm from rdb$user_privileges " +" select rdb$relation_name as nm from system.rdb$user_privileges " " where rdb$privilege = 'M' and rdb$field_name = 'D' and rdb$user = ? and rdb$user_type = 8 " " union all " -" select p.rdb$relation_name as nm from rdb$user_privileges p " +" select p.rdb$relation_name as nm from system.rdb$user_privileges p " " join role_tree t on t.nm = p.rdb$user " " where p.rdb$privilege = 'M' and p.rdb$field_name = 'D') " "select r.rdb$system_privileges from role_tree t " -" join rdb$roles r on t.nm = r.rdb$role_name " +" join system.rdb$roles r on t.nm = r.rdb$role_name " ; class SysPrivCache : public PermanentStorage @@ -1228,7 +1228,7 @@ private: Message cols; Field role(cols, MAX_SQL_IDENTIFIER_SIZE); - const char* sql = "select RDB$RELATION_NAME from RDB$USER_PRIVILEGES " + const char* sql = "select RDB$RELATION_NAME from SYSTEM.RDB$USER_PRIVILEGES " "where RDB$USER = ? and RDB$PRIVILEGE = 'M' and RDB$USER_TYPE = 8 and RDB$OBJECT_TYPE = 13"; RefPtr curs(REF_NO_INCR, iDb->openCursor(&st, tra, 0, sql, 3, @@ -1744,7 +1744,7 @@ RecordBuffer* MappingList::getList(thread_db* tdbb, jrd_rel* relation) curs = att->openCursor(&st, tra, 0, "SELECT RDB$MAP_NAME, RDB$MAP_USING, RDB$MAP_PLUGIN, RDB$MAP_DB, " " RDB$MAP_FROM_TYPE, RDB$MAP_FROM, RDB$MAP_TO_TYPE, RDB$MAP_TO, RDB$DESCRIPTION " - "FROM RDB$AUTH_MAPPING", + "FROM SYSTEM.RDB$AUTH_MAPPING", 3, nullptr, nullptr, mMap.getMetadata(), nullptr, 0); if (st->getState() & IStatus::STATE_ERRORS) { diff --git a/src/jrd/MetaName.h b/src/jrd/MetaName.h index c8450e624f..f3d066b943 100644 --- a/src/jrd/MetaName.h +++ b/src/jrd/MetaName.h @@ -31,6 +31,7 @@ #include "../common/classes/fb_string.h" #include "../common/classes/fb_pair.h" +#include "../common/classes/MetaString.h" #include "../jrd/constants.h" #include @@ -50,12 +51,6 @@ #define DIC_STAT_SEGMENT_PAR #endif -namespace Firebird { - -class MetaString; - -} - namespace Jrd { @@ -299,6 +294,11 @@ public: return compare(m.begin(), m.length()); } + Firebird::string toQuotedString() const + { + return Firebird::MetaString(c_str(), length()).toQuotedString(); + } + bool operator==(const char* s) const { return compare(s) == 0; diff --git a/src/jrd/Monitoring.cpp b/src/jrd/Monitoring.cpp index 704c116865..06cfeb5771 100644 --- a/src/jrd/Monitoring.cpp +++ b/src/jrd/Monitoring.cpp @@ -47,6 +47,7 @@ #include "../jrd/Monitoring.h" #include "../jrd/Function.h" #include "../jrd/optimizer/Optimizer.h" +#include #ifdef WIN_NT #include @@ -706,7 +707,7 @@ void SnapshotData::putField(thread_db* tdbb, Record* record, const DumpField& fi from_desc.makeLong(0, &local_id); MOV_move(tdbb, &from_desc, &to_desc); } - else if (field.type == VALUE_TABLE_ID) + else if (field.type == VALUE_TABLE_ID_OBJECT_NAME || field.type == VALUE_TABLE_ID_SCHEMA_NAME) { // special case: translate relation ID into name fb_assert(field.length == sizeof(SLONG)); @@ -714,10 +715,12 @@ void SnapshotData::putField(thread_db* tdbb, Record* record, const DumpField& fi memcpy(&rel_id, field.data, field.length); const jrd_rel* const relation = MET_lookup_relation_id(tdbb, rel_id, false); - if (!relation || relation->rel_name.isEmpty()) + if (!relation || relation->rel_name.object.isEmpty()) return; - const MetaName& name = relation->rel_name; + const auto& name = field.type == VALUE_TABLE_ID_OBJECT_NAME ? + relation->rel_name.object : relation->rel_name.schema; + dsc from_desc; from_desc.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str()); MOV_move(tdbb, &from_desc, &to_desc); @@ -1061,6 +1064,19 @@ void Monitoring::putAttachment(SnapshotData::DumpRecord& record, const Jrd::Atta record.storeInteger(f_mon_att_par_workers, attachment->att_parallel_workers); + if (const auto& searchPath = *attachment->att_schema_search_path; searchPath.hasData()) + { + record.storeString(f_mon_att_search_path, + std::accumulate( + std::next(searchPath.begin()), + searchPath.end(), + searchPath.front().toQuotedString(), + [](const auto& str, const auto& name) { + return str + ", " + name.toQuotedString(); + } + )); + } + record.write(); if (attachment->att_database->dbb_flags & DBB_shared) @@ -1175,12 +1191,16 @@ void Monitoring::putStatement(SnapshotData::DumpRecord& record, const Statement* if (routine->getName().package.hasData()) record.storeString(f_mon_cmp_stmt_pkg_name, routine->getName().package); - record.storeString(f_mon_cmp_stmt_name, routine->getName().identifier); + if (routine->getName().schema.hasData()) + record.storeString(f_mon_cmp_sch_name, routine->getName().schema); + + record.storeString(f_mon_cmp_stmt_name, routine->getName().object); record.storeInteger(f_mon_cmp_stmt_type, routine->getObjectType()); } - else if (!statement->triggerName.isEmpty()) + else if (statement->triggerName.object.hasData()) { - record.storeString(f_mon_cmp_stmt_name, statement->triggerName); + record.storeString(f_mon_cmp_sch_name, statement->triggerName.schema); + record.storeString(f_mon_cmp_stmt_name, statement->triggerName.object); record.storeInteger(f_mon_cmp_stmt_type, obj_trigger); } @@ -1285,12 +1305,16 @@ void Monitoring::putCall(SnapshotData::DumpRecord& record, const Request* reques if (routine->getName().package.hasData()) record.storeString(f_mon_call_pkg_name, routine->getName().package); - record.storeString(f_mon_call_name, routine->getName().identifier); + if (routine->getName().schema.hasData()) + record.storeString(f_mon_call_sch_name, routine->getName().schema); + + record.storeString(f_mon_call_name, routine->getName().object); record.storeInteger(f_mon_call_type, routine->getObjectType()); } - else if (!statement->triggerName.isEmpty()) + else if (statement->triggerName.object.hasData()) { - record.storeString(f_mon_call_name, statement->triggerName); + record.storeString(f_mon_call_sch_name, statement->triggerName.schema); + record.storeString(f_mon_call_name, statement->triggerName.object); record.storeInteger(f_mon_call_type, obj_trigger); } else @@ -1368,7 +1392,8 @@ void Monitoring::putStatistics(SnapshotData::DumpRecord& record, const RuntimeSt record.reset(rel_mon_tab_stats); record.storeGlobalId(f_mon_tab_stat_id, id); record.storeInteger(f_mon_tab_stat_group, stat_group); - record.storeTableId(f_mon_tab_name, (*iter).getRelationId()); + record.storeTableIdSchemaName(f_mon_tab_sch_name, (*iter).getRelationId()); + record.storeTableIdObjectName(f_mon_tab_name, (*iter).getRelationId()); record.storeGlobalId(f_mon_tab_rec_stat_id, rec_stat_id); record.write(); diff --git a/src/jrd/Monitoring.h b/src/jrd/Monitoring.h index dccc2a4de4..0fa1091cb4 100644 --- a/src/jrd/Monitoring.h +++ b/src/jrd/Monitoring.h @@ -53,12 +53,14 @@ public: { VALUE_UNKNOWN, VALUE_GLOBAL_ID, - VALUE_TABLE_ID, + VALUE_TABLE_ID_OBJECT_NAME, VALUE_INTEGER, VALUE_TIMESTAMP, VALUE_TIMESTAMP_TZ, VALUE_STRING, - VALUE_BOOLEAN + VALUE_BOOLEAN, + VALUE_TABLE_ID_SCHEMA_NAME, + VALUE_LAST_MARKER // Should be last item }; struct DumpField @@ -122,9 +124,14 @@ public: storeField(field_id, VALUE_GLOBAL_ID, sizeof(SINT64), &value); } - void storeTableId(int field_id, SLONG value) + void storeTableIdObjectName(int field_id, SLONG value) { - storeField(field_id, VALUE_TABLE_ID, sizeof(SLONG), &value); + storeField(field_id, VALUE_TABLE_ID_OBJECT_NAME, sizeof(SLONG), &value); + } + + void storeTableIdSchemaName(int field_id, SLONG value) + { + storeField(field_id, VALUE_TABLE_ID_SCHEMA_NAME, sizeof(SLONG), &value); } void storeInteger(int field_id, SINT64 value) @@ -175,7 +182,7 @@ public: { field.id = (USHORT) buffer[offset++]; field.type = (ValueType) buffer[offset++]; - fb_assert(field.type >= VALUE_GLOBAL_ID && field.type <= VALUE_BOOLEAN); + fb_assert(field.type >= VALUE_GLOBAL_ID && field.type < VALUE_LAST_MARKER); memcpy(&field.length, &buffer[offset], sizeof(ULONG)); offset += sizeof(ULONG); field.data = &buffer[offset]; diff --git a/src/jrd/PreparedStatement.cpp b/src/jrd/PreparedStatement.cpp index ce6e4140e4..fe65a4632c 100644 --- a/src/jrd/PreparedStatement.cpp +++ b/src/jrd/PreparedStatement.cpp @@ -416,10 +416,23 @@ PreparedStatement::~PreparedStatement() void PreparedStatement::init(thread_db* tdbb, Attachment* attachment, jrd_tra* transaction, const Firebird::string& text, bool isInternalRequest) { + auto newSchemaSearchPath = isInternalRequest ? + makeRef(FB_NEW_POOL(*attachment->att_pool) AnyRef>(*attachment->att_pool)) : + attachment->att_schema_search_path; + + if (isInternalRequest) + { + newSchemaSearchPath->push(SYSTEM_SCHEMA); + // FIXME: PLUGINS_SCHEMA? + } + + AutoSetRestore>>> autoSchemaSearchPath( + &attachment->att_schema_search_path, newSchemaSearchPath); + AutoSetRestore autoAttCharset(&attachment->att_charset, (isInternalRequest ? CS_METADATA : attachment->att_charset)); - dsqlRequest = NULL; + dsqlRequest = nullptr; try { const Database& dbb = *tdbb->getDatabase(); diff --git a/src/jrd/ProfilerManager.cpp b/src/jrd/ProfilerManager.cpp index 95fb61d779..0897ad355e 100644 --- a/src/jrd/ProfilerManager.cpp +++ b/src/jrd/ProfilerManager.cpp @@ -666,8 +666,7 @@ ProfilerManager::Statement* ProfilerManager::getStatement(Request* request) statement && !currentSession->statements.exist(statement->getStatementId()); statement = statement->parentStatement) { - MetaName packageName; - MetaName routineName; + QualifiedName name; const char* type; if (const auto routine = statement->getRoutine()) @@ -677,13 +676,12 @@ ProfilerManager::Statement* ProfilerManager::getStatement(Request* request) else if (statement->function) type = "FUNCTION"; - packageName = routine->getName().package; - routineName = routine->getName().identifier; + name = routine->getName(); } - else if (statement->triggerName.hasData()) + else if (statement->triggerName.object.hasData()) { type = "TRIGGER"; - routineName = statement->triggerName; + name = statement->triggerName; } else type = "BLOCK"; @@ -691,10 +689,10 @@ ProfilerManager::Statement* ProfilerManager::getStatement(Request* request) const StmtNumber parentStatementId = statement->parentStatement ? statement->parentStatement->getStatementId() : 0; - LogLocalStatus status("Profiler defineStatement"); - currentSession->pluginSession->defineStatement(&status, + LogLocalStatus status("Profiler defineStatement2"); + currentSession->pluginSession->defineStatement2(&status, (SINT64) statement->getStatementId(), (SINT64) parentStatementId, - type, packageName.nullStr(), routineName.nullStr(), + type, name.schema.nullStr(), name.package.nullStr(), name.object.nullStr(), (statement->sqlText.hasData() ? statement->sqlText->c_str() : "")); auto profileStatement = currentSession->statements.put(statement->getStatementId()); diff --git a/src/jrd/ProfilerManager.h b/src/jrd/ProfilerManager.h index 0b9570be6e..1d19afc9fb 100644 --- a/src/jrd/ProfilerManager.h +++ b/src/jrd/ProfilerManager.h @@ -284,7 +284,7 @@ public: { Firebird::status_exception::raise( Firebird::Arg::Gds(isc_not_valid_for_var) << - "FLUSH_INTERVAL" << + "\"FLUSH_INTERVAL\"" << Firebird::Arg::Num(interval)); } } diff --git a/src/jrd/QualifiedName.h b/src/jrd/QualifiedName.h index 3457a5df8f..bede8e161a 100644 --- a/src/jrd/QualifiedName.h +++ b/src/jrd/QualifiedName.h @@ -27,86 +27,17 @@ #ifndef JRD_QUALIFIEDNAME_H #define JRD_QUALIFIEDNAME_H -#include "MetaName.h" +#include "../jrd/MetaName.h" #include "../common/classes/array.h" +#include "../common/classes/fb_pair.h" +#include "../common/classes/MetaString.h" +#include "../common/classes/QualifiedMetaString.h" +#include "../common/StatusArg.h" namespace Jrd { -class QualifiedName -{ -public: - QualifiedName(MemoryPool& p, const MetaName& aIdentifier, const MetaName& aPackage) - : identifier(p, aIdentifier), - package(p, aPackage) - { - } - - QualifiedName(const MetaName& aIdentifier, const MetaName& aPackage) - : identifier(aIdentifier), - package(aPackage) - { - } - - QualifiedName(MemoryPool& p, const MetaName& aIdentifier) - : identifier(p, aIdentifier), - package(p) - { - } - - explicit QualifiedName(const MetaName& aIdentifier) - : identifier(aIdentifier) - { - } - - explicit QualifiedName(MemoryPool& p) - : identifier(p), - package(p) - { - } - - QualifiedName() - { - } - - QualifiedName(MemoryPool& p, const QualifiedName& src) - : identifier(p, src.identifier), - package(p, src.package) - { - } - -public: - bool operator >(const QualifiedName& m) const - { - return package > m.package || (package == m.package && identifier > m.identifier); - } - - bool operator ==(const QualifiedName& m) const - { - return identifier == m.identifier && package == m.package; - } - - bool operator !=(const QualifiedName& m) const - { - return !(identifier == m.identifier && package == m.package); - } - -public: - Firebird::string toString() const - { - Firebird::string s; - if (package.hasData()) - { - s = package.c_str(); - s.append("."); - } - s.append(identifier.c_str()); - return s; - } - -public: - MetaName identifier; - MetaName package; -}; +using QualifiedName = Firebird::BaseQualifiedName; +using QualifiedNameMetaNamePair = Firebird::FullPooledPair; } // namespace Jrd diff --git a/src/jrd/RecordSourceNodes.cpp b/src/jrd/RecordSourceNodes.cpp index 47367b41dc..4d75fb8026 100644 --- a/src/jrd/RecordSourceNodes.cpp +++ b/src/jrd/RecordSourceNodes.cpp @@ -193,7 +193,7 @@ PlanNode* PlanNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) if (dsqlNames) { - node->dsqlNames = FB_NEW_POOL(pool) ObjectsArray(pool); + node->dsqlNames = FB_NEW_POOL(pool) ObjectsArray(pool); *node->dsqlNames = *dsqlNames; dsql_ctx* context = dsqlPassAliasList(dsqlScratch); @@ -231,8 +231,8 @@ dsql_ctx* PlanNode::dsqlPassAliasList(DsqlCompilerScratch* dsqlScratch) { DEV_BLKCHK(dsqlScratch, dsql_type_req); - ObjectsArray::iterator arg = dsqlNames->begin(); - ObjectsArray::iterator end = dsqlNames->end(); + auto arg = dsqlNames->begin(); + const auto end = dsqlNames->end(); // Loop through every alias and find the context for that alias. // All aliases should have a corresponding context. @@ -252,7 +252,7 @@ dsql_ctx* PlanNode::dsqlPassAliasList(DsqlCompilerScratch* dsqlScratch) else if (context->ctx_relation) { // This must be a VIEW - ObjectsArray::iterator startArg = arg; + const auto startArg = arg; dsql_rel* viewRelation = context->ctx_relation; dsql_rel* relation = nullptr; @@ -263,8 +263,7 @@ dsql_ctx* PlanNode::dsqlPassAliasList(DsqlCompilerScratch* dsqlScratch) for (; arg != end; ++arg) { if (!METD_get_view_relation(dsqlScratch->getTransaction(), - dsqlScratch, viewRelation->rel_name, *arg, - relation, procedure)) + dsqlScratch, viewRelation->rel_name, *arg, relation, procedure)) { break; }; @@ -286,20 +285,10 @@ dsql_ctx* PlanNode::dsqlPassAliasList(DsqlCompilerScratch* dsqlScratch) newContext->ctx_procedure = procedure; // Concatenate all the contexts to form the alias name. - // Calculate the length leaving room for spaces. - USHORT aliasLength = dsqlNames->getCount(); - ObjectsArray::iterator aliasArg = startArg; - for (; aliasArg != end; ++aliasArg) - aliasLength += aliasArg->length(); - - newContext->ctx_alias.reserve(aliasLength); + auto aliasArg = startArg; for (aliasArg = startArg; aliasArg != end; ++aliasArg) - { - if (aliasArg != startArg) - newContext->ctx_alias.append(" ", 1); - newContext->ctx_alias.append(aliasArg->c_str(), aliasArg->length()); - } + newContext->ctx_alias.add(*aliasArg); context = newContext; } @@ -326,7 +315,7 @@ dsql_ctx* PlanNode::dsqlPassAliasList(DsqlCompilerScratch* dsqlScratch) // there is no alias or table named %s at this scope level. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << Arg::Gds(isc_dsql_command_err) << - Arg::Gds(isc_dsql_no_relation_alias) << *arg); + Arg::Gds(isc_dsql_no_relation_alias) << arg->toQuotedString()); } return context; @@ -335,7 +324,7 @@ dsql_ctx* PlanNode::dsqlPassAliasList(DsqlCompilerScratch* dsqlScratch) // The passed relation or alias represents a context which was previously specified in the from // list. Find and return the proper context. dsql_ctx* PlanNode::dsqlPassAlias(DsqlCompilerScratch* dsqlScratch, DsqlContextStack& stack, - const MetaName& alias) + const QualifiedName& alias) { dsql_ctx* result_context = nullptr; @@ -351,30 +340,30 @@ dsql_ctx* PlanNode::dsqlPassAlias(DsqlCompilerScratch* dsqlScratch, DsqlContextS continue; // check for matching alias. - if (context->ctx_internal_alias.hasData()) + if (context->ctx_internal_alias.object.hasData()) { - if (context->ctx_internal_alias == alias.c_str()) + if (context->ctx_internal_alias == alias) return context; continue; } // If an unnamed derived table and empty alias. - if (context->ctx_rse && !context->ctx_relation && !context->ctx_procedure && alias.isEmpty()) + if (context->ctx_rse && !context->ctx_relation && !context->ctx_procedure && alias.object.isEmpty()) result_context = context; // Check for matching relation name; aliases take priority so // save the context in case there is an alias of the same name. // Also to check that there is no self-join in the query. - if ((context->ctx_relation && context->ctx_relation->rel_name == alias) || - (context->ctx_procedure && context->ctx_procedure->prc_name.identifier == alias)) + if ((context->ctx_relation && PASS1_compare_alias(context->ctx_relation->rel_name, alias)) || + (context->ctx_procedure && PASS1_compare_alias(context->ctx_procedure->prc_name, alias))) { if (result_context) { // the table %s is referenced twice; use aliases to differentiate ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << Arg::Gds(isc_dsql_command_err) << - Arg::Gds(isc_dsql_self_join) << alias); + Arg::Gds(isc_dsql_self_join) << alias.toQuotedString()); } result_context = context; @@ -570,7 +559,7 @@ RelationSourceNode* RelationSourceNode::parse(thread_db* tdbb, CompilerScratch* // Find relation either by id or by name AutoPtr aliasString; - MetaName name; + QualifiedName name; switch (blrOp) { @@ -586,17 +575,22 @@ RelationSourceNode* RelationSourceNode::parse(thread_db* tdbb, CompilerScratch* } if (!(node->relation = MET_lookup_relation_id(tdbb, id, false))) - name.printf("id %d", id); + name.object.printf("id %d", id); break; } + case blr_relation3: + csb->csb_blr_reader.getMetaName(name.schema); + // fall through + case blr_relation: case blr_relation2: { - csb->csb_blr_reader.getMetaName(name); + csb->csb_blr_reader.getMetaName(name.object); + csb->qualifyExistingName(tdbb, name, obj_relation); - if (blrOp == blr_relation2) + if (blrOp == blr_relation2 || blrOp == blr_relation3) { aliasString = FB_NEW_POOL(csb->csb_pool) string(csb->csb_pool); csb->csb_blr_reader.getString(*aliasString); @@ -611,7 +605,7 @@ RelationSourceNode* RelationSourceNode::parse(thread_db* tdbb, CompilerScratch* } if (!node->relation) - PAR_error(csb, Arg::Gds(isc_relnotdef) << Arg::Str(name), false); + PAR_error(csb, Arg::Gds(isc_relnotdef) << name.toQuotedString(), false); // if an alias was passed, store with the relation @@ -682,12 +676,26 @@ void RelationSourceNode::genBlr(DsqlCompilerScratch* dsqlScratch) } else { - dsqlScratch->appendUChar(dsqlContext->ctx_alias.hasData() ? blr_relation2 : blr_relation); - dsqlScratch->appendMetaString(relation->rel_name.c_str()); + if (relation->rel_name.schema != dsqlScratch->ddlSchema) + { + dsqlScratch->appendUChar(blr_relation3); + dsqlScratch->appendMetaString(relation->rel_name.schema.c_str()); + dsqlScratch->appendMetaString(relation->rel_name.object.c_str()); + if (dsqlContext->ctx_alias.isEmpty()) + dsqlScratch->appendMetaString(""); + } + else + { + dsqlScratch->appendUChar(dsqlContext->ctx_alias.hasData() ? blr_relation2 : blr_relation); + dsqlScratch->appendMetaString(relation->rel_name.object.c_str()); + } } if (dsqlContext->ctx_alias.hasData()) - dsqlScratch->appendMetaString(dsqlContext->ctx_alias.c_str()); + { + const auto contextAliases = dsqlContext->getConcatenatedAlias(); + dsqlScratch->appendMetaString(contextAliases.c_str()); + } GEN_stuff_context(dsqlScratch, dsqlContext); } @@ -730,7 +738,11 @@ RecordSourceNode* RelationSourceNode::pass1(thread_db* tdbb, CompilerScratch* cs { const SLONG ssRelationId = tail->csb_view ? tail->csb_view->rel_id : view ? view->rel_id : csb->csb_view ? csb->csb_view->rel_id : 0; - CMP_post_access(tdbb, csb, relation->rel_security_name, ssRelationId, + + CMP_post_access(tdbb, csb, relation->rel_security_name.schema, ssRelationId, + SCL_usage, obj_schemas, QualifiedName(relation->rel_name.schema)); + + CMP_post_access(tdbb, csb, relation->rel_security_name.object, ssRelationId, SCL_select, obj_relations, relation->rel_name); } @@ -925,44 +937,57 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch { switch (subCode) { - case blr_invsel_procedure_type: + case blr_invsel_procedure_id: { - UCHAR procedureType = blrReader.getByte(); + bool isSub = false; + UCHAR procedureIdCode; - switch (procedureType) + while ((procedureIdCode = blrReader.getByte()) != blr_end) { - case blr_invsel_procedure_type_packaged: - blrReader.getMetaName(name.package); - break; + switch (procedureIdCode) + { + case blr_invsel_procedure_id_schema: + blrReader.getMetaName(name.schema); + break; - case blr_invsel_procedure_type_standalone: - case blr_invsel_procedure_type_sub: - break; + case blr_invsel_procedure_id_package: + blrReader.getMetaName(name.package); + break; - default: - PAR_error(csb, Arg::Gds(isc_random) << "Invalid blr_invsel_procedure_type"); - break; + case blr_invsel_procedure_id_name: + blrReader.getMetaName(name.object); + break; + + case blr_invsel_procedure_id_sub: + isSub = true; + break; + + default: + PAR_error(csb, Arg::Gds(isc_random) << "Invalid blr_invsel_procedure_id"); + break; + } } - blrReader.getMetaName(name.identifier); - - if (procedureType == blr_invsel_procedure_type_sub) + if (isSub) { for (auto curCsb = csb; curCsb && !node->procedure; curCsb = curCsb->mainCsb) { - if (const auto declareNode = curCsb->subProcedures.get(name.identifier)) + if (const auto declareNode = curCsb->subProcedures.get(name.object)) node->procedure = (*declareNode)->routine; } } else if (!node->procedure) + { + csb->qualifyExistingName(tdbb, name, obj_procedure); node->procedure = MET_lookup_procedure(tdbb, name, false); + } break; } case blr_invsel_procedure_in_arg_names: { - predateCheck(node->procedure, "blr_invsel_procedure_type", "blr_invsel_procedure_in_arg_names"); + predateCheck(node->procedure, "blr_invsel_procedure_id", "blr_invsel_procedure_in_arg_names"); predateCheck(!node->inputSources, "blr_invsel_procedure_in_arg_names", "blr_invsel_procedure_in_args"); inArgNamesPos = blrReader.getPos(); @@ -981,7 +1006,7 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch } case blr_invsel_procedure_in_args: - predateCheck(node->procedure, "blr_invsel_procedure_type", "blr_invsel_procedure_in_args"); + predateCheck(node->procedure, "blr_invsel_procedure_id", "blr_invsel_procedure_in_args"); inArgCount = blrReader.getWord(); node->inputSources = PAR_args(tdbb, csb, inArgCount, @@ -996,7 +1021,7 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch "blr_invsel_procedure_context not expected inside plan clauses"); } - predateCheck(node->procedure, "blr_invsel_procedure_type", "blr_invsel_procedure_context"); + predateCheck(node->procedure, "blr_invsel_procedure_id", "blr_invsel_procedure_context"); node->stream = PAR_context2(csb, &node->context); csbTail = &csb->csb_rpt[node->stream]; csbTail->csb_procedure = node->procedure; @@ -1032,7 +1057,7 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch blrReader.getString(node->alias); if (!(node->procedure = MET_lookup_procedure_id(tdbb, pid, false, false, 0))) - name.identifier.printf("id %d", pid); + name.object.printf("id %d", pid); break; } @@ -1045,7 +1070,7 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch if (blrOp == blr_procedure3 || blrOp == blr_procedure4) blrReader.getMetaName(name.package); - blrReader.getMetaName(name.identifier); + blrReader.getMetaName(name.object); if (blrOp == blr_procedure2 || blrOp == blr_procedure4 || blrOp == blr_subproc) blrReader.getString(node->alias); @@ -1054,12 +1079,15 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch { for (auto curCsb = csb; curCsb && !node->procedure; curCsb = curCsb->mainCsb) { - if (const auto declareNode = curCsb->subProcedures.get(name.identifier)) + if (const auto declareNode = curCsb->subProcedures.get(name.object)) node->procedure = (*declareNode)->routine; } } else + { + csb->qualifyExistingName(tdbb, name, obj_procedure); node->procedure = MET_lookup_procedure(tdbb, name, false); + } break; @@ -1078,15 +1106,15 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch if (!node->procedure) { blrReader.setPos(blrStartPos); - PAR_error(csb, Arg::Gds(isc_prcnotdef) << name.toString()); + PAR_error(csb, Arg::Gds(isc_prcnotdef) << name.toQuotedString()); } if (node->procedure->prc_type == prc_executable) { if (tdbb->getAttachment()->isGbak()) - PAR_warning(Arg::Warning(isc_illegal_prc_type) << node->procedure->getName().toString()); + PAR_warning(Arg::Warning(isc_illegal_prc_type) << node->procedure->getName().toQuotedString()); else - PAR_error(csb, Arg::Gds(isc_illegal_prc_type) << node->procedure->getName().toString()); + PAR_error(csb, Arg::Gds(isc_illegal_prc_type) << node->procedure->getName().toQuotedString()); } node->isSubRoutine = node->procedure->isSubRoutine(); @@ -1097,14 +1125,14 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch if (tdbb->getAttachment()->isGbak() || (tdbb->tdbb_flags & TDBB_replicator)) { PAR_warning( - Arg::Warning(isc_prcnotdef) << name.toString() << + Arg::Warning(isc_prcnotdef) << name.toQuotedString() << Arg::Warning(isc_modnotfound)); } else { blrReader.setPos(blrStartPos); PAR_error(csb, - Arg::Gds(isc_prcnotdef) << name.toString() << + Arg::Gds(isc_prcnotdef) << name.toQuotedString() << Arg::Gds(isc_modnotfound)); } } @@ -1143,7 +1171,7 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch mismatchStatus)) { status_exception::raise(Arg::Gds(isc_prcmismat) << - node->procedure->getName().toString() << mismatchStatus); + node->procedure->getName().toQuotedString() << mismatchStatus); } if (csb->collectingDependencies() && !node->procedure->isSubRoutine()) @@ -1262,24 +1290,32 @@ void ProcedureSourceNode::genBlr(DsqlCompilerScratch* dsqlScratch) { const dsql_prc* dsqlProcedure = dsqlContext->ctx_procedure; - if (dsqlInputArgNames) + if (dsqlInputArgNames || dsqlName.schema != dsqlScratch->ddlSchema) { dsqlScratch->appendUChar(blr_select_procedure); - dsqlScratch->appendUChar(blr_invsel_procedure_type); + dsqlScratch->appendUChar(blr_invsel_procedure_id); - if (dsqlName.package.hasData()) - { - dsqlScratch->appendUChar(blr_invsel_procedure_type_packaged); - dsqlScratch->appendMetaString(dsqlName.package.c_str()); - } + if (dsqlProcedure->prc_flags & PRC_subproc) + dsqlScratch->appendUChar(blr_invsel_procedure_id_sub); else { - dsqlScratch->appendUChar((dsqlProcedure->prc_flags & PRC_subproc) ? - blr_invsel_procedure_type_sub : blr_invsel_procedure_type_standalone); + if (dsqlName.schema != dsqlScratch->ddlSchema) + { + dsqlScratch->appendUChar(blr_invsel_procedure_id_schema); + dsqlScratch->appendMetaString(dsqlName.schema.c_str()); + } + + if (dsqlName.package.hasData()) + { + dsqlScratch->appendUChar(blr_invsel_procedure_id_package); + dsqlScratch->appendMetaString(dsqlName.package.c_str()); + } } - dsqlScratch->appendMetaString(dsqlName.identifier.c_str()); + dsqlScratch->appendUChar(blr_invsel_procedure_id_name); + dsqlScratch->appendMetaString(dsqlName.object.c_str()); + dsqlScratch->appendUChar(blr_end); // Input parameters. if (inputSources) @@ -1309,7 +1345,9 @@ void ProcedureSourceNode::genBlr(DsqlCompilerScratch* dsqlScratch) if (dsqlContext->ctx_alias.hasData()) { dsqlScratch->appendUChar(blr_invsel_procedure_alias); - dsqlScratch->appendMetaString(dsqlContext->ctx_alias.c_str()); + + const auto contextAliases = dsqlContext->getConcatenatedAlias(); + dsqlScratch->appendMetaString(contextAliases.c_str()); } dsqlScratch->appendUChar(blr_end); @@ -1320,8 +1358,10 @@ void ProcedureSourceNode::genBlr(DsqlCompilerScratch* dsqlScratch) if (dsqlProcedure->prc_flags & PRC_subproc) { dsqlScratch->appendUChar(blr_subproc); - dsqlScratch->appendMetaString(dsqlProcedure->prc_name.identifier.c_str()); - dsqlScratch->appendMetaString(dsqlContext->ctx_alias.c_str()); + dsqlScratch->appendMetaString(dsqlProcedure->prc_name.object.c_str()); + + const auto contextAliases = dsqlContext->getConcatenatedAlias(); + dsqlScratch->appendMetaString(contextAliases.c_str()); } else { @@ -1338,17 +1378,20 @@ void ProcedureSourceNode::genBlr(DsqlCompilerScratch* dsqlScratch) { dsqlScratch->appendUChar(dsqlContext->ctx_alias.hasData() ? blr_procedure4 : blr_procedure3); dsqlScratch->appendMetaString(dsqlProcedure->prc_name.package.c_str()); - dsqlScratch->appendMetaString(dsqlProcedure->prc_name.identifier.c_str()); + dsqlScratch->appendMetaString(dsqlProcedure->prc_name.object.c_str()); } else { dsqlScratch->appendUChar(dsqlContext->ctx_alias.hasData() ? blr_procedure2 : blr_procedure); - dsqlScratch->appendMetaString(dsqlProcedure->prc_name.identifier.c_str()); + dsqlScratch->appendMetaString(dsqlProcedure->prc_name.object.c_str()); } } if (dsqlContext->ctx_alias.hasData()) - dsqlScratch->appendMetaString(dsqlContext->ctx_alias.c_str()); + { + const auto contextAliases = dsqlContext->getConcatenatedAlias(); + dsqlScratch->appendMetaString(contextAliases.c_str()); + } } GEN_stuff_context(dsqlScratch, dsqlContext); @@ -3308,8 +3351,8 @@ void RseNode::planCheck(const CompilerScratch* csb) const if (!csb->csb_rpt[stream].csb_plan) { - const auto name = relation ? relation->rel_name : - procedure ? procedure->getName().toString() : ""; + const auto name = relation ? relation->rel_name.toQuotedString() : + procedure ? procedure->getName().toQuotedString() : ""; ERR_post(Arg::Gds(isc_no_stream_plan) << Arg::Str(name)); } @@ -3357,7 +3400,8 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan) fb_assert(planRelation || planProcedure); const auto name = planRelation ? planRelation->rel_name : - planProcedure ? planProcedure->getName().toString() : ""; + planProcedure ? planProcedure->getName() : + QualifiedName(); // If the plan references a view, find the real base relation // we are interested in by searching the view map @@ -3368,7 +3412,8 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan) if (tail->csb_map) { auto tailName = tail->csb_relation ? tail->csb_relation->rel_name : - tail->csb_procedure ? tail->csb_procedure->getName().toString() : ""; + tail->csb_procedure ? tail->csb_procedure->getName() : + QualifiedName(); // If the user has specified an alias, skip past it to find the alias // for the base table (if multiple aliases are specified) @@ -3378,9 +3423,9 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan) if (planAlias.hasData()) { const auto spacePos = planAlias.find_first_of(' '); - const auto subAlias = planAlias.substr(0, spacePos); + const auto subAlias = planAlias.substr(0, spacePos); // FIXME: - if (tailName == subAlias || tailAlias == subAlias) + if (tailName.object == subAlias || tailAlias == subAlias) // FIXME: { planAlias = planAlias.substr(spacePos); planAlias.ltrim(); @@ -3413,7 +3458,7 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan) else { // view %s has more than one base relation; use aliases to distinguish - ERR_post(Arg::Gds(isc_view_alias) << Arg::Str(name)); + ERR_post(Arg::Gds(isc_view_alias) << name.toQuotedString()); } break; @@ -3429,7 +3474,7 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan) if (planAlias.isEmpty()) { auto duplicateMap = mapBase; - MetaName duplicateName; + QualifiedName duplicateName; map = nullptr; @@ -3444,16 +3489,19 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan) (procedure && planProcedure && procedure->getId() == planProcedure->getId())) { - if (duplicateName.hasData()) + if (duplicateName.object.hasData()) { // table %s is referenced twice in view; use an alias to distinguish ERR_post(Arg::Gds(isc_duplicate_base_table) << - Arg::Str(duplicateName)); + duplicateName.toQuotedString()); } else { - duplicateName = relation ? relation->rel_name : - procedure ? procedure->getName().toString() : ""; + duplicateName = + relation ? relation->rel_name : + procedure ? procedure->getName() : + QualifiedName(); + map = duplicateMap; tail = duplicateTail; } @@ -3471,7 +3519,7 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan) tail = &csb->csb_rpt[*map]; tailName = tail->csb_relation ? tail->csb_relation->rel_name : - tail->csb_procedure ? tail->csb_procedure->getName().toString() : ""; + tail->csb_procedure ? tail->csb_procedure->getName() : QualifiedName(); // Match the user-supplied alias with the alias supplied // with the view definition. Failing that, try the base @@ -3480,9 +3528,9 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan) tailAlias = tail->csb_alias ? *tail->csb_alias : ""; const auto spacePos = planAlias.find_first_of(' '); - const auto subAlias = planAlias.substr(0, spacePos); + const auto subAlias = planAlias.substr(0, spacePos); // FIXME: - if (tailName == subAlias || tailAlias == subAlias) + if (tailName.object == subAlias || tailAlias == subAlias) // FIXME: { // Skip past the alias planAlias = planAlias.substr(spacePos); @@ -3494,7 +3542,7 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan) if (!*map) { // table or procedure %s is referenced in the plan but not the from list - ERR_post(Arg::Gds(isc_stream_not_found) << Arg::Str(name)); + ERR_post(Arg::Gds(isc_stream_not_found) << name.toQuotedString()); } } @@ -3503,7 +3551,7 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan) if (!map || !*map) { // table or procedure %s is referenced in the plan but not the from list - ERR_post(Arg::Gds(isc_stream_not_found) << Arg::Str(name)); + ERR_post(Arg::Gds(isc_stream_not_found) << name.toQuotedString()); } plan->recordSourceNode->setStream(*map); @@ -3514,7 +3562,7 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan) if (!tail->csb_relation && !tail->csb_procedure) { // table or procedure %s is referenced in the plan but not the from list - ERR_post(Arg::Gds(isc_stream_not_found) << Arg::Str(name)); + ERR_post(Arg::Gds(isc_stream_not_found) << name.toQuotedString()); } if ((tail->csb_relation && planRelation && @@ -3523,7 +3571,7 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan) tail->csb_procedure->getId() != planProcedure->getId() && !viewProcedure)) { // table or procedure %s is referenced in the plan but not the from list - ERR_post(Arg::Gds(isc_stream_not_found) << Arg::Str(name)); + ERR_post(Arg::Gds(isc_stream_not_found) << name.toQuotedString()); } // Check if we already have a plan for this stream @@ -3531,7 +3579,7 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan) if (tail->csb_plan) { // table or procedure %s is referenced more than once in plan; use aliases to distinguish - ERR_post(Arg::Gds(isc_stream_twice) << Arg::Str(name)); + ERR_post(Arg::Gds(isc_stream_twice) << name.toQuotedString()); } tail->csb_plan = plan; @@ -3658,12 +3706,12 @@ RseNode* SelectExprNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) static RecordSourceNode* dsqlPassRelProc(DsqlCompilerScratch* dsqlScratch, RecordSourceNode* source) { bool couldBeCte = true; - MetaName relName; + QualifiedName relName; string relAlias; if (const auto procNode = nodeAs(source)) { - relName = procNode->dsqlName.identifier; + relName = procNode->dsqlName; relAlias = procNode->alias; couldBeCte = !procNode->inputSources && procNode->dsqlName.package.isEmpty(); } @@ -3676,10 +3724,12 @@ static RecordSourceNode* dsqlPassRelProc(DsqlCompilerScratch* dsqlScratch, Recor else fb_assert(false); - if (relAlias.isEmpty()) - relAlias = relName.c_str(); + couldBeCte = couldBeCte && relName.schema.isEmpty() && relName.package.isEmpty(); - SelectExprNode* cte = couldBeCte ? dsqlScratch->findCTE(relName) : NULL; + if (relAlias.isEmpty()) + relAlias = relName.object.c_str(); + + SelectExprNode* cte = couldBeCte ? dsqlScratch->findCTE(relName.object) : NULL; if (!cte) return PASS1_relation(dsqlScratch, source); @@ -3692,7 +3742,7 @@ static RecordSourceNode* dsqlPassRelProc(DsqlCompilerScratch* dsqlScratch, Recor { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << // Recursive CTE member (%s) can refer itself only in FROM clause - Arg::Gds(isc_dsql_cte_wrong_reference) << relName); + Arg::Gds(isc_dsql_cte_wrong_reference) << relName.toQuotedString()); } for (Stack::const_iterator stack(dsqlScratch->currCtes); stack.hasData(); ++stack) @@ -3702,7 +3752,7 @@ static RecordSourceNode* dsqlPassRelProc(DsqlCompilerScratch* dsqlScratch, Recor { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << // CTE %s has cyclic dependencies - Arg::Gds(isc_dsql_cte_cycle) << relName); + Arg::Gds(isc_dsql_cte_cycle) << relName.toQuotedString()); } } @@ -4056,7 +4106,7 @@ static ValueExprNode* resolveUsingField(DsqlCompilerScratch* dsqlScratch, const { string qualifier; qualifier.printf("<%s side of USING>", side); - PASS1_field_unknown(qualifier.c_str(), name.c_str(), flawedNode); + PASS1_field_unknown(qualifier.c_str(), name.toQuotedString().c_str(), flawedNode); } DsqlAliasNode* aliasNode; diff --git a/src/jrd/RecordSourceNodes.h b/src/jrd/RecordSourceNodes.h index ce4f7c0d51..bbc45ee152 100644 --- a/src/jrd/RecordSourceNodes.h +++ b/src/jrd/RecordSourceNodes.h @@ -147,7 +147,7 @@ public: SLONG relationId; SLONG indexId; - MetaName indexName; + QualifiedName indexName; }; struct AccessType @@ -192,14 +192,14 @@ public: private: dsql_ctx* dsqlPassAliasList(DsqlCompilerScratch* dsqlScratch); static dsql_ctx* dsqlPassAlias(DsqlCompilerScratch* dsqlScratch, DsqlContextStack& stack, - const MetaName& alias); + const QualifiedName& alias); public: Type const type; AccessType* accessType; RecordSourceNode* recordSourceNode; Firebird::Array > subNodes; - Firebird::ObjectsArray* dsqlNames; + Firebird::ObjectsArray* dsqlNames; }; class InversionNode @@ -354,7 +354,7 @@ public: class RelationSourceNode final : public TypedNode { public: - explicit RelationSourceNode(MemoryPool& pool, const MetaName& aDsqlName = NULL) + explicit RelationSourceNode(MemoryPool& pool, const QualifiedName& aDsqlName = {}) : TypedNode(pool), dsqlName(pool, aDsqlName), alias(pool), @@ -416,7 +416,7 @@ public: virtual RecordSource* compile(thread_db* tdbb, Optimizer* opt, bool innerSubStream); public: - MetaName dsqlName; + QualifiedName dsqlName; Firebird::string alias; // SQL alias for the relation jrd_rel* relation; @@ -431,7 +431,7 @@ class ProcedureSourceNode final : public TypedNode(pool), dsqlName(pool, aDsqlName), alias(pool) diff --git a/src/jrd/Relation.cpp b/src/jrd/Relation.cpp index f379ba4c1f..38ef09e1a1 100644 --- a/src/jrd/Relation.cpp +++ b/src/jrd/Relation.cpp @@ -133,12 +133,12 @@ RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, TraNumber tran, bool a for (auto& idx : indices) { - MetaName idx_name; + QualifiedName idx_name; MET_lookup_index(tdbb, idx_name, this->rel_name, idx.idx_id + 1); idx.idx_root = 0; SelectivityList selectivity(*pool); - IDX_create_index(tdbb, this, &idx, idx_name.c_str(), NULL, idxTran, selectivity); + IDX_create_index(tdbb, this, &idx, idx_name, NULL, idxTran, selectivity); #ifdef VIO_DEBUG VIO_trace(DEBUG_WRITES, diff --git a/src/jrd/Relation.h b/src/jrd/Relation.h index f2784c2bf6..0e39b8e2b5 100644 --- a/src/jrd/Relation.h +++ b/src/jrd/Relation.h @@ -44,7 +44,7 @@ class ViewContext { public: explicit ViewContext(MemoryPool& p, const TEXT* context_name, - const TEXT* relation_name, USHORT context, + const QualifiedName& relation_name, USHORT context, ViewContextType type) : vcx_context_name(p, context_name, fb_strlen(context_name)), vcx_relation_name(relation_name), @@ -59,7 +59,7 @@ public: } const Firebird::string vcx_context_name; - const MetaName vcx_relation_name; + const QualifiedName vcx_relation_name; const USHORT vcx_context; const ViewContextType vcx_type; }; @@ -232,9 +232,9 @@ public: ULONG rel_flags; Format* rel_current_format; // Current record format - MetaName rel_name; // ascii relation name + QualifiedName rel_name; // ascii relation name MetaName rel_owner_name; // ascii owner - MetaName rel_security_name; // security class name for relation + QualifiedName rel_security_name; // security class name for relation vec* rel_formats; // Known record formats vec* rel_fields; // vector of field blocks @@ -493,8 +493,8 @@ public: ArrayField* fld_array; // array description, if array MetaName fld_name; // Field name MetaName fld_security_name; // security class name for field - MetaName fld_generator_name; // identity generator name - MetaNamePair fld_source_rel_field; // Relation/field source name + QualifiedName fld_generator_name; // identity generator name + QualifiedNameMetaNamePair fld_source_rel_field; // Relation/field source name std::optional fld_identity_type; USHORT fld_flags; diff --git a/src/jrd/Routine.cpp b/src/jrd/Routine.cpp index 4876f5d5f7..11d539640f 100644 --- a/src/jrd/Routine.cpp +++ b/src/jrd/Routine.cpp @@ -142,7 +142,7 @@ void Routine::checkReload(thread_db* tdbb) string err; err.printf("Recompile of %s \"%s\" failed", getObjectType() == obj_udf ? "FUNCTION" : "PROCEDURE", - getName().toString().c_str()); + getName().toQuotedString().c_str()); (Arg::Gds(isc_random) << Arg::Str(err)).raise(); } @@ -172,7 +172,7 @@ void Routine::parseBlr(thread_db* tdbb, CompilerScratch* csb, bid* blob_id, bid* flags &= ~Routine::FLAG_RELOAD; Statement* statement = getStatement(); - PAR_blr(tdbb, NULL, tmp.begin(), (ULONG) tmp.getCount(), NULL, &csb, &statement, false, 0); + PAR_blr(tdbb, &name.schema, NULL, tmp.begin(), (ULONG) tmp.getCount(), NULL, &csb, &statement, false, 0); setStatement(statement); if (csb->csb_g_flags & csb_reload) @@ -188,23 +188,10 @@ void Routine::parseMessages(thread_db* tdbb, CompilerScratch* csb, BlrReader blr if (blrReader.getLength() < 2) status_exception::raise(Arg::Gds(isc_metadata_corrupt)); + csb->csb_schema = name.schema; csb->csb_blr_reader = blrReader; - const SSHORT version = csb->csb_blr_reader.getByte(); - - switch (version) - { - case blr_version4: - case blr_version5: - //case blr_version6: - break; - - default: - status_exception::raise( - Arg::Gds(isc_metadata_corrupt) << - Arg::Gds(isc_wroblrver2) << Arg::Num(blr_version4) << Arg::Num(blr_version5/*6*/) << - Arg::Num(version)); - } + csb->csb_blr_reader.parseHeader(); if (csb->csb_blr_reader.getByte() != blr_begin) status_exception::raise(Arg::Gds(isc_metadata_corrupt)); @@ -275,7 +262,7 @@ void Routine::release(thread_db* tdbb) string buffer; buffer.printf( "Called from CMP_decrement():\n\t Decrementing use count of %s\n", - getName().toString().c_str()); + getName().toQuotedString().c_str()); JRD_print_procedure_info(tdbb, buffer.c_str()); } #endif @@ -364,8 +351,8 @@ void Routine::remove(thread_db* tdbb) { // Fully clear routine block. Some pieces of code check for empty // routine name, this is why we do it. - setName(QualifiedName()); - setSecurityName(""); + setName({}); + setSecurityName({}); setDefaultCount(0); releaseExternal(); flags |= FLAG_CLEARED; diff --git a/src/jrd/Routine.h b/src/jrd/Routine.h index 6481ab29b3..7397567a5f 100644 --- a/src/jrd/Routine.h +++ b/src/jrd/Routine.h @@ -101,8 +101,8 @@ namespace Jrd const QualifiedName& getName() const { return name; } void setName(const QualifiedName& value) { name = value; } - const MetaName& getSecurityName() const { return securityName; } - void setSecurityName(const MetaName& value) { securityName = value; } + const QualifiedName& getSecurityName() const { return securityName; } + void setSecurityName(const QualifiedName& value) { securityName = value; } /*const*/ Statement* getStatement() const { return statement; } void setStatement(Statement* value); @@ -163,8 +163,8 @@ namespace Jrd private: USHORT id; // routine ID - QualifiedName name; // routine name - MetaName securityName; // security class name + QualifiedName name; // routine name + QualifiedName securityName; // security class name Statement* statement; // compiled routine statement bool subRoutine; // Is this a subroutine? bool implemented; // Is the packaged routine missing the body/entrypoint? diff --git a/src/jrd/RuntimeStatistics.cpp b/src/jrd/RuntimeStatistics.cpp index d854b484c8..cdc4e4b092 100644 --- a/src/jrd/RuntimeStatistics.cpp +++ b/src/jrd/RuntimeStatistics.cpp @@ -80,7 +80,8 @@ void RuntimeStatistics::addRelCounts(const RelCounters& other, bool add) PerformanceInfo* RuntimeStatistics::computeDifference(Attachment* att, const RuntimeStatistics& new_stat, PerformanceInfo& dest, - TraceCountsArray& temp) + TraceCountsArray& temp, + ObjectsArray& tempNames) { // NOTE: we do not initialize dest.pin_time. This must be done by the caller @@ -92,6 +93,7 @@ PerformanceInfo* RuntimeStatistics::computeDifference(Attachment* att, // Calculate relation-level statistics temp.clear(); + tempNames.clear(); // This loop assumes that base array is smaller than new one RelCounters::iterator base_cnts = rel_counts.begin(); @@ -115,7 +117,16 @@ PerformanceInfo* RuntimeStatistics::computeDifference(Attachment* att, TraceCounts traceCounts; traceCounts.trc_relation_id = rel_id; traceCounts.trc_counters = base_cnts->getCounterVector(); - traceCounts.trc_relation_name = relation ? relation->rel_name.c_str() : NULL; + + if (relation) + { + auto& tempName = tempNames.add(); + tempName = relation->rel_name.toQuotedString(); + traceCounts.trc_relation_name = tempName.c_str(); + } + else + traceCounts.trc_relation_name = nullptr; + temp.add(traceCounts); } @@ -132,7 +143,16 @@ PerformanceInfo* RuntimeStatistics::computeDifference(Attachment* att, TraceCounts traceCounts; traceCounts.trc_relation_id = rel_id; traceCounts.trc_counters = new_cnts->getCounterVector(); - traceCounts.trc_relation_name = relation ? relation->rel_name.c_str() : NULL; + + if (relation) + { + auto& tempName = tempNames.add(); + tempName = relation->rel_name.toQuotedString(); + traceCounts.trc_relation_name = tempName.c_str(); + } + else + traceCounts.trc_relation_name = nullptr; + temp.add(traceCounts); } }; diff --git a/src/jrd/RuntimeStatistics.h b/src/jrd/RuntimeStatistics.h index 79df6d7bca..2c34096be6 100644 --- a/src/jrd/RuntimeStatistics.h +++ b/src/jrd/RuntimeStatistics.h @@ -24,6 +24,7 @@ #define JRD_RUNTIME_STATISTICS_H #include "../common/classes/alloc.h" +#include "../common/classes/fb_string.h" #include "../common/classes/objects_array.h" #include "../common/classes/init.h" #include "../common/classes/tree.h" @@ -239,7 +240,7 @@ public: // Calculate difference between counts stored in this object and current // counts of given request. Counts stored in object are destroyed. Firebird::PerformanceInfo* computeDifference(Attachment* att, const RuntimeStatistics& new_stat, - Firebird::PerformanceInfo& dest, TraceCountsArray& temp); + Firebird::PerformanceInfo& dest, TraceCountsArray& temp, Firebird::ObjectsArray& tempNames); // add difference between newStats and baseStats to our counters // newStats and baseStats must be "in-sync" diff --git a/src/jrd/Statement.cpp b/src/jrd/Statement.cpp index 3aac47c4d1..4324dd254c 100644 --- a/src/jrd/Statement.cpp +++ b/src/jrd/Statement.cpp @@ -568,17 +568,17 @@ void Statement::verifyAccess(thread_db* tdbb) UserId* effectiveUser = userName.hasData() ? attachment->getUserId(userName) : attachment->att_ss_user; AutoSetRestore userIdHolder(&attachment->att_ss_user, effectiveUser); - const SecurityClass* sec_class = SCL_get_class(tdbb, access.acc_security_name.c_str()); + const SecurityClass* sec_class = SCL_get_class(tdbb, access.acc_security_name); if (routine->getName().package.isEmpty()) { - SCL_check_access(tdbb, sec_class, aclType, routine->getName().identifier, - access.acc_mask, access.acc_type, true, access.acc_name, access.acc_r_name); + SCL_check_access(tdbb, sec_class, aclType, routine->getName(), + access.acc_mask, access.acc_type, true, access.acc_name, access.acc_col_name); } else { - SCL_check_access(tdbb, sec_class, id_package, routine->getName().package, - access.acc_mask, access.acc_type, true, access.acc_name, access.acc_r_name); + SCL_check_access(tdbb, sec_class, id_package, routine->getName().getSchemaAndPackage(), + access.acc_mask, access.acc_type, true, access.acc_name, access.acc_col_name); } } } @@ -593,7 +593,7 @@ void Statement::verifyAccess(thread_db* tdbb) for (const AccessItem* access = accessList.begin(); access != accessList.end(); ++access) { - MetaName objName; + QualifiedName objName; SLONG objType = 0; MetaName userName; @@ -615,7 +615,7 @@ void Statement::verifyAccess(thread_db* tdbb) objType = id_package; break; case obj_type_MAX: // CallerName() constructor - fb_assert(transaction->tra_caller_name.name.isEmpty()); + fb_assert(transaction->tra_caller_name.name.object.isEmpty()); break; default: fb_assert(false); @@ -636,10 +636,10 @@ void Statement::verifyAccess(thread_db* tdbb) UserId* effectiveUser = userName.hasData() ? attachment->getUserId(userName) : attachment->att_ss_user; AutoSetRestore userIdHolder(&attachment->att_ss_user, effectiveUser); - const SecurityClass* sec_class = SCL_get_class(tdbb, access->acc_security_name.c_str()); + const SecurityClass* sec_class = SCL_get_class(tdbb, access->acc_security_name); SCL_check_access(tdbb, sec_class, objType, objName, - access->acc_mask, access->acc_type, true, access->acc_name, access->acc_r_name); + access->acc_mask, access->acc_type, true, access->acc_name, access->acc_col_name); } } @@ -778,7 +778,7 @@ void Statement::verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation, continue; } if (access->acc_type == obj_column && - (ownerRelation->rel_name == access->acc_r_name)) + (ownerRelation->rel_name == access->acc_name)) { continue; } @@ -798,10 +798,10 @@ void Statement::verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation, UserId* effectiveUser = userName.hasData() ? attachment->getUserId(userName) : attachment->att_ss_user; AutoSetRestore userIdHolder(&attachment->att_ss_user, effectiveUser); - const SecurityClass* sec_class = SCL_get_class(tdbb, access->acc_security_name.c_str()); + const SecurityClass* sec_class = SCL_get_class(tdbb, access->acc_security_name); SCL_check_access(tdbb, sec_class, id_trigger, t.statement->triggerName, access->acc_mask, - access->acc_type, true, access->acc_name, access->acc_r_name); + access->acc_type, true, access->acc_name, access->acc_col_name); } } } diff --git a/src/jrd/Statement.h b/src/jrd/Statement.h index da27d6ff88..6c5cbdd856 100644 --- a/src/jrd/Statement.h +++ b/src/jrd/Statement.h @@ -103,7 +103,7 @@ public: ResourceList resources; // Resources (relations and indices) const jrd_prc* procedure; // procedure, if any const Function* function; // function, if any - MetaName triggerName; // name of request (trigger), if any + QualifiedName triggerName; // name of request (trigger), if any Jrd::UserId* triggerInvoker; // user name if trigger run with SQL SECURITY DEFINER Statement* parentStatement; // Sub routine's parent statement Firebird::Array subStatements; // Array of subroutines' statements diff --git a/src/jrd/SysFunction.cpp b/src/jrd/SysFunction.cpp index 027fa1a1ae..9bf5e4aa44 100644 --- a/src/jrd/SysFunction.cpp +++ b/src/jrd/SysFunction.cpp @@ -398,6 +398,8 @@ const char CURRENT_USER_NAME[] = "CURRENT_USER", CURRENT_ROLE_NAME[] = "CURRENT_ROLE", SERVER_PID_NAME[] = "SERVER_PID", + CURRENT_SCHEMA_NAME[] = "CURRENT_SCHEMA", + SEARCH_PATH[] = "SEARCH_PATH", SESSION_IDLE_TIMEOUT[] = "SESSION_IDLE_TIMEOUT", STATEMENT_TIMEOUT[] = "STATEMENT_TIMEOUT", EFFECTIVE_USER_NAME[] = "EFFECTIVE_USER", @@ -414,6 +416,7 @@ const char // DDL_TRIGGER namespace DDL_EVENT_NAME[] = "DDL_EVENT", EVENT_TYPE_NAME[] = "EVENT_TYPE", + SCHEMA_NAME[] = "SCHEMA_NAME", OBJECT_NAME[] = "OBJECT_NAME", OLD_OBJECT_NAME[] = "OLD_OBJECT_NAME", NEW_OBJECT_NAME[] = "NEW_OBJECT_NAME", @@ -4713,6 +4716,26 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar } else if (nameStr == SERVER_PID_NAME) resultStr.printf("%d", getpid()); + else if (nameStr == CURRENT_SCHEMA_NAME) + { + QualifiedName name; + attachment->qualifyNewName(tdbb, name); + + if (name.schema.isEmpty()) + return nullptr; + + resultStr = name.schema.c_str(); + } + else if (nameStr == SEARCH_PATH) + { + for (const auto& schema : *attachment->att_schema_search_path) + { + if (resultStr.hasData()) + resultStr += ", "; + + resultStr += schema.toQuotedString(); + } + } else if (nameStr == SESSION_IDLE_TIMEOUT) resultStr.printf("%" ULONGFORMAT, attachment->getIdleTimeout()); else if (nameStr == STATEMENT_TIMEOUT) @@ -4805,25 +4828,30 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar resultStr = context->objectType; else if (nameStr == DDL_EVENT_NAME) resultStr = context->eventType + " " + context->objectType; + else if (nameStr == SCHEMA_NAME) + { + resultStr = context->objectName.schema.c_str(); + resultType = ttype_metadata; + } else if (nameStr == OBJECT_NAME) { - resultStr = context->objectName.c_str(); + resultStr = context->objectName.object.c_str(); resultType = ttype_metadata; } else if (nameStr == OLD_OBJECT_NAME) { - if (context->oldObjectName.isEmpty()) + if (context->oldObjectName.object.isEmpty()) return NULL; - resultStr = context->oldObjectName.c_str(); + resultStr = context->oldObjectName.object.c_str(); resultType = ttype_metadata; } else if (nameStr == NEW_OBJECT_NAME) { - if (context->newObjectName.isEmpty()) + if (context->newObjectName.object.isEmpty()) return NULL; - resultStr = context->newObjectName.c_str(); + resultStr = context->newObjectName.object.c_str(); resultType = ttype_metadata; } else if (nameStr == SQL_TEXT_NAME) @@ -5374,8 +5402,9 @@ dsc* evlMakeDbkey(Jrd::thread_db* tdbb, const SysFunction* function, const NestV { // MAKE_DBKEY ( REL_NAME | REL_ID, RECNUM [, DPNUM [, PPNUM] ] ) - Database* const dbb = tdbb->getDatabase(); - Request* const request = tdbb->getRequest(); + const auto dbb = tdbb->getDatabase(); + const auto attachment = tdbb->getAttachment(); + const auto request = tdbb->getRequest(); fb_assert(args.getCount() >= 2 && args.getCount() <= 4); @@ -5387,12 +5416,14 @@ dsc* evlMakeDbkey(Jrd::thread_db* tdbb, const SysFunction* function, const NestV if (argDsc->isText()) { - MetaName relName; - CVT2_make_metaname(argDsc, relName, tdbb->getAttachment()->att_dec_status); + UCHAR* argPtr; + USHORT len = MOV_get_string(tdbb, argDsc, &argPtr, NULL, 0); + auto relName = QualifiedName::parseSchemaObject(string((const char*) argPtr, len)); + attachment->qualifyExistingName(tdbb, relName, obj_relation); const jrd_rel* const relation = MET_lookup_relation(tdbb, relName); if (!relation) - (Arg::Gds(isc_relnotdef) << Arg::Str(relName)).raise(); + (Arg::Gds(isc_relnotdef) << relName.toQuotedString()).raise(); relId = relation->rel_id; } diff --git a/src/jrd/SystemTriggers.epp b/src/jrd/SystemTriggers.epp index fc3d3d407f..de7be4189d 100644 --- a/src/jrd/SystemTriggers.epp +++ b/src/jrd/SystemTriggers.epp @@ -24,6 +24,7 @@ #include #include "firebird/Interface.h" #include "../jrd/SystemTriggers.h" +#include "../jrd/acl.h" #include "../jrd/constants.h" #include "../jrd/ids.h" #include "../jrd/ini.h" @@ -48,18 +49,23 @@ namespace void beforeDeleteCheckConstraint(thread_db* tdbb, Record* record) { const auto transaction = tdbb->getTransaction(); + dsc desc; + + MetaName schemaName; + if (EVL_field(nullptr, record, f_ccon_schema, &desc)) + MOV_get_metaname(tdbb, &desc, schemaName); - dsc descConstraintName; MetaName constraintName; - if (EVL_field(nullptr, record, f_ccon_cname, &descConstraintName)) - MOV_get_metaname(tdbb, &descConstraintName, constraintName); + if (EVL_field(nullptr, record, f_ccon_cname, &desc)) + MOV_get_metaname(tdbb, &desc, constraintName); static const CachedRequestId requestCacheId; AutoCacheRequest request(tdbb, requestCacheId); FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RLC IN RDB$RELATION_CONSTRAINTS - WITH RLC.RDB$CONSTRAINT_NAME EQ constraintName.c_str() + WITH RLC.RDB$SCHEMA_NAME EQ schemaName.c_str() AND + RLC.RDB$CONSTRAINT_NAME EQ constraintName.c_str() { ERR_post(Arg::Gds(isc_check_cnstrnt_del)); } @@ -71,6 +77,10 @@ void afterDeleteCheckConstraint(thread_db* tdbb, Record* record) const auto transaction = tdbb->getTransaction(); dsc desc; + MetaName schemaName; + if (EVL_field(nullptr, record, f_ccon_schema, &desc)) + MOV_get_metaname(tdbb, &desc, schemaName); + MetaName constraintName; if (EVL_field(nullptr, record, f_ccon_cname, &desc)) MOV_get_metaname(tdbb, &desc, constraintName); @@ -85,8 +95,10 @@ void afterDeleteCheckConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request1 TRANSACTION_HANDLE transaction) TRG IN RDB$TRIGGERS CROSS RLC IN RDB$RELATION_CONSTRAINTS - WITH RLC.RDB$CONSTRAINT_NAME = constraintName.c_str() AND + WITH RLC.RDB$SCHEMA_NAME EQ schemaName.c_str() AND + RLC.RDB$CONSTRAINT_NAME = constraintName.c_str() AND RLC.RDB$CONSTRAINT_TYPE = FOREIGN_KEY AND + TRG.RDB$SCHEMA_NAME = RLC.RDB$SCHEMA_NAME AND TRG.RDB$TRIGGER_NAME = triggerName.c_str() { ERASE TRG; @@ -99,7 +111,9 @@ void afterDeleteCheckConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) RFR IN RDB$RELATION_FIELDS CROSS RLC IN RDB$RELATION_CONSTRAINTS - WITH RFR.RDB$FIELD_NAME = triggerName.c_str() AND + WITH RFR.RDB$SCHEMA_NAME = schemaName.c_str() AND + RFR.RDB$FIELD_NAME = triggerName.c_str() AND + RLC.RDB$SCHEMA_NAME = RFR.RDB$SCHEMA_NAME AND RLC.RDB$CONSTRAINT_NAME = constraintName.c_str() AND RLC.RDB$RELATION_NAME = RFR.RDB$RELATION_NAME AND RLC.RDB$CONSTRAINT_TYPE = NOT_NULL_CNSTRT @@ -116,8 +130,10 @@ void afterDeleteCheckConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request3 TRANSACTION_HANDLE transaction) TRG IN RDB$TRIGGERS CROSS RLC IN RDB$RELATION_CONSTRAINTS - WITH RLC.RDB$CONSTRAINT_NAME = constraintName.c_str() AND + WITH RLC.RDB$SCHEMA_NAME EQ schemaName.c_str() AND + RLC.RDB$CONSTRAINT_NAME = constraintName.c_str() AND RLC.RDB$CONSTRAINT_TYPE = CHECK_CNSTRT AND + TRG.RDB$SCHEMA_NAME = RLC.RDB$SCHEMA_NAME AND TRG.RDB$RELATION_NAME = RLC.RDB$RELATION_NAME AND TRG.RDB$TRIGGER_NAME = triggerName.c_str() { @@ -129,11 +145,15 @@ void afterDeleteCheckConstraint(thread_db* tdbb, Record* record) void beforeUpdateCheckConstraint(thread_db* tdbb, Record* orgRecord, Record* newRecord) { const auto transaction = tdbb->getTransaction(); + dsc desc; + + MetaName schemaName; + if (EVL_field(nullptr, orgRecord, f_ccon_schema, &desc)) + MOV_get_metaname(tdbb, &desc, schemaName); - dsc descConstraintName; MetaName constraintName; - if (EVL_field(nullptr, orgRecord, f_ccon_cname, &descConstraintName)) - MOV_get_metaname(tdbb, &descConstraintName, constraintName); + if (EVL_field(nullptr, orgRecord, f_ccon_cname, &desc)) + MOV_get_metaname(tdbb, &desc, constraintName); static const CachedRequestId requestCacheId; AutoCacheRequest request(tdbb, requestCacheId); @@ -141,6 +161,7 @@ void beforeUpdateCheckConstraint(thread_db* tdbb, Record* orgRecord, Record* new FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RLC IN RDB$RELATION_CONSTRAINTS WITH RLC.RDB$CONSTRAINT_TYPE != NOT_NULL_CNSTRT AND + RLC.RDB$SCHEMA_NAME EQ schemaName.c_str() AND RLC.RDB$CONSTRAINT_NAME EQ constraintName.c_str() { ERR_post(Arg::Gds(isc_check_cnstrnt_update)); @@ -151,18 +172,23 @@ void beforeUpdateCheckConstraint(thread_db* tdbb, Record* orgRecord, Record* new void beforeDeleteIndex(thread_db* tdbb, Record* record) { const auto transaction = tdbb->getTransaction(); + dsc desc; + + MetaName schemaName; + if (EVL_field(nullptr, record, f_idx_schema, &desc)) + MOV_get_metaname(tdbb, &desc, schemaName); - dsc descIndexName; MetaName indexName; - if (EVL_field(nullptr, record, f_idx_name, &descIndexName)) - MOV_get_metaname(tdbb, &descIndexName, indexName); + if (EVL_field(nullptr, record, f_idx_name, &desc)) + MOV_get_metaname(tdbb, &desc, indexName); static const CachedRequestId requestCacheId; AutoCacheRequest request(tdbb, requestCacheId); FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RLC IN RDB$RELATION_CONSTRAINTS - WITH RLC.RDB$INDEX_NAME EQ indexName.c_str() + WITH RLC.RDB$SCHEMA_NAME EQ schemaName.c_str() AND + RLC.RDB$INDEX_NAME EQ indexName.c_str() { ERR_post(Arg::Gds(isc_integ_index_del)); } @@ -172,19 +198,26 @@ void beforeDeleteIndex(thread_db* tdbb, Record* record) void beforeUpdateIndex(thread_db* tdbb, Record* orgRecord, Record* newRecord) { const auto transaction = tdbb->getTransaction(); + dsc desc; + + MetaName oldSchemaName; + if (EVL_field(nullptr, orgRecord, f_idx_schema, &desc)) + MOV_get_metaname(tdbb, &desc, oldSchemaName); - dsc descOldIndexName; MetaName oldIndexName; - if (EVL_field(nullptr, orgRecord, f_idx_name, &descOldIndexName)) - MOV_get_metaname(tdbb, &descOldIndexName, oldIndexName); + if (EVL_field(nullptr, orgRecord, f_idx_name, &desc)) + MOV_get_metaname(tdbb, &desc, oldIndexName); static const CachedRequestId request1CacheId; AutoCacheRequest request1(tdbb, request1CacheId); FOR (REQUEST_HANDLE request1 TRANSACTION_HANDLE transaction) RLC IN RDB$RELATION_CONSTRAINTS - WITH RLC.RDB$INDEX_NAME EQ oldIndexName.c_str() + WITH RLC.RDB$SCHEMA_NAME EQ oldSchemaName.c_str() AND + RLC.RDB$INDEX_NAME EQ oldIndexName.c_str() { + dsc descNewSchemaName; + MetaName newSchemaName; dsc descNewIndexName; MetaName newIndexName; dsc descOldRelationName, descNewRelationName; @@ -196,7 +229,8 @@ void beforeUpdateIndex(thread_db* tdbb, Record* orgRecord, Record* newRecord) dsc descOldForeignKey, descNewForeignKey; MetaName oldForeignKey, newForeignKey; - if (EVL_field(nullptr, newRecord, f_idx_name, &descNewIndexName) && + if (EVL_field(nullptr, newRecord, f_idx_schema, &descNewSchemaName) && + EVL_field(nullptr, newRecord, f_idx_name, &descNewIndexName) && EVL_field(nullptr, orgRecord, f_idx_relation, &descOldRelationName) && EVL_field(nullptr, newRecord, f_idx_relation, &descNewRelationName) && EVL_field(nullptr, orgRecord, f_idx_id, &descOldIndexId) && @@ -206,6 +240,7 @@ void beforeUpdateIndex(thread_db* tdbb, Record* orgRecord, Record* newRecord) EVL_field(nullptr, orgRecord, f_idx_foreign, &descOldForeignKey) && EVL_field(nullptr, newRecord, f_idx_foreign, &descNewForeignKey)) { + MOV_get_metaname(tdbb, &descNewSchemaName, newSchemaName); MOV_get_metaname(tdbb, &descNewIndexName, newIndexName); MOV_get_metaname(tdbb, &descOldRelationName, oldRelationName); MOV_get_metaname(tdbb, &descNewRelationName, newRelationName); @@ -216,7 +251,8 @@ void beforeUpdateIndex(thread_db* tdbb, Record* orgRecord, Record* newRecord) MOV_get_metaname(tdbb, &descOldForeignKey, oldForeignKey); MOV_get_metaname(tdbb, &descNewForeignKey, newForeignKey); - if (oldIndexName != newIndexName || + if (oldSchemaName != newSchemaName || + oldIndexName != newIndexName || oldRelationName != newRelationName || oldIndexId != newIndexId || oldSegmentCount != newSegmentCount || @@ -242,9 +278,12 @@ void beforeUpdateIndex(thread_db* tdbb, Record* orgRecord, Record* newRecord) RCL IN RDB$RELATION_CONSTRAINTS CROSS IND1 IN RDB$INDICES CROSS IND2 IN RDB$INDICES - WITH RCL.RDB$INDEX_NAME = oldIndexName.c_str() AND + WITH RCL.RDB$SCHEMA_NAME = oldSchemaName.c_str() AND + RCL.RDB$INDEX_NAME = oldIndexName.c_str() AND + IND1.RDB$SCHEMA_NAME = RCL.RDB$SCHEMA_NAME AND IND1.RDB$INDEX_NAME = RCL.RDB$INDEX_NAME AND - IND2.RDB$FOREIGN_KEY = RCL.RDB$INDEX_NAME + IND2.RDB$FOREIGN_KEY_SCHEMA_NAME = IND1.RDB$SCHEMA_NAME AND + IND2.RDB$FOREIGN_KEY = IND1.RDB$INDEX_NAME { ERR_post(Arg::Gds(isc_integ_index_deactivate)); } @@ -255,7 +294,8 @@ void beforeUpdateIndex(thread_db* tdbb, Record* orgRecord, Record* newRecord) FOR (REQUEST_HANDLE request3 TRANSACTION_HANDLE transaction) RCL IN RDB$RELATION_CONSTRAINTS - WITH RCL.RDB$INDEX_NAME = oldIndexName.c_str() AND + WITH RCL.RDB$SCHEMA_NAME = oldSchemaName.c_str() AND + RCL.RDB$INDEX_NAME = oldIndexName.c_str() AND (RCL.RDB$CONSTRAINT_TYPE = PRIMARY_KEY OR RCL.RDB$CONSTRAINT_TYPE = UNIQUE_CNSTRT OR RCL.RDB$CONSTRAINT_TYPE = FOREIGN_KEY) @@ -274,18 +314,23 @@ void beforeUpdateIndex(thread_db* tdbb, Record* orgRecord, Record* newRecord) void beforeDeleteIndexSegment(thread_db* tdbb, Record* record) { const auto transaction = tdbb->getTransaction(); + dsc desc; + + MetaName schemaName; + if (EVL_field(nullptr, record, f_seg_schema, &desc)) + MOV_get_metaname(tdbb, &desc, schemaName); - dsc descIndexName; MetaName indexName; - if (EVL_field(nullptr, record, f_seg_name, &descIndexName)) - MOV_get_metaname(tdbb, &descIndexName, indexName); + if (EVL_field(nullptr, record, f_seg_name, &desc)) + MOV_get_metaname(tdbb, &desc, indexName); static const CachedRequestId requestCacheId; AutoCacheRequest request(tdbb, requestCacheId); FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RLC IN RDB$RELATION_CONSTRAINTS - WITH RLC.RDB$INDEX_NAME EQ indexName.c_str() + WITH RLC.RDB$SCHEMA_NAME EQ schemaName.c_str() AND + RLC.RDB$INDEX_NAME EQ indexName.c_str() { ERR_post(Arg::Gds(isc_integ_index_seg_del)); } @@ -295,19 +340,26 @@ void beforeDeleteIndexSegment(thread_db* tdbb, Record* record) void beforeUpdateIndexSegment(thread_db* tdbb, Record* orgRecord, Record* newRecord) { const auto transaction = tdbb->getTransaction(); + dsc desc; + + MetaName oldSchemaName; + if (EVL_field(nullptr, orgRecord, f_seg_schema, &desc)) + MOV_get_metaname(tdbb, &desc, oldSchemaName); - dsc descOldIndexName; MetaName oldIndexName; - if (EVL_field(nullptr, orgRecord, f_seg_name, &descOldIndexName)) - MOV_get_metaname(tdbb, &descOldIndexName, oldIndexName); + if (EVL_field(nullptr, orgRecord, f_seg_name, &desc)) + MOV_get_metaname(tdbb, &desc, oldIndexName); static const CachedRequestId requestCacheId; AutoCacheRequest request(tdbb, requestCacheId); FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RLC IN RDB$RELATION_CONSTRAINTS - WITH RLC.RDB$INDEX_NAME EQ oldIndexName.c_str() + WITH RLC.RDB$SCHEMA_NAME EQ oldSchemaName.c_str() AND + RLC.RDB$INDEX_NAME EQ oldIndexName.c_str() { + dsc descNewSchemaName; + MetaName newSchemaName; dsc descNewIndexName; MetaName newIndexName; dsc descOldFieldName, descNewFieldName; @@ -315,19 +367,22 @@ void beforeUpdateIndexSegment(thread_db* tdbb, Record* orgRecord, Record* newRec dsc descOldFieldPosition, descNewFieldPosition; SLONG oldFieldPosition, newFieldPosition; - if (EVL_field(nullptr, newRecord, f_seg_name, &descNewIndexName) && + if (EVL_field(nullptr, newRecord, f_seg_schema, &descNewSchemaName) && + EVL_field(nullptr, newRecord, f_seg_name, &descNewIndexName) && EVL_field(nullptr, orgRecord, f_seg_field, &descOldFieldName) && EVL_field(nullptr, newRecord, f_seg_field, &descNewFieldName) && EVL_field(nullptr, orgRecord, f_seg_position, &descOldFieldPosition) && EVL_field(nullptr, newRecord, f_seg_position, &descNewFieldPosition)) { + MOV_get_metaname(tdbb, &descNewSchemaName, newSchemaName); MOV_get_metaname(tdbb, &descNewIndexName, newIndexName); MOV_get_metaname(tdbb, &descOldFieldName, oldFieldName); MOV_get_metaname(tdbb, &descNewFieldName, newFieldName); oldFieldPosition = MOV_get_long(tdbb, &descOldFieldPosition, 0); newFieldPosition = MOV_get_long(tdbb, &descNewFieldPosition, 0); - if (oldIndexName != newIndexName || + if (newSchemaName != oldSchemaName || + oldIndexName != newIndexName || oldFieldName != newFieldName || oldFieldPosition != newFieldPosition) { @@ -341,12 +396,17 @@ void beforeUpdateIndexSegment(thread_db* tdbb, Record* orgRecord, Record* newRec void beforeUpdateField(thread_db* tdbb, Record* orgRecord, Record* newRecord) { const auto transaction = tdbb->getTransaction(); + dsc desc; - dsc descFieldName; - MetaName fieldName; - if (!EVL_field(nullptr, orgRecord, f_fld_name, &descFieldName)) + MetaName schemaName; + if (!EVL_field(nullptr, orgRecord, f_fld_schema, &desc)) return; - MOV_get_metaname(tdbb, &descFieldName, fieldName); + MOV_get_metaname(tdbb, &desc, schemaName); + + MetaName fieldName; + if (!EVL_field(nullptr, orgRecord, f_fld_name, &desc)) + return; + MOV_get_metaname(tdbb, &desc, fieldName); dsc descOldFieldLength, descNewFieldLength; SLONG oldFieldLength, newFieldLength; @@ -388,10 +448,14 @@ void beforeUpdateField(thread_db* tdbb, Record* orgRecord, Record* newRecord) CROSS IND IN RDB$INDICES CROSS RLC IN RDB$RELATION_CONSTRAINTS CROSS IDS IN RDB$INDEX_SEGMENTS - WITH RFL.RDB$FIELD_SOURCE = fieldName.c_str() AND + WITH RFL.RDB$FIELD_SOURCE_SCHEMA_NAME = schemaName.c_str() AND + RFL.RDB$FIELD_SOURCE = fieldName.c_str() AND + IND.RDB$SCHEMA_NAME = RFL.RDB$SCHEMA_NAME AND IND.RDB$RELATION_NAME = RFL.RDB$RELATION_NAME AND + IDS.RDB$SCHEMA_NAME = IND.RDB$SCHEMA_NAME AND IDS.RDB$INDEX_NAME = IND.RDB$INDEX_NAME AND IDS.RDB$FIELD_NAME = RFL.RDB$FIELD_NAME AND + RLC.RDB$SCHEMA_NAME = IND.RDB$SCHEMA_NAME AND RLC.RDB$INDEX_NAME = IND.RDB$INDEX_NAME { ERR_post(Arg::Gds(isc_integ_index_seg_mod)); @@ -404,11 +468,23 @@ void beforeUpdateField(thread_db* tdbb, Record* orgRecord, Record* newRecord) void beforeInsertRefConstraint(thread_db* tdbb, Record* record) { const auto transaction = tdbb->getTransaction(); + dsc desc; + + MetaName schemaName; + if (EVL_field(nullptr, record, f_refc_schema, &desc)) + MOV_get_metaname(tdbb, &desc, schemaName); + else + schemaName = PUBLIC_SCHEMA; + + MetaName uqSchemaName; + if (EVL_field(nullptr, record, f_refc_uq_schema, &desc)) + MOV_get_metaname(tdbb, &desc, uqSchemaName); + else + uqSchemaName = PUBLIC_SCHEMA; - dsc descConstraintName; MetaName constraintName; - if (EVL_field(nullptr, record, f_refc_cname, &descConstraintName)) - MOV_get_metaname(tdbb, &descConstraintName, constraintName); + if (EVL_field(nullptr, record, f_refc_cname, &desc)) + MOV_get_metaname(tdbb, &desc, constraintName); static const CachedRequestId request1CacheId; AutoCacheRequest request1(tdbb, request1CacheId); @@ -417,6 +493,7 @@ void beforeInsertRefConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request1 TRANSACTION_HANDLE transaction) RLC IN RDB$RELATION_CONSTRAINTS WITH RLC.RDB$CONSTRAINT_TYPE = FOREIGN_KEY AND + RLC.RDB$SCHEMA_NAME = schemaName.c_str() AND RLC.RDB$CONSTRAINT_NAME EQ constraintName.c_str() { fkFound = true; @@ -426,10 +503,9 @@ void beforeInsertRefConstraint(thread_db* tdbb, Record* record) if (!fkFound) ERR_post(Arg::Gds(isc_ref_cnstrnt_notfound)); - dsc descConstraintNameUq; MetaName constraintNameUq; - if (EVL_field(nullptr, record, f_refc_uq, &descConstraintNameUq)) - MOV_get_metaname(tdbb, &descConstraintNameUq, constraintNameUq); + if (EVL_field(nullptr, record, f_refc_uq, &desc)) + MOV_get_metaname(tdbb, &desc, constraintNameUq); static const CachedRequestId request2CacheId; AutoCacheRequest request2(tdbb, request2CacheId); @@ -438,6 +514,7 @@ void beforeInsertRefConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) RLC IN RDB$RELATION_CONSTRAINTS WITH (RLC.RDB$CONSTRAINT_TYPE = PRIMARY_KEY OR RLC.RDB$CONSTRAINT_TYPE = UNIQUE_CNSTRT) AND + RLC.RDB$SCHEMA_NAME = uqSchemaName.c_str() AND RLC.RDB$CONSTRAINT_NAME EQ constraintNameUq.c_str() { pkUniqueFound = true; @@ -453,6 +530,10 @@ void beforeDeleteRelationConstraint(thread_db* tdbb, Record* record) const auto transaction = tdbb->getTransaction(); dsc desc; + MetaName schemaName; + if (EVL_field(nullptr, record, f_rcon_schema, &desc)) + MOV_get_metaname(tdbb, &desc, schemaName); + MetaName constraintName; if (EVL_field(nullptr, record, f_rcon_cname, &desc)) MOV_get_metaname(tdbb, &desc, constraintName); @@ -471,7 +552,8 @@ void beforeDeleteRelationConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) REF IN RDB$REF_CONSTRAINTS - WITH REF.RDB$CONST_NAME_UQ = constraintName.c_str() + WITH REF.RDB$CONST_SCHEMA_NAME_UQ = schemaName.c_str() AND + REF.RDB$CONST_NAME_UQ = constraintName.c_str() { ERR_post(Arg::Gds(isc_primary_key_ref)); } @@ -484,7 +566,8 @@ void beforeDeleteRelationConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) REF IN RDB$REF_CONSTRAINTS - WITH REF.RDB$CONSTRAINT_NAME = constraintName.c_str() + WITH REF.RDB$SCHEMA_NAME = schemaName.c_str() AND + REF.RDB$CONSTRAINT_NAME = constraintName.c_str() { ERASE REF; } @@ -505,12 +588,17 @@ void beforeDeleteRelationConstraint(thread_db* tdbb, Record* record) CROSS FLD IN RDB$FIELDS CROSS IND IN RDB$INDICES CROSS IDS IN RDB$INDEX_SEGMENTS - WITH CHK.RDB$CONSTRAINT_NAME = constraintName.c_str() AND + WITH CHK.RDB$SCHEMA_NAME = schemaName.c_str() AND + CHK.RDB$CONSTRAINT_NAME = constraintName.c_str() AND + RFL.RDB$SCHEMA_NAME = CHK.RDB$SCHEMA_NAME AND RFL.RDB$RELATION_NAME = relationName.c_str() AND RFL.RDB$FIELD_NAME = CHK.RDB$TRIGGER_NAME AND - IND.RDB$RELATION_NAME = relationName.c_str() AND + IND.RDB$SCHEMA_NAME = RFL.RDB$SCHEMA_NAME AND + IND.RDB$RELATION_NAME = RFL.RDB$RELATION_NAME AND + IDS.RDB$SCHEMA_NAME = IND.RDB$SCHEMA_NAME AND IDS.RDB$INDEX_NAME = IND.RDB$INDEX_NAME AND IDS.RDB$FIELD_NAME = RFL.RDB$FIELD_NAME AND + FLD.RDB$SCHEMA_NAME = RFL.RDB$FIELD_SOURCE_SCHEMA_NAME AND FLD.RDB$FIELD_NAME = RFL.RDB$FIELD_SOURCE AND (FLD.RDB$NULL_FLAG MISSING OR FLD.RDB$NULL_FLAG = 0) { @@ -519,7 +607,8 @@ void beforeDeleteRelationConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) RCL IN RDB$RELATION_CONSTRAINTS - WITH RCL.RDB$INDEX_NAME = IND.RDB$INDEX_NAME AND + WITH RCL.RDB$SCHEMA_NAME = IND.RDB$SCHEMA_NAME AND + RCL.RDB$INDEX_NAME = IND.RDB$INDEX_NAME AND RCL.RDB$CONSTRAINT_TYPE = PRIMARY_KEY { ERR_post(Arg::Gds(isc_primary_key_notnull)); @@ -542,6 +631,10 @@ void afterDeleteRelationConstraint(thread_db* tdbb, Record* record) constraintType.rtrim(); } + MetaName schemaName; + if (EVL_field(nullptr, record, f_rcon_schema, &desc)) + MOV_get_metaname(tdbb, &desc, schemaName); + MetaName constraintName; if (EVL_field(nullptr, record, f_rcon_cname, &desc)) MOV_get_metaname(tdbb, &desc, constraintName); @@ -561,7 +654,8 @@ void afterDeleteRelationConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request1 TRANSACTION_HANDLE transaction) CHK IN RDB$CHECK_CONSTRAINTS - WITH CHK.RDB$CONSTRAINT_NAME = constraintName.c_str() + WITH CHK.RDB$SCHEMA_NAME = schemaName.c_str() AND + CHK.RDB$CONSTRAINT_NAME = constraintName.c_str() { ERASE CHK; @@ -570,7 +664,8 @@ void afterDeleteRelationConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) TRG IN RDB$TRIGGERS - WITH TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME + WITH TRG.RDB$SCHEMA_NAME = CHK.RDB$SCHEMA_NAME AND + TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME { ERASE TRG; } @@ -586,7 +681,8 @@ void afterDeleteRelationConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request3 TRANSACTION_HANDLE transaction) IND IN RDB$INDICES - WITH IND.RDB$INDEX_NAME = indexName.c_str() + WITH IND.RDB$SCHEMA_NAME = schemaName.c_str() AND + IND.RDB$INDEX_NAME = indexName.c_str() { ERASE IND; @@ -595,7 +691,8 @@ void afterDeleteRelationConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request4 TRANSACTION_HANDLE transaction) IDS IN RDB$INDEX_SEGMENTS - WITH IDS.RDB$INDEX_NAME = IND.RDB$INDEX_NAME + WITH IDS.RDB$SCHEMA_NAME = IND.RDB$SCHEMA_NAME AND + IDS.RDB$INDEX_NAME = IND.RDB$INDEX_NAME { ERASE IDS; } @@ -612,7 +709,9 @@ void afterDeleteRelationConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request5 TRANSACTION_HANDLE transaction) CHK IN RDB$CHECK_CONSTRAINTS CROSS RFL IN RDB$RELATION_FIELDS - WITH CHK.RDB$CONSTRAINT_NAME = constraintName.c_str() AND + WITH CHK.RDB$SCHEMA_NAME = schemaName.c_str() AND + CHK.RDB$CONSTRAINT_NAME = constraintName.c_str() AND + RFL.RDB$SCHEMA_NAME = CHK.RDB$SCHEMA_NAME AND RFL.RDB$RELATION_NAME = relationName.c_str() AND RFL.RDB$FIELD_NAME = CHK.RDB$TRIGGER_NAME { @@ -634,7 +733,8 @@ void afterDeleteRelationConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request6 TRANSACTION_HANDLE transaction) CHK IN RDB$CHECK_CONSTRAINTS - WITH CHK.RDB$CONSTRAINT_NAME = constraintName.c_str() + WITH CHK.RDB$SCHEMA_NAME = schemaName.c_str() AND + CHK.RDB$CONSTRAINT_NAME = constraintName.c_str() { ERASE CHK; @@ -643,7 +743,8 @@ void afterDeleteRelationConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request7 TRANSACTION_HANDLE transaction) TRG IN RDB$TRIGGERS - WITH TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME AND + WITH TRG.RDB$SCHEMA_NAME = CHK.RDB$SCHEMA_NAME AND + TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME AND TRG.RDB$RELATION_NAME = relationName.c_str() { ERASE TRG; @@ -659,6 +760,12 @@ void beforeInsertRelationConstraint(thread_db* tdbb, Record* record) const auto transaction = tdbb->getTransaction(); dsc desc; + MetaName schemaName; + if (EVL_field(nullptr, record, f_rcon_schema, &desc)) + MOV_get_metaname(tdbb, &desc, schemaName); + else + schemaName = PUBLIC_SCHEMA; + MetaName relationName; if (EVL_field(nullptr, record, f_rcon_rname, &desc)) MOV_get_metaname(tdbb, &desc, relationName); @@ -675,7 +782,8 @@ void beforeInsertRelationConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request1 TRANSACTION_HANDLE transaction) REL IN RDB$RELATIONS - WITH REL.RDB$RELATION_NAME EQ relationName.c_str() AND + WITH REL.RDB$SCHEMA_NAME EQ schemaName.c_str() AND + REL.RDB$RELATION_NAME EQ relationName.c_str() AND REL.RDB$VIEW_SOURCE NOT MISSING { ERR_post(Arg::Gds(isc_constaint_on_view)); @@ -689,7 +797,8 @@ void beforeInsertRelationConstraint(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) RLC IN RDB$RELATION_CONSTRAINTS - WITH RLC.RDB$RELATION_NAME EQ relationName.c_str() AND + WITH RLC.RDB$SCHEMA_NAME EQ schemaName.c_str() AND + RLC.RDB$RELATION_NAME EQ relationName.c_str() AND RLC.RDB$CONSTRAINT_TYPE = PRIMARY_KEY { ERR_post(Arg::Gds(isc_primary_key_exists)); @@ -703,6 +812,11 @@ void beforeDeleteRelationField(thread_db* tdbb, Record* record) const auto transaction = tdbb->getTransaction(); dsc desc; + MetaName schemaName; + if (!EVL_field(nullptr, record, f_rfr_schema, &desc)) + return; + MOV_get_metaname(tdbb, &desc, schemaName); + MetaName relationName; if (!EVL_field(nullptr, record, f_rfr_rname, &desc)) return; @@ -720,17 +834,21 @@ void beforeDeleteRelationField(thread_db* tdbb, Record* record) IND IN RDB$INDICES CROSS RCL IN RDB$RELATION_CONSTRAINTS CROSS IDS IN RDB$INDEX_SEGMENTS - WITH IND.RDB$RELATION_NAME = relationName.c_str() AND + WITH IND.RDB$SCHEMA_NAME = schemaName.c_str() AND + IND.RDB$RELATION_NAME = relationName.c_str() AND + IDS.RDB$SCHEMA_NAME = IND.RDB$SCHEMA_NAME AND IDS.RDB$INDEX_NAME = IND.RDB$INDEX_NAME AND - RCL.RDB$INDEX_NAME = IND.RDB$INDEX_NAME AND - IDS.RDB$FIELD_NAME = fieldName.c_str() + IDS.RDB$FIELD_NAME = fieldName.c_str() AND + RCL.RDB$SCHEMA_NAME = IND.RDB$SCHEMA_NAME AND + RCL.RDB$INDEX_NAME = IND.RDB$INDEX_NAME { static const CachedRequestId request2CacheId; AutoCacheRequest request2(tdbb, request2CacheId); FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) IDS2 IN RDB$INDEX_SEGMENTS - WITH IDS2.RDB$INDEX_NAME = IND.RDB$INDEX_NAME AND + WITH IDS2.RDB$SCHEMA_NAME = IND.RDB$SCHEMA_NAME AND + IDS2.RDB$INDEX_NAME = IND.RDB$INDEX_NAME AND IDS2.RDB$FIELD_NAME != fieldName.c_str() { ERR_post(Arg::Gds(isc_cnstrnt_fld_del)); @@ -748,12 +866,15 @@ void beforeDeleteRelationField(thread_db* tdbb, Record* record) RCL IN RDB$RELATION_CONSTRAINTS CROSS CHK IN RDB$CHECK_CONSTRAINTS CROSS DEP IN RDB$DEPENDENCIES - WITH RCL.RDB$RELATION_NAME = relationName.c_str() AND + WITH RCL.RDB$SCHEMA_NAME = schemaName.c_str() AND + RCL.RDB$RELATION_NAME = relationName.c_str() AND RCL.RDB$CONSTRAINT_TYPE = CHECK_CNSTRT AND - DEP.RDB$DEPENDED_ON_NAME = relationName.c_str() AND + DEP.RDB$DEPENDED_ON_SCHEMA_NAME = RCL.RDB$SCHEMA_NAME AND + DEP.RDB$DEPENDED_ON_NAME = RCL.RDB$RELATION_NAME AND DEP.RDB$FIELD_NAME = fieldName.c_str() AND DEP.RDB$DEPENDENT_TYPE = obj_trigger AND DEP.RDB$DEPENDED_ON_TYPE = obj_relation AND + CHK.RDB$SCHEMA_NAME = DEP.RDB$DEPENDENT_SCHEMA_NAME AND CHK.RDB$TRIGGER_NAME = DEP.RDB$DEPENDENT_NAME { static const CachedRequestId request4CacheId; @@ -761,9 +882,11 @@ void beforeDeleteRelationField(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request4 TRANSACTION_HANDLE transaction) DEP4 IN RDB$DEPENDENCIES - WITH DEP4.RDB$DEPENDENT_NAME = CHK.RDB$TRIGGER_NAME AND + WITH DEP4.RDB$DEPENDENT_SCHEMA_NAME = CHK.RDB$SCHEMA_NAME AND + DEP4.RDB$DEPENDENT_NAME = CHK.RDB$TRIGGER_NAME AND DEP4.RDB$DEPENDENT_TYPE = obj_trigger AND DEP4.RDB$DEPENDED_ON_TYPE = obj_relation AND + DEP4.RDB$DEPENDED_ON_SCHEMA_NAME = schemaName.c_str() AND DEP4.RDB$DEPENDED_ON_NAME = relationName.c_str() AND DEP4.RDB$FIELD_NAME != fieldName.c_str() { @@ -781,6 +904,11 @@ void afterDeleteRelationField(thread_db* tdbb, Record* record) const auto transaction = tdbb->getTransaction(); dsc desc; + MetaName schemaName; + if (!EVL_field(nullptr, record, f_rfr_schema, &desc)) + return; + MOV_get_metaname(tdbb, &desc, schemaName); + MetaName relationName; if (!EVL_field(nullptr, record, f_rfr_rname, &desc)) return; @@ -797,7 +925,9 @@ void afterDeleteRelationField(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) CHK IN RDB$CHECK_CONSTRAINTS CROSS RCL IN RDB$RELATION_CONSTRAINTS - WITH CHK.RDB$TRIGGER_NAME EQ fieldName.c_str() AND + WITH CHK.RDB$SCHEMA_NAME = schemaName.c_str() AND + CHK.RDB$TRIGGER_NAME EQ fieldName.c_str() AND + RCL.RDB$SCHEMA_NAME = CHK.RDB$SCHEMA_NAME AND RCL.RDB$CONSTRAINT_NAME EQ CHK.RDB$CONSTRAINT_NAME AND RCL.RDB$RELATION_NAME = relationName.c_str() AND RCL.RDB$CONSTRAINT_TYPE = NOT_NULL_CNSTRT @@ -811,13 +941,17 @@ void afterDeleteRelationField(thread_db* tdbb, Record* record) void beforeUpdateRelationField(thread_db* tdbb, Record* orgRecord, Record* newRecord) { const auto transaction = tdbb->getTransaction(); - dsc desc; + + MetaName oldSchemaName; MetaName oldRelationName; MetaName oldFieldName, newFieldName; MetaName oldFieldSource, newFieldSource; std::optional oldCollationId, newCollationId; + if (EVL_field(nullptr, orgRecord, f_rfr_schema, &desc)) + MOV_get_metaname(tdbb, &desc, oldSchemaName); + if (EVL_field(nullptr, orgRecord, f_rfr_rname, &desc)) MOV_get_metaname(tdbb, &desc, oldRelationName); @@ -849,9 +983,12 @@ void beforeUpdateRelationField(thread_db* tdbb, Record* orgRecord, Record* newRe IND IN RDB$INDICES CROSS IDS IN RDB$INDEX_SEGMENTS CROSS RLC IN RDB$RELATION_CONSTRAINTS - WITH IND.RDB$RELATION_NAME = oldRelationName.c_str() AND + WITH IND.RDB$SCHEMA_NAME = oldSchemaName.c_str() AND + IND.RDB$RELATION_NAME = oldRelationName.c_str() AND + IDS.RDB$SCHEMA_NAME = IND.RDB$SCHEMA_NAME AND IDS.RDB$INDEX_NAME = IND.RDB$INDEX_NAME AND IDS.RDB$FIELD_NAME = oldFieldName.c_str() AND + RLC.RDB$SCHEMA_NAME = IND.RDB$SCHEMA_NAME AND RLC.RDB$INDEX_NAME = IND.RDB$INDEX_NAME { if (oldFieldName != newFieldName) @@ -872,6 +1009,10 @@ void beforeDeleteTrigger(thread_db* tdbb, Record* record) if (EVL_field(nullptr, record, f_trg_sys_flag, &desc) && MOV_get_long(tdbb, &desc, 0) == 1) ERR_post(Arg::Gds(isc_systrig_update)); + MetaName oldSchemaName; + if (EVL_field(nullptr, record, f_trg_schema, &desc)) + MOV_get_metaname(tdbb, &desc, oldSchemaName); + MetaName oldTriggerName; if (EVL_field(nullptr, record, f_trg_name, &desc)) MOV_get_metaname(tdbb, &desc, oldTriggerName); @@ -882,7 +1023,9 @@ void beforeDeleteTrigger(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) CHK IN RDB$CHECK_CONSTRAINTS CROSS RCL IN RDB$RELATION_CONSTRAINTS - WITH CHK.RDB$TRIGGER_NAME EQ oldTriggerName.c_str() AND + WITH CHK.RDB$SCHEMA_NAME = oldSchemaName.c_str() AND + CHK.RDB$TRIGGER_NAME EQ oldTriggerName.c_str() AND + RCL.RDB$SCHEMA_NAME = CHK.RDB$SCHEMA_NAME AND RCL.RDB$CONSTRAINT_NAME EQ CHK.RDB$CONSTRAINT_NAME AND RCL.RDB$CONSTRAINT_TYPE = CHECK_CNSTRT { @@ -899,6 +1042,12 @@ void beforeUpdateTrigger(thread_db* tdbb, Record* orgRecord, Record* newRecord) if (EVL_field(nullptr, orgRecord, f_trg_sys_flag, &desc) && MOV_get_long(tdbb, &desc, 0) == 1) ERR_post(Arg::Gds(isc_systrig_update)); + MetaName oldSchemaName, newSchemaName; + if (EVL_field(nullptr, orgRecord, f_trg_schema, &desc)) + MOV_get_metaname(tdbb, &desc, oldSchemaName); + if (EVL_field(nullptr, newRecord, f_trg_schema, &desc)) + MOV_get_metaname(tdbb, &desc, newSchemaName); + MetaName oldTriggerName, newTriggerName; if (EVL_field(nullptr, orgRecord, f_trg_name, &desc)) MOV_get_metaname(tdbb, &desc, oldTriggerName); @@ -947,11 +1096,13 @@ void beforeUpdateTrigger(thread_db* tdbb, Record* orgRecord, Record* newRecord) FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) CHK IN RDB$CHECK_CONSTRAINTS CROSS RCL IN RDB$RELATION_CONSTRAINTS - WITH CHK.RDB$TRIGGER_NAME = oldTriggerName.c_str() AND + WITH CHK.RDB$SCHEMA_NAME = oldSchemaName.c_str() AND + CHK.RDB$TRIGGER_NAME = oldTriggerName.c_str() AND RCL.RDB$CONSTRAINT_NAME = CHK.RDB$CONSTRAINT_NAME AND RCL.RDB$CONSTRAINT_TYPE = CHECK_CNSTRT { - if (!(oldTriggerName == newTriggerName && + if (!(oldSchemaName == newSchemaName && + oldTriggerName == newTriggerName && oldRelationName == newRelationName && oldTriggerSequence == newTriggerSequence && oldTriggerBlr == newTriggerBlr && @@ -970,6 +1121,11 @@ void beforeDeleteUserPrivilege(thread_db* tdbb, Record* record) const auto transaction = tdbb->getTransaction(); dsc desc; + MetaName schemaName; + if (!EVL_field(nullptr, record, f_prv_rel_schema, &desc)) + return; + MOV_get_metaname(tdbb, &desc, schemaName); + MetaName relationName; if (!EVL_field(nullptr, record, f_prv_rname, &desc)) return; @@ -986,7 +1142,8 @@ void beforeDeleteUserPrivilege(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RFL IN RDB$RELATION_FIELDS CROSS SEC IN RDB$SECURITY_CLASSES - WITH RFL.RDB$RELATION_NAME = relationName.c_str() AND + WITH RFL.RDB$SCHEMA_NAME = schemaName.c_str() AND + RFL.RDB$RELATION_NAME = relationName.c_str() AND RFL.RDB$FIELD_NAME = fieldName.c_str() AND RFL.RDB$SECURITY_CLASS STARTING SQL_FLD_SECCLASS_PREFIX AND SEC.RDB$SECURITY_CLASS = RFL.RDB$SECURITY_CLASS @@ -1036,6 +1193,12 @@ void beforeInsertUserPrivilege(thread_db* tdbb, Record* record) if (EVL_field(nullptr, record, f_prv_priv, &desc)) MOV_get_string(tdbb, &desc, privilege); + MetaName schemaName; + if (EVL_field(nullptr, record, f_prv_rel_schema, &desc)) + MOV_get_metaname(tdbb, &desc, schemaName); + else + schemaName = PUBLIC_SCHEMA; + MetaName relationName; if (EVL_field(nullptr, record, f_prv_rname, &desc)) MOV_get_metaname(tdbb, &desc, relationName); @@ -1053,7 +1216,8 @@ void beforeInsertUserPrivilege(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request1 TRANSACTION_HANDLE transaction) REL IN RDB$RELATIONS - WITH REL.RDB$RELATION_NAME EQ relationName.c_str() + WITH REL.RDB$SCHEMA_NAME EQ schemaName.c_str() AND + REL.RDB$RELATION_NAME EQ relationName.c_str() { const MetaName relationOwner(REL.RDB$OWNER_NAME); @@ -1071,11 +1235,14 @@ void beforeInsertUserPrivilege(thread_db* tdbb, Record* record) RFL2 IN RDB$RELATION_FIELDS CROSS VRL2 IN RDB$VIEW_RELATIONS CROSS REL2 IN RDB$RELATIONS - WITH RFL2.RDB$RELATION_NAME = relationName.c_str() AND + WITH RFL2.RDB$SCHEMA_NAME = schemaName.c_str() AND + RFL2.RDB$RELATION_NAME = relationName.c_str() AND RFL2.RDB$FIELD_NAME = fieldName.c_str() AND RFL2.RDB$BASE_FIELD NOT MISSING AND + VRL2.RDB$SCHEMA_NAME = RFL2.RDB$SCHEMA_NAME AND VRL2.RDB$VIEW_NAME = RFL2.RDB$RELATION_NAME AND VRL2.RDB$VIEW_CONTEXT = RFL2.RDB$VIEW_CONTEXT AND + REL2.RDB$SCHEMA_NAME = VRL2.RDB$RELATION_SCHEMA_NAME AND REL2.RDB$RELATION_NAME = VRL2.RDB$RELATION_NAME { const MetaName relation2Owner(REL2.RDB$OWNER_NAME); @@ -1088,7 +1255,8 @@ void beforeInsertUserPrivilege(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request3 TRANSACTION_HANDLE transaction) PRIV3 IN RDB$USER_PRIVILEGES - WITH PRIV3.RDB$RELATION_NAME = REL2.RDB$RELATION_NAME AND + WITH PRIV3.RDB$RELATION_SCHEMA_NAME = REL2.RDB$SCHEMA_NAME AND + PRIV3.RDB$RELATION_NAME = REL2.RDB$RELATION_NAME AND PRIV3.RDB$OBJECT_TYPE = obj_relation AND PRIV3.RDB$PRIVILEGE = privilege.c_str() AND PRIV3.RDB$USER = relationOwner.c_str() AND @@ -1115,7 +1283,9 @@ void beforeInsertUserPrivilege(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request4 TRANSACTION_HANDLE transaction) VRL4 IN RDB$VIEW_RELATIONS CROSS REL4 IN RDB$RELATIONS - WITH VRL4.RDB$VIEW_NAME = relationName.c_str() AND + WITH VRL4.RDB$SCHEMA_NAME = schemaName.c_str() AND + VRL4.RDB$VIEW_NAME = relationName.c_str() AND + REL4.RDB$SCHEMA_NAME = VRL4.RDB$RELATION_SCHEMA_NAME AND REL4.RDB$RELATION_NAME = VRL4.RDB$RELATION_NAME { const MetaName relation4Owner(REL4.RDB$OWNER_NAME); @@ -1128,7 +1298,8 @@ void beforeInsertUserPrivilege(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request5 TRANSACTION_HANDLE transaction) PRIV5 IN RDB$USER_PRIVILEGES - WITH PRIV5.RDB$RELATION_NAME = REL4.RDB$RELATION_NAME AND + WITH PRIV5.RDB$RELATION_SCHEMA_NAME = REL4.RDB$SCHEMA_NAME AND + PRIV5.RDB$RELATION_NAME = REL4.RDB$RELATION_NAME AND PRIV5.RDB$OBJECT_TYPE = obj_relation AND PRIV5.RDB$PRIVILEGE = privilege.c_str() AND PRIV5.RDB$USER = relationOwner.c_str() AND @@ -1154,7 +1325,9 @@ void beforeInsertUserPrivilege(thread_db* tdbb, Record* record) MODIFY REL { sprintf(REL.RDB$SECURITY_CLASS, "%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, - DPM_gen_id(tdbb, MET_lookup_generator(tdbb, SQL_SECCLASS_GENERATOR), false, 1)); + DPM_gen_id(tdbb, + MET_lookup_generator(tdbb, + QualifiedName(SQL_SECCLASS_GENERATOR, SYSTEM_SCHEMA)), false, 1)); REL.RDB$SECURITY_CLASS.NULL = FALSE; } END_MODIFY @@ -1171,7 +1344,8 @@ void beforeInsertUserPrivilege(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request6 TRANSACTION_HANDLE transaction) RFL6 IN RDB$RELATION_FIELDS - WITH RFL6.RDB$RELATION_NAME = relationName.c_str() AND + WITH RFL6.RDB$SCHEMA_NAME = schemaName.c_str() AND + RFL6.RDB$RELATION_NAME = relationName.c_str() AND RFL6.RDB$FIELD_NAME = fieldName.c_str() { if (RFL6.RDB$SECURITY_CLASS.NULL) @@ -1179,7 +1353,9 @@ void beforeInsertUserPrivilege(thread_db* tdbb, Record* record) MODIFY RFL6 { sprintf(RFL6.RDB$SECURITY_CLASS, "%s%" SQUADFORMAT, SQL_FLD_SECCLASS_PREFIX, - DPM_gen_id(tdbb, MET_lookup_generator(tdbb, SQL_SECCLASS_GENERATOR), false, 1)); + DPM_gen_id(tdbb, + MET_lookup_generator(tdbb, + QualifiedName(SQL_SECCLASS_GENERATOR, SYSTEM_SCHEMA)), false, 1)); RFL6.RDB$SECURITY_CLASS.NULL = TRUE; } END_MODIFY @@ -1200,7 +1376,8 @@ void beforeInsertUserPrivilege(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request1 TRANSACTION_HANDLE transaction) PRC IN RDB$PROCEDURES - WITH PRC.RDB$PROCEDURE_NAME EQ relationName.c_str() AND + WITH PRC.RDB$SCHEMA_NAME = schemaName.c_str() AND + PRC.RDB$PROCEDURE_NAME EQ relationName.c_str() AND PRC.RDB$PACKAGE_NAME MISSING { if (PRC.RDB$SECURITY_CLASS.NULL) @@ -1208,7 +1385,9 @@ void beforeInsertUserPrivilege(thread_db* tdbb, Record* record) MODIFY PRC { sprintf(PRC.RDB$SECURITY_CLASS, "%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, - DPM_gen_id(tdbb, MET_lookup_generator(tdbb, SQL_SECCLASS_GENERATOR), false, 1)); + DPM_gen_id(tdbb, + MET_lookup_generator(tdbb, + QualifiedName(SQL_SECCLASS_GENERATOR, SYSTEM_SCHEMA)), false, 1)); PRC.RDB$SECURITY_CLASS.NULL = FALSE; } END_MODIFY @@ -1228,7 +1407,8 @@ void beforeInsertUserPrivilege(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request1 TRANSACTION_HANDLE transaction) FUN IN RDB$FUNCTIONS - WITH FUN.RDB$FUNCTION_NAME EQ relationName.c_str() AND + WITH FUN.RDB$SCHEMA_NAME = schemaName.c_str() AND + FUN.RDB$FUNCTION_NAME EQ relationName.c_str() AND FUN.RDB$PACKAGE_NAME MISSING { if (FUN.RDB$SECURITY_CLASS.NULL) @@ -1236,7 +1416,9 @@ void beforeInsertUserPrivilege(thread_db* tdbb, Record* record) MODIFY FUN { sprintf(FUN.RDB$SECURITY_CLASS, "%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, - DPM_gen_id(tdbb, MET_lookup_generator(tdbb, SQL_SECCLASS_GENERATOR), false, 1)); + DPM_gen_id(tdbb, + MET_lookup_generator(tdbb, + QualifiedName(SQL_SECCLASS_GENERATOR, SYSTEM_SCHEMA)), false, 1)); FUN.RDB$SECURITY_CLASS.NULL = FALSE; } END_MODIFY @@ -1256,14 +1438,17 @@ void beforeInsertUserPrivilege(thread_db* tdbb, Record* record) FOR (REQUEST_HANDLE request1 TRANSACTION_HANDLE transaction) PKG IN RDB$PACKAGES - WITH PKG.RDB$PACKAGE_NAME EQ relationName.c_str() + WITH PKG.RDB$SCHEMA_NAME = schemaName.c_str() AND + PKG.RDB$PACKAGE_NAME EQ relationName.c_str() { if (PKG.RDB$SECURITY_CLASS.NULL) { MODIFY PKG { sprintf(PKG.RDB$SECURITY_CLASS, "%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, - DPM_gen_id(tdbb, MET_lookup_generator(tdbb, SQL_SECCLASS_GENERATOR), false, 1)); + DPM_gen_id(tdbb, + MET_lookup_generator(tdbb, + QualifiedName(SQL_SECCLASS_GENERATOR, SYSTEM_SCHEMA)), false, 1)); PKG.RDB$SECURITY_CLASS.NULL = FALSE; } END_MODIFY @@ -1275,6 +1460,35 @@ void beforeInsertUserPrivilege(thread_db* tdbb, Record* record) break; } + + case obj_schema: + { + static const CachedRequestId request1CacheId; + AutoCacheRequest request1(tdbb, request1CacheId); + + FOR (REQUEST_HANDLE request1 TRANSACTION_HANDLE transaction) + SCH IN RDB$SCHEMAS + WITH SCH.RDB$SCHEMA_NAME = relationName.c_str() + { + if (SCH.RDB$SECURITY_CLASS.NULL) + { + MODIFY SCH + { + sprintf(SCH.RDB$SECURITY_CLASS, "%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX, + DPM_gen_id(tdbb, + MET_lookup_generator(tdbb, + QualifiedName(SQL_SECCLASS_GENERATOR, SYSTEM_SCHEMA)), false, 1)); + SCH.RDB$SECURITY_CLASS.NULL = FALSE; + } + END_MODIFY + } + else if (strncmp(SCH.RDB$SECURITY_CLASS, SQL_SECCLASS_PREFIX, SQL_SECCLASS_PREFIX_LEN) != 0) + ERR_post(Arg::Gds(isc_nonsql_security_rel)); + } + END_FOR + + break; + } } } diff --git a/src/jrd/acl.h b/src/jrd/acl.h index abf7540984..76a56355d9 100644 --- a/src/jrd/acl.h +++ b/src/jrd/acl.h @@ -28,7 +28,7 @@ // of int, based on usage, but they aren't coherent either with scl.epp's // P_NAMES.p_names_acl that's USHORT. -const int ACL_version = 1; +const int ACL_version = 2; const int ACL_end = 0; const int ACL_id_list = 1; diff --git a/src/jrd/blb.cpp b/src/jrd/blb.cpp index 923161dc8b..7c6cd75ede 100644 --- a/src/jrd/blb.cpp +++ b/src/jrd/blb.cpp @@ -1754,8 +1754,12 @@ void blb::put_slice(thread_db* tdbb, ERR_punt(); jrd_rel* relation; - if (info.sdl_info_relation.length()) { - relation = MET_lookup_relation(tdbb, info.sdl_info_relation); + if (info.sdl_info_relation.object.hasData()) + { + QualifiedName infoRelationName(info.sdl_info_relation); + tdbb->getAttachment()->qualifyExistingName(tdbb, infoRelationName, obj_relation); + + relation = MET_lookup_relation(tdbb, infoRelationName); } else { relation = MET_relation(tdbb, info.sdl_info_rid); diff --git a/src/jrd/blp.h b/src/jrd/blp.h index ffab974de2..bb1dd8e4e3 100644 --- a/src/jrd/blp.h +++ b/src/jrd/blp.h @@ -173,7 +173,7 @@ static const struct {"retrieve", two}, {"relation2", relation2}, {"rid2", rid2}, - {NULL, NULL}, + {"relation3", relation3}, {NULL, NULL}, {"set_generator", gen_id}, // 150 {"ansi_any", one}, @@ -261,5 +261,9 @@ static const struct {"select_procedure", invsel_procedure}, {"default_arg", zero}, {"cast_format", cast_format}, + {"gen_id3", gen_id3}, + {"default2", default2}, + {"current_schema", zero}, + {NULL, NULL}, // flags - part of header {0, 0} }; diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index 71d5e6224c..be3e0c600d 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -281,18 +281,19 @@ void IndexErrorContext::raise(thread_db* tdbb, idx_e result, Record* record) if (result == idx_e_conversion || result == idx_e_interrupt) ERR_punt(); - const MetaName& relationName = isLocationDefined ? m_location.relation->rel_name : m_relation->rel_name; + const auto& relationName = isLocationDefined ? m_location.relation->rel_name : m_relation->rel_name; const USHORT indexId = isLocationDefined ? m_location.indexId : m_index->idx_id; - MetaName indexName(m_indexName), constraintName; + QualifiedName indexName(m_indexName); + MetaName constraintName; - if (indexName.isEmpty()) + if (indexName.object.isEmpty()) MET_lookup_index(tdbb, indexName, relationName, indexId + 1); - if (indexName.hasData()) + if (indexName.object.hasData()) MET_lookup_cnstrt_for_index(tdbb, constraintName, indexName); else - indexName = "***unknown***"; + indexName.object = "***unknown***"; const bool haveConstraint = constraintName.hasData(); @@ -303,18 +304,18 @@ void IndexErrorContext::raise(thread_db* tdbb, idx_e result, Record* record) { case idx_e_keytoobig: ERR_post_nothrow(Arg::Gds(isc_imp_exc) << - Arg::Gds(isc_keytoobig) << Arg::Str(indexName)); + Arg::Gds(isc_keytoobig) << indexName.toQuotedString()); break; case idx_e_foreign_target_doesnt_exist: ERR_post_nothrow(Arg::Gds(isc_foreign_key) << - Arg::Str(constraintName) << Arg::Str(relationName) << + constraintName.toQuotedString() << relationName.toQuotedString() << Arg::Gds(isc_foreign_key_target_doesnt_exist)); break; case idx_e_foreign_references_present: ERR_post_nothrow(Arg::Gds(isc_foreign_key) << - Arg::Str(constraintName) << Arg::Str(relationName) << + constraintName.toQuotedString() << relationName.toQuotedString() << Arg::Gds(isc_foreign_key_references_present)); break; @@ -322,10 +323,10 @@ void IndexErrorContext::raise(thread_db* tdbb, idx_e result, Record* record) if (haveConstraint) { ERR_post_nothrow(Arg::Gds(isc_unique_key_violation) << - Arg::Str(constraintName) << Arg::Str(relationName)); + constraintName.toQuotedString() << relationName.toQuotedString()); } else - ERR_post_nothrow(Arg::Gds(isc_no_dup) << Arg::Str(indexName)); + ERR_post_nothrow(Arg::Gds(isc_no_dup) << indexName.toQuotedString()); break; default: @@ -677,15 +678,15 @@ idx_e IndexKey::compose(Record* record) error.value()[0] == isc_arg_gds && error.value()[1] == isc_expression_eval_index)) { - MetaName indexName; + QualifiedName indexName; MET_lookup_index(m_tdbb, indexName, m_relation->rel_name, m_index->idx_id + 1); - if (indexName.isEmpty()) - indexName = "***unknown***"; + if (indexName.object.isEmpty()) + indexName.object = "***unknown***"; error.prepend(Arg::Gds(isc_expression_eval_index) << - Arg::Str(indexName) << - Arg::Str(m_relation->rel_name)); + indexName.toQuotedString() << + m_relation->rel_name.toQuotedString()); } error.copyTo(m_tdbb->tdbb_status_vector); @@ -1025,16 +1026,16 @@ bool BTR_description(thread_db* tdbb, jrd_rel* relation, index_root_page* root, if (error) { - MetaName indexName; + QualifiedName indexName; MET_lookup_index(tdbb, indexName, relation->rel_name, idx->idx_id + 1); Arg::StatusVector status; - if (indexName.hasData()) - status.assign(Arg::Gds(error) << indexName); + if (indexName.object.hasData()) + status.assign(Arg::Gds(error) << indexName.toQuotedString()); else // there is no index in table @1 with id @2 - status.assign(Arg::Gds(isc_indexnotdefined) << relation->rel_name << Arg::Num(idx->idx_id)); + status.assign(Arg::Gds(isc_indexnotdefined) << relation->rel_name.toQuotedString() << Arg::Num(idx->idx_id)); ERR_post_nothrow(status); CCH_unwind(tdbb, true); diff --git a/src/jrd/btr.h b/src/jrd/btr.h index 7f1bc99303..b1f3142d9b 100644 --- a/src/jrd/btr.h +++ b/src/jrd/btr.h @@ -184,7 +184,7 @@ const int ISR_null = 2; // Record consists of NULL values only // Index retrieval block -- hold stuff for index retrieval -class IndexRetrieval +class IndexRetrieval final { public: IndexRetrieval(jrd_rel* relation, const index_desc* idx, USHORT count, temporary_key* key) @@ -196,10 +196,10 @@ public: } IndexRetrieval(MemoryPool& pool, jrd_rel* relation, const index_desc* idx, - const MetaName& name) + const QualifiedName& name) : irb_relation(relation), irb_index(idx->idx_id), irb_generic(0), irb_lower_count(0), irb_upper_count(0), irb_key(NULL), - irb_name(FB_NEW_POOL(pool) MetaName(name)), + irb_name(FB_NEW_POOL(pool) QualifiedName(name)), irb_value(FB_NEW_POOL(pool) ValueExprNode*[idx->idx_count * 2]), irb_list(nullptr), irb_scale(nullptr) { @@ -220,7 +220,7 @@ public: USHORT irb_lower_count; // Number of segments for retrieval USHORT irb_upper_count; // Number of segments for retrieval temporary_key* irb_key; // Key for equality retrieval - MetaName* irb_name; // Index name + QualifiedName* irb_name; // Index name ValueExprNode** irb_value; // Matching value (for equality search) LookupValueList* irb_list; // Matching values list (for IN ) SSHORT* irb_scale; // Scale for int64/int128 key @@ -295,7 +295,7 @@ struct IndexCreation { jrd_rel* relation; index_desc* index; - const TEXT* index_name; + QualifiedName index_name; jrd_tra* transaction; PartitionedSort* sort; sort_key_def* key_desc; @@ -316,7 +316,7 @@ class IndexErrorContext }; public: - IndexErrorContext(jrd_rel* relation, index_desc* index, const char* indexName = nullptr) + IndexErrorContext(jrd_rel* relation, index_desc* index, const QualifiedName& indexName = {}) : m_relation(relation), m_index(index), m_indexName(indexName) {} @@ -332,7 +332,7 @@ public: private: jrd_rel* const m_relation; index_desc* const m_index; - const char* const m_indexName; + const QualifiedName m_indexName; Location m_location; bool isLocationDefined = false; }; diff --git a/src/jrd/cmp.cpp b/src/jrd/cmp.cpp index 87930ad8b6..952a5f00cc 100644 --- a/src/jrd/cmp.cpp +++ b/src/jrd/cmp.cpp @@ -328,8 +328,8 @@ void CMP_post_access(thread_db* tdbb, SLONG ssRelationId, // SQL SECURITY relation in which context permissions should be check SecurityClass::flags_t mask, ObjectType obj_type, - const MetaName& name, - const MetaName& r_name) + const QualifiedName& name, + const MetaName& columnName) { /************************************** * @@ -353,7 +353,7 @@ void CMP_post_access(thread_db* tdbb, SET_TDBB(tdbb); - AccessItem access(security_name, ssRelationId, name, obj_type, mask, r_name); + AccessItem access(security_name, ssRelationId, name, obj_type, mask, columnName); FB_SIZE_T i; @@ -572,15 +572,15 @@ bool CMP_procedure_arguments( FieldInfo fieldInfo; if (parameter->prm_mechanism != prm_mech_type_of && - !fb_utils::implicit_domain(parameter->prm_field_source.c_str())) + !fb_utils::implicit_domain(parameter->prm_field_source.object.c_str())) { - const MetaNamePair namePair(parameter->prm_field_source, ""); + const QualifiedNameMetaNamePair entry(parameter->prm_field_source, {}); - if (!csb->csb_map_field_info.get(namePair, fieldInfo)) + if (!csb->csb_map_field_info.get(entry, fieldInfo)) { dsc dummyDesc; MET_get_domain(tdbb, csb->csb_pool, parameter->prm_field_source, &dummyDesc, &fieldInfo); - csb->csb_map_field_info.put(namePair, fieldInfo); + csb->csb_map_field_info.put(entry, fieldInfo); } } @@ -664,18 +664,21 @@ void CMP_post_procedure_access(thread_db* tdbb, CompilerScratch* csb, jrd_prc* p if (csb->csb_g_flags & (csb_internal | csb_ignore_perm)) return; + const SLONG ssRelationId = csb->csb_view ? csb->csb_view->rel_id : 0; + + CMP_post_access(tdbb, csb, procedure->getSecurityName().schema, ssRelationId, + SCL_usage, obj_schemas, QualifiedName(procedure->getName().schema)); + // this request must have EXECUTE permission on the stored procedure if (procedure->getName().package.isEmpty()) { - CMP_post_access(tdbb, csb, procedure->getSecurityName(), - (csb->csb_view ? csb->csb_view->rel_id : 0), - SCL_execute, obj_procedures, procedure->getName().identifier); + CMP_post_access(tdbb, csb, procedure->getSecurityName().object, ssRelationId, + SCL_execute, obj_procedures, procedure->getName()); } else { - CMP_post_access(tdbb, csb, procedure->getSecurityName(), - (csb->csb_view ? csb->csb_view->rel_id : 0), - SCL_execute, obj_packages, procedure->getName().package); + CMP_post_access(tdbb, csb, procedure->getSecurityName().object, ssRelationId, + SCL_execute, obj_packages, procedure->getName().getSchemaAndPackage()); } // Add the procedure to list of external objects accessed diff --git a/src/jrd/cmp_proto.h b/src/jrd/cmp_proto.h index f974f9972e..5b4d094531 100644 --- a/src/jrd/cmp_proto.h +++ b/src/jrd/cmp_proto.h @@ -59,8 +59,9 @@ bool CMP_procedure_arguments( Firebird::Arg::StatusVector& mismatchStatus); void CMP_post_access(Jrd::thread_db*, Jrd::CompilerScratch*, const Jrd::MetaName&, SLONG ssRelationId, - Jrd::SecurityClass::flags_t, ObjectType obj_type, const Jrd::MetaName&, - const Jrd::MetaName& = ""); + Jrd::SecurityClass::flags_t, ObjectType obj_type, + const Jrd::QualifiedName&, + const Jrd::MetaName& = {}); void CMP_post_procedure_access(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::jrd_prc*); void CMP_post_resource(Jrd::ResourceList*, void*, Jrd::Resource::rsc_s, USHORT); diff --git a/src/jrd/constants.h b/src/jrd/constants.h index ce322ee78d..612bf2571e 100644 --- a/src/jrd/constants.h +++ b/src/jrd/constants.h @@ -72,6 +72,12 @@ const FB_SIZE_T MAX_SQL_IDENTIFIER_LEN = METADATA_IDENTIFIER_CHAR_LEN * METADATA const FB_SIZE_T MAX_SQL_IDENTIFIER_SIZE = MAX_SQL_IDENTIFIER_LEN + 1; const FB_SIZE_T MAX_CONFIG_NAME_LEN = 63; +// Every character of the name may be a double-quote needed to be escaped (with another double-quote). +// The name would also need to be enclosed in double-quotes. +// There is two names, separated by a dot. +const FB_SIZE_T MAX_QUALIFIED_NAME_TO_STRING_LEN = + ((METADATA_IDENTIFIER_CHAR_LEN * 2 + 2) * 2 + 1) * METADATA_BYTES_PER_CHAR; + const ULONG MAX_SQL_LENGTH = 10 * 1024 * 1024; // 10 MB - just a safety check const char* const DB_KEY_NAME = "DB_KEY"; @@ -98,12 +104,12 @@ const char* const UNIQUE_CNSTRT = "UNIQUE"; const char* const CHECK_CNSTRT = "CHECK"; const char* const NOT_NULL_CNSTRT = "NOT NULL"; -const char* const REL_SCOPE_PERSISTENT = "persistent table \"%s\""; -const char* const REL_SCOPE_GTT_PRESERVE = "global temporary table \"%s\" of type ON COMMIT PRESERVE ROWS"; -const char* const REL_SCOPE_GTT_DELETE = "global temporary table \"%s\" of type ON COMMIT DELETE ROWS"; -const char* const REL_SCOPE_EXTERNAL = "external table \"%s\""; -const char* const REL_SCOPE_VIEW = "view \"%s\""; -const char* const REL_SCOPE_VIRTUAL = "virtual table \"%s\""; +const char* const REL_SCOPE_PERSISTENT = "persistent table %s"; +const char* const REL_SCOPE_GTT_PRESERVE = "global temporary table %s of type ON COMMIT PRESERVE ROWS"; +const char* const REL_SCOPE_GTT_DELETE = "global temporary table %s of type ON COMMIT DELETE ROWS"; +const char* const REL_SCOPE_EXTERNAL = "external table %s"; +const char* const REL_SCOPE_VIEW = "view %s"; +const char* const REL_SCOPE_VIRTUAL = "virtual table %s"; // literal strings in rdb$ref_constraints to be used to identify // the cascade actions for referential constraints. Used @@ -127,6 +133,8 @@ const int IMPLICIT_PK_PREFIX_LEN = 11; // The invisible "id zero" generator. const char* const MASTER_GENERATOR = ""; //Was "RDB$GENERATORS"; +constexpr const char* SYSTEM_SCHEMA = "SYSTEM"; +constexpr const char* PUBLIC_SCHEMA = "PUBLIC"; // Automatically created security classes for SQL objects. // Keep in sync with trig.h @@ -391,7 +399,10 @@ static const char* const DDL_TRIGGER_ACTION_NAMES[][2] = {"DROP", "PACKAGE BODY"}, {"CREATE", "MAPPING"}, {"ALTER", "MAPPING"}, - {"DROP", "MAPPING"} + {"DROP", "MAPPING"}, + {"CREATE", "SCHEMA"}, + {"ALTER", "SCHEMA"}, + {"DROP", "SCHEMA"} }; const int DDL_TRIGGER_BEFORE = 0; @@ -444,6 +455,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_SCHEMA = 48; +const int DDL_TRIGGER_ALTER_SCHEMA = 49; +const int DDL_TRIGGER_DROP_SCHEMA = 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 1edc4ff4ee..81e32b68a8 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -193,17 +193,19 @@ public: USHORT dfw_id; // object id, if appropriate USHORT dfw_count; // count of block posts string dfw_name; // name of object + MetaName dfw_schema; // schema name MetaName dfw_package; // package name SortedArray dfw_ids; // list of identifiers (or any numbers) needed by an action public: DeferredWork(MemoryPool& p, DeferredWork*** end, enum dfw_t t, USHORT id, SavNumber sn, const string& name, - const MetaName& package) + const MetaName& schema, const MetaName& package) : dfw_type(t), dfw_end(end), dfw_prev(dfw_end ? *dfw_end : NULL), dfw_next(dfw_prev ? *dfw_prev : NULL), dfw_lock(NULL), dfw_args(p), dfw_sav_number(sn), dfw_id(id), dfw_count(1), dfw_name(p, name), - dfw_package(p, package), dfw_ids(p) + dfw_schema(p, schema), dfw_package(p, package), + dfw_ids(p) { // make previous element point to us if (dfw_prev) @@ -274,12 +276,18 @@ public: return dfw_next; } + QualifiedName getQualifiedName() const + { + return QualifiedName(dfw_name, dfw_schema, dfw_package); + } + // hash interface bool isEqual(const DeferredWork& work) const { if (dfw_type == work.dfw_type && dfw_id == work.dfw_id && dfw_name == work.dfw_name && + dfw_schema == work.dfw_schema && dfw_package == work.dfw_package && dfw_sav_number == work.dfw_sav_number) { @@ -293,7 +301,7 @@ public: static FB_SIZE_T hash(const DeferredWork& work, FB_SIZE_T hashSize) { const int nameLimit = 32; - char key[sizeof work.dfw_type + sizeof work.dfw_id + nameLimit]; + char key[sizeof work.dfw_type + sizeof work.dfw_id + nameLimit + nameLimit]; memset(key, 0, sizeof key); char* place = key; @@ -304,6 +312,9 @@ public: place += sizeof work.dfw_id; work.dfw_name.copyTo(place, nameLimit); // It's good enough to have first 32 bytes + place += nameLimit; + + work.dfw_schema.copyTo(place, nameLimit); // It's good enough to have first 32 bytes return DefaultHash::hash(key, sizeof key, hashSize); } @@ -488,19 +499,19 @@ 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 string remove_icu_info_from_attributes(const string&, const string&); +static string remove_icu_info_from_attributes(const QualifiedName&, const string&); // ---------------------------------------------------------------- static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction); static void check_computed_dependencies(thread_db* tdbb, jrd_tra* transaction, - const MetaName& fieldName); -static void check_dependencies(thread_db*, const TEXT*, const TEXT*, const TEXT*, int, jrd_tra*); + const QualifiedName& fieldName); +static void check_dependencies(thread_db*, const QualifiedName&, const MetaName&, int, jrd_tra*); static void check_filename(const Firebird::string&, bool); static void cleanup_index_creation(thread_db*, DeferredWork*, jrd_tra*); static bool formatsAreEqual(const Format*, const Format*); -static bool find_depend_in_dfw(thread_db*, TEXT*, USHORT, USHORT, jrd_tra*); +static bool find_depend_in_dfw(thread_db*, const QualifiedName&, USHORT, USHORT, jrd_tra*); static void get_array_desc(thread_db*, const TEXT*, Ods::InternalArrayDesc*); static void get_trigger_dependencies(DeferredWork*, bool, jrd_tra*); static Format* make_format(thread_db*, jrd_rel*, USHORT *, TemporaryField*); @@ -508,12 +519,12 @@ static void put_summary_blob(thread_db* tdbb, blb*, enum rsr_t, bid*, jrd_tra*); static void put_summary_record(thread_db* tdbb, blb*, enum rsr_t, const UCHAR*, ULONG); static void setup_array(thread_db*, blb*, const TEXT*, USHORT, TemporaryField*); static blb* setup_triggers(thread_db*, jrd_rel*, bool, TrigVector**, blb*); -static void setup_trigger_details(thread_db*, jrd_rel*, blb*, TrigVector**, const TEXT*, bool); +static void setup_trigger_details(thread_db*, jrd_rel*, blb*, TrigVector**, const QualifiedName&, bool); static bool validate_text_type (thread_db*, const TemporaryField*); static void check_partners(thread_db*, const USHORT); static string get_string(const dsc* desc); -static void setupSpecificCollationAttributes(thread_db*, jrd_tra*, const USHORT, const char*, bool); +static void setupSpecificCollationAttributes(thread_db*, jrd_tra*, const USHORT, const QualifiedName&, bool); static ISC_STATUS getErrorCodeByObjectType(int obj_type) { @@ -572,37 +583,35 @@ static void raiseDatabaseInUseError(bool timeout) Arg::Gds(isc_obj_in_use) << Arg::Str("DATABASE")); } -static void raiseObjectInUseError(const string& obj_type, const string& obj_name) +static void raiseObjectInUseError(const string& obj_type, const QualifiedName& obj_name) { string name; - name.printf("%s \"%s\"", obj_type.c_str(), obj_name.c_str()); + name.printf("%s %s", obj_type.c_str(), obj_name.toQuotedString().c_str()); ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_obj_in_use) << Arg::Str(name)); + Arg::Gds(isc_obj_in_use) << name); } static void raiseRelationInUseError(const jrd_rel* relation) { const string obj_type = relation->isView() ? "VIEW" : "TABLE"; - const string obj_name = relation->rel_name.c_str(); - raiseObjectInUseError(obj_type, obj_name); + raiseObjectInUseError(obj_type, relation->rel_name); } static void raiseRoutineInUseError(const Routine* routine, const QualifiedName& name) { const string obj_type = (routine->getObjectType() == obj_udf) ? "FUNCTION" : "PROCEDURE"; - const string obj_name = routine->getName().toString(); - raiseObjectInUseError(obj_type, obj_name.hasData() ? obj_name : name.toString()); + raiseObjectInUseError(obj_type, (routine->getName().object.hasData() ? routine->getName() : name)); } -static void raiseTooManyVersionsError(const int obj_type, const string& obj_name) +static void raiseTooManyVersionsError(const int obj_type, const QualifiedName& obj_name) { ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(getErrorCodeByObjectType(obj_type)) << Arg::Str(obj_name) << + Arg::Gds(getErrorCodeByObjectType(obj_type)) << obj_name.toQuotedString() << Arg::Gds(isc_version_err)); } @@ -699,8 +708,7 @@ namespace const bool compile = !work->findArg(dfw_arg_check_blr); getDependencies(work, compile, transaction); - T* routine = lookupByName(tdbb, - QualifiedName(work->dfw_name, work->dfw_package), compile); + T* routine = lookupByName(tdbb, work->getQualifiedName(), compile); if (!routine) return false; @@ -717,7 +725,7 @@ namespace jrd_tra* transaction) { SET_TDBB(tdbb); - const QualifiedName name(work->dfw_name, work->dfw_package); + const QualifiedName name(work->getQualifiedName()); Routine* routine; switch (phase) @@ -769,12 +777,12 @@ namespace { ///raiseRoutineInUseError(routine, name); gds__log("Modifying %s %s which is currently in use by active user requests", - Self::getTypeStr(), name.toString().c_str()); + Self::getTypeStr(), name.toQuotedString().c_str()); USHORT alterCount = routine->alterCount; if (alterCount > Routine::MAX_ALTER_COUNT) - raiseTooManyVersionsError(routine->getObjectType(), work->dfw_name); + raiseTooManyVersionsError(routine->getObjectType(), work->getQualifiedName()); if (routine->existenceLock) LCK_release(tdbb, routine->existenceLock); @@ -805,7 +813,7 @@ namespace // delete dependency lists if (work->dfw_package.isEmpty()) - MET_delete_dependencies(tdbb, work->dfw_name, objType, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), objType, transaction); /* the routine has just been scanned by lookupById and its Routine::FLAG_SCANNED flag is set. We are going to reread it @@ -870,7 +878,7 @@ namespace jrd_tra* transaction) { SET_TDBB(tdbb); - const QualifiedName name(work->dfw_name, work->dfw_package); + const QualifiedName name(work->getQualifiedName()); T* routine; switch (phase) @@ -886,8 +894,7 @@ namespace return false; case 1: - check_dependencies(tdbb, work->dfw_name.c_str(), NULL, work->dfw_package.c_str(), - objType, transaction); + check_dependencies(tdbb, work->getQualifiedName(), NULL, objType, transaction); return true; case 2: @@ -924,10 +931,10 @@ namespace { ///raiseRoutineInUseError(routine, name); gds__log("Deleting %s %s which is currently in use by active user requests", - Self::getTypeStr(), name.toString().c_str()); + Self::getTypeStr(), name.toQuotedString().c_str()); if (work->dfw_package.isEmpty()) - MET_delete_dependencies(tdbb, work->dfw_name, objType, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), objType, transaction); if (routine->existenceLock) LCK_release(tdbb, routine->existenceLock); @@ -953,7 +960,7 @@ namespace // delete dependency lists if (work->dfw_package.isEmpty()) - MET_delete_dependencies(tdbb, work->dfw_name, objType, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), objType, transaction); if (routine->existenceLock) LCK_release(tdbb, routine->existenceLock); @@ -989,8 +996,9 @@ namespace if (!routine) return; - const MetaName depName(work->dfw_package.isEmpty() ? - MetaName(work->dfw_name) : work->dfw_package); + const QualifiedName depName(work->dfw_package.isEmpty() ? + work->getQualifiedName() : + QualifiedName(work->dfw_package, work->dfw_schema)); if (!blobId.isEmpty()) { @@ -1024,14 +1032,14 @@ namespace { for (const auto parameter : *parameters) { - if (parameter->prm_type_of_table.hasData()) + if (parameter->prm_type_of_table.object.hasData()) { CompilerScratch::Dependency dependency(obj_relation); dependency.relation = MET_lookup_relation(tdbb, parameter->prm_type_of_table); dependency.subName = ¶meter->prm_type_of_column; dependencies.push(dependency); } - else if (!fb_utils::implicit_domain(parameter->prm_field_source.c_str())) + else if (!fb_utils::implicit_domain(parameter->prm_field_source.object.c_str())) { CompilerScratch::Dependency dependency(obj_field); dependency.name = ¶meter->prm_field_source; @@ -1108,13 +1116,13 @@ namespace Routine* routine = NULL; FOR(REQUEST_HANDLE handle) - X IN RDB$FUNCTIONS WITH - X.RDB$FUNCTION_NAME EQ work->dfw_name.c_str() AND - X.RDB$PACKAGE_NAME EQUIV NULLIF(work->dfw_package.c_str(), '') + X IN RDB$FUNCTIONS + WITH X.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + X.RDB$FUNCTION_NAME EQ work->dfw_name.c_str() AND + X.RDB$PACKAGE_NAME EQUIV NULLIF(work->dfw_package.c_str(), '') { blobId = X.RDB$FUNCTION_BLR; - routine = Function::lookup(tdbb, - QualifiedName(work->dfw_name, work->dfw_package), !compile); + routine = Function::lookup(tdbb, work->getQualifiedName(), !compile); } END_FOR @@ -1149,21 +1157,26 @@ namespace FOR (REQUEST_HANDLE handle) DEP IN RDB$DEPENDENCIES - WITH DEP.RDB$DEPENDED_ON_NAME EQ work->dfw_name.c_str() AND + WITH DEP.RDB$DEPENDED_ON_SCHEMA_NAME EQ work->dfw_schema.c_str() AND + DEP.RDB$DEPENDED_ON_NAME EQ work->dfw_name.c_str() AND DEP.RDB$PACKAGE_NAME EQUIV NULLIF(work->dfw_package.c_str(), '') AND DEP.RDB$DEPENDED_ON_TYPE = obj_udf AND NOT DEP.RDB$FIELD_NAME MISSING AND NOT ANY ARG IN RDB$FUNCTION_ARGUMENTS - WITH ARG.RDB$FUNCTION_NAME EQ DEP.RDB$DEPENDED_ON_NAME AND + WITH ARG.RDB$SCHEMA_NAME EQ DEP.RDB$DEPENDED_ON_SCHEMA_NAME AND + ARG.RDB$FUNCTION_NAME EQ DEP.RDB$DEPENDED_ON_NAME AND ARG.RDB$PACKAGE_NAME EQUIV DEP.RDB$PACKAGE_NAME AND ARG.RDB$ARGUMENT_NAME EQ DEP.RDB$FIELD_NAME { // If the found object is also being deleted, there's no dependency - if (!find_depend_in_dfw(tdbb, DEP.RDB$DEPENDENT_NAME, DEP.RDB$DEPENDENT_TYPE, 0, transaction)) + if (!find_depend_in_dfw(tdbb, + QualifiedName(DEP.RDB$DEPENDENT_NAME, + (DEP.RDB$DEPENDENT_SCHEMA_NAME.NULL ? "" : DEP.RDB$DEPENDENT_SCHEMA_NAME)), + DEP.RDB$DEPENDENT_TYPE, 0, transaction)) { string& name = names.add(); - name.printf("%s.%s", work->dfw_name.c_str(), DEP.RDB$FIELD_NAME); + name.printf("%s.%s", work->getQualifiedName().toQuotedString().c_str(), DEP.RDB$FIELD_NAME); ++depCount; } @@ -1192,13 +1205,13 @@ namespace Routine* routine = NULL; FOR(REQUEST_HANDLE handle) - X IN RDB$PROCEDURES WITH - X.RDB$PROCEDURE_NAME EQ work->dfw_name.c_str() AND - X.RDB$PACKAGE_NAME EQUIV NULLIF(work->dfw_package.c_str(), '') + X IN RDB$PROCEDURES + WITH X.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + X.RDB$PROCEDURE_NAME EQ work->dfw_name.c_str() AND + X.RDB$PACKAGE_NAME EQUIV NULLIF(work->dfw_package.c_str(), '') { blobId = X.RDB$PROCEDURE_BLR; - routine = MET_lookup_procedure(tdbb, - QualifiedName(work->dfw_name, work->dfw_package), !compile); + routine = MET_lookup_procedure(tdbb, work->getQualifiedName(), !compile); } END_FOR @@ -1233,21 +1246,26 @@ namespace FOR (REQUEST_HANDLE handle) DEP IN RDB$DEPENDENCIES - WITH DEP.RDB$DEPENDED_ON_NAME EQ work->dfw_name.c_str() AND + WITH DEP.RDB$DEPENDED_ON_SCHEMA_NAME EQ work->dfw_schema.c_str() AND + DEP.RDB$DEPENDED_ON_NAME EQ work->dfw_name.c_str() AND DEP.RDB$PACKAGE_NAME EQUIV NULLIF(work->dfw_package.c_str(), '') AND DEP.RDB$DEPENDED_ON_TYPE = obj_procedure AND NOT DEP.RDB$FIELD_NAME MISSING AND NOT ANY PP IN RDB$PROCEDURE_PARAMETERS - WITH PP.RDB$PROCEDURE_NAME EQ DEP.RDB$DEPENDED_ON_NAME AND + WITH PP.RDB$SCHEMA_NAME EQ DEP.RDB$DEPENDED_ON_SCHEMA_NAME AND + PP.RDB$PROCEDURE_NAME EQ DEP.RDB$DEPENDED_ON_NAME AND PP.RDB$PACKAGE_NAME EQUIV DEP.RDB$PACKAGE_NAME AND PP.RDB$PARAMETER_NAME EQ DEP.RDB$FIELD_NAME { // If the found object is also being deleted, there's no dependency - if (!find_depend_in_dfw(tdbb, DEP.RDB$DEPENDENT_NAME, DEP.RDB$DEPENDENT_TYPE, 0, transaction)) + if (!find_depend_in_dfw(tdbb, + QualifiedName(DEP.RDB$DEPENDENT_NAME, + (DEP.RDB$DEPENDENT_SCHEMA_NAME.NULL ? "" : DEP.RDB$DEPENDENT_SCHEMA_NAME)), + DEP.RDB$DEPENDENT_TYPE, 0, transaction)) { string& name = names.add(); - name.printf("%s.%s", work->dfw_name.c_str(), DEP.RDB$FIELD_NAME); + name.printf("%s.%s", work->getQualifiedName().toQuotedString().c_str(), DEP.RDB$FIELD_NAME); ++depCount; } @@ -1321,7 +1339,7 @@ static const deferred_task task_table[] = }; -USHORT DFW_assign_index_type(thread_db* tdbb, const MetaName& name, SSHORT field_type, +USHORT DFW_assign_index_type(thread_db* tdbb, const QualifiedName& name, SSHORT field_type, SSHORT ttype) { /************************************** @@ -1360,7 +1378,7 @@ USHORT DFW_assign_index_type(thread_db* tdbb, const MetaName& name, SSHORT field return INTL_TEXT_TO_INDEX(ttype); ERR_post_nothrow(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_random) << Arg::Str(name)); + Arg::Gds(isc_random) << name.toQuotedString()); INTL_texttype_lookup(tdbb, ttype); // should punt ERR_punt(); // if INTL_texttype_lookup hasn't punt } @@ -1698,7 +1716,7 @@ void DFW_perform_post_commit_work(jrd_tra* transaction) } -DeferredWork* DFW_post_work(jrd_tra* transaction, enum dfw_t type, const dsc* desc, USHORT id, +DeferredWork* DFW_post_work(jrd_tra* transaction, enum dfw_t type, const dsc* desc, const dsc* schemaDesc, USHORT id, const MetaName& package) { /************************************** @@ -1712,12 +1730,12 @@ DeferredWork* DFW_post_work(jrd_tra* transaction, enum dfw_t type, const dsc* de * **************************************/ - return DFW_post_work(transaction, type, get_string(desc), id, package); + return DFW_post_work(transaction, type, get_string(desc), get_string(schemaDesc), id, package); } -DeferredWork* DFW_post_work(jrd_tra* transaction, enum dfw_t type, const string& name, USHORT id, - const MetaName& package) +DeferredWork* DFW_post_work(jrd_tra* transaction, enum dfw_t type, const string& name, const MetaName& schema, + USHORT id, const MetaName& package) { /************************************** * @@ -1752,7 +1770,7 @@ DeferredWork* DFW_post_work(jrd_tra* transaction, enum dfw_t type, const string& job->hash.add(sp); } - DeferredWork tmp(AutoStorage::getAutoMemoryPool(), 0, type, id, sav_number, name, package); + DeferredWork tmp(AutoStorage::getAutoMemoryPool(), 0, type, id, sav_number, name, schema, package); DeferredWork* work = sp->hash.lookup(tmp); if (work) { @@ -1763,7 +1781,7 @@ DeferredWork* DFW_post_work(jrd_tra* transaction, enum dfw_t type, const string& // Not already posted, so do so now. work = FB_NEW_POOL(*transaction->tra_pool) - DeferredWork(*transaction->tra_pool, &(job->end), type, id, sav_number, name, package); + DeferredWork(*transaction->tra_pool, &(job->end), type, id, sav_number, name, schema, package); job->end = work->getNextPtr(); fb_assert(!(*job->end)); sp->hash.add(work); @@ -1787,7 +1805,7 @@ DeferredWork* DFW_post_work(jrd_tra* transaction, enum dfw_t type, const string& } -DeferredWork* DFW_post_work_arg( jrd_tra* transaction, DeferredWork* work, const dsc* desc, +DeferredWork* DFW_post_work_arg(jrd_tra* transaction, DeferredWork* work, const dsc* nameDesc, const dsc* schemaDesc, USHORT id) { /************************************** @@ -1800,11 +1818,11 @@ DeferredWork* DFW_post_work_arg( jrd_tra* transaction, DeferredWork* work, const * Post an argument for work to be deferred to commit time. * **************************************/ - return DFW_post_work_arg(transaction, work, desc, id, work->dfw_type); + return DFW_post_work_arg(transaction, work, nameDesc, schemaDesc, id, work->dfw_type); } -DeferredWork* DFW_post_work_arg( jrd_tra* transaction, DeferredWork* work, const dsc* desc, +DeferredWork* DFW_post_work_arg( jrd_tra* transaction, DeferredWork* work, const dsc* nameDesc, const dsc* schemaDesc, USHORT id, Jrd::dfw_t type) { /************************************** @@ -1817,14 +1835,14 @@ DeferredWork* DFW_post_work_arg( jrd_tra* transaction, DeferredWork* work, const * Post an argument for work to be deferred to commit time. * **************************************/ - const Firebird::string name = get_string(desc); - DeferredWork* arg = work->findArg(type); if (! arg) { + const auto schema = get_string(schemaDesc); + const auto name = get_string(nameDesc); arg = FB_NEW_POOL(*transaction->tra_pool) - DeferredWork(*transaction->tra_pool, 0, type, id, 0, name, ""); + DeferredWork(*transaction->tra_pool, 0, type, id, 0, name, schema, {}); work->dfw_args.add(arg); } @@ -1832,7 +1850,7 @@ DeferredWork* DFW_post_work_arg( jrd_tra* transaction, DeferredWork* work, const } -void DFW_update_index(const TEXT* name, USHORT id, const SelectivityList& selectivity, +void DFW_update_index(const QualifiedName& name, USHORT id, const SelectivityList& selectivity, jrd_tra* transaction) { /************************************** @@ -1851,8 +1869,10 @@ void DFW_update_index(const TEXT* name, USHORT id, const SelectivityList& select AutoCacheRequest request(tdbb, irq_m_index_seg, IRQ_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - SEG IN RDB$INDEX_SEGMENTS WITH SEG.RDB$INDEX_NAME EQ name - SORTED BY SEG.RDB$FIELD_POSITION + SEG IN RDB$INDEX_SEGMENTS + WITH SEG.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + SEG.RDB$INDEX_NAME EQ name.object.c_str() + SORTED BY SEG.RDB$FIELD_POSITION { MODIFY SEG USING SEG.RDB$STATISTICS = selectivity[SEG.RDB$FIELD_POSITION]; @@ -1863,7 +1883,9 @@ void DFW_update_index(const TEXT* name, USHORT id, const SelectivityList& select request.reset(tdbb, irq_m_index, IRQ_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - IDX IN RDB$INDICES WITH IDX.RDB$INDEX_NAME EQ name + IDX IN RDB$INDICES + WITH IDX.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + IDX.RDB$INDEX_NAME EQ name.object.c_str() { MODIFY IDX USING IDX.RDB$INDEX_ID = id + 1; @@ -1912,7 +1934,7 @@ static bool add_shadow(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tr return true; case 4: - check_filename(work->dfw_name, false); + check_filename(work->dfw_name.c_str(), false); /* could have two cases: 1) this shadow has already been written to, so add this file using @@ -2004,7 +2026,7 @@ static bool add_difference(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr ERR_post(Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_wrong_backup_state)); } - check_filename(work->dfw_name, true); + check_filename(work->dfw_name.c_str(), true); dbb->dbb_backup_manager->setDifference(tdbb, work->dfw_name.c_str()); } break; @@ -2223,7 +2245,7 @@ static bool check_not_null(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr case 3: { - jrd_rel* relation = MET_lookup_relation(tdbb, work->dfw_name); + jrd_rel* relation = MET_lookup_relation(tdbb, work->getQualifiedName()); if (!relation || relation->rel_view_rse || work->dfw_ids.isEmpty()) break; @@ -2240,7 +2262,9 @@ static bool check_not_null(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr FOR(REQUEST_HANDLE handle) RFL IN RDB$RELATION_FIELDS CROSS FLD IN RDB$FIELDS - WITH RFL.RDB$RELATION_NAME EQ work->dfw_name.c_str() AND + WITH RFL.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + RFL.RDB$RELATION_NAME EQ work->dfw_name.c_str() AND + FLD.RDB$SCHEMA_NAME EQ RFL.RDB$FIELD_SOURCE_SCHEMA_NAME AND FLD.RDB$FIELD_NAME EQ RFL.RDB$FIELD_SOURCE AND RFL.RDB$FIELD_ID EQ *itr AND (RFL.RDB$NULL_FLAG = TRUE OR FLD.RDB$NULL_FLAG = TRUE) @@ -2367,7 +2391,7 @@ static bool check_not_null(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr hasError = true; errs << Arg::Gds(isc_cannot_make_not_null) << (*relation->rel_fields)[fields[i]]->fld_name << - relation->rel_name; + relation->rel_name.toQuotedString(); } } @@ -2398,11 +2422,14 @@ static bool store_view_context_type(thread_db* tdbb, SSHORT phase, DeferredWork* AutoRequest handle1; FOR (REQUEST_HANDLE handle1 TRANSACTION_HANDLE transaction) - VRL IN RDB$VIEW_RELATIONS CROSS - REL IN RDB$RELATIONS OVER RDB$RELATION_NAME WITH - VRL.RDB$VIEW_NAME = work->dfw_name.c_str() AND - VRL.RDB$VIEW_CONTEXT = work->dfw_id AND - VRL.RDB$PACKAGE_NAME MISSING + VRL IN RDB$VIEW_RELATIONS + CROSS REL IN RDB$RELATIONS + WITH VRL.RDB$SCHEMA_NAME = work->dfw_schema.c_str() AND + VRL.RDB$VIEW_NAME = work->dfw_name.c_str() AND + VRL.RDB$VIEW_CONTEXT = work->dfw_id AND + VRL.RDB$PACKAGE_NAME MISSING AND + REL.RDB$SCHEMA_NAME EQ VRL.RDB$RELATION_SCHEMA_NAME AND + REL.RDB$RELATION_NAME EQ VRL.RDB$RELATION_NAME { vct = (REL.RDB$VIEW_BLR.NULL ? VCT_TABLE : VCT_VIEW); } @@ -2410,9 +2437,10 @@ static bool store_view_context_type(thread_db* tdbb, SSHORT phase, DeferredWork* AutoRequest handle2; FOR (REQUEST_HANDLE handle2 TRANSACTION_HANDLE transaction) - VRL IN RDB$VIEW_RELATIONS WITH - VRL.RDB$VIEW_NAME = work->dfw_name.c_str() AND - VRL.RDB$VIEW_CONTEXT = work->dfw_id + VRL IN RDB$VIEW_RELATIONS + WITH VRL.RDB$SCHEMA_NAME = work->dfw_schema.c_str() AND + VRL.RDB$VIEW_NAME = work->dfw_name.c_str() AND + VRL.RDB$VIEW_CONTEXT = work->dfw_id { MODIFY VRL USING VRL.RDB$CONTEXT_TYPE.NULL = FALSE; @@ -2467,8 +2495,8 @@ static bool drop_package_header(thread_db* tdbb, SSHORT phase, DeferredWork* wor switch (phase) { case 1: - MET_delete_dependencies(tdbb, work->dfw_name, obj_package_body, transaction); - MET_delete_dependencies(tdbb, work->dfw_name, obj_package_header, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), obj_package_body, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), obj_package_header, transaction); break; } @@ -2484,7 +2512,7 @@ static bool modify_package_header(thread_db* tdbb, SSHORT phase, DeferredWork* w switch (phase) { case 1: - MET_delete_dependencies(tdbb, work->dfw_name, obj_package_header, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), obj_package_header, transaction); break; } @@ -2500,7 +2528,7 @@ static bool drop_package_body(thread_db* tdbb, SSHORT phase, DeferredWork* work, switch (phase) { case 1: - MET_delete_dependencies(tdbb, work->dfw_name, obj_package_body, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), obj_package_body, transaction); break; } @@ -2526,7 +2554,7 @@ static bool grant_privileges(thread_db* tdbb, SSHORT phase, DeferredWork* work, return true; case 2: - GRANT_privileges(tdbb, work->dfw_name, work->dfw_id, transaction); + GRANT_privileges(tdbb, QualifiedName(work->dfw_name, work->dfw_schema), work->dfw_id, transaction); break; default: @@ -2554,8 +2582,8 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* { case 0: cleanup_index_creation(tdbb, work, transaction); - MET_delete_dependencies(tdbb, work->dfw_name, obj_index_expression, transaction); - MET_delete_dependencies(tdbb, work->dfw_name, obj_index_condition, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), obj_index_expression, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), obj_index_condition, transaction); return false; case 1: @@ -2576,23 +2604,24 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* AutoCacheRequest request(tdbb, irq_c_exp_index, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - IDX IN RDB$INDICES CROSS - REL IN RDB$RELATIONS OVER RDB$RELATION_NAME WITH - IDX.RDB$EXPRESSION_BLR NOT MISSING AND - IDX.RDB$INDEX_NAME EQ work->dfw_name.c_str() + IDX IN RDB$INDICES + CROSS REL IN RDB$RELATIONS OVER RDB$SCHEMA_NAME, RDB$RELATION_NAME + WITH IDX.RDB$EXPRESSION_BLR NOT MISSING AND + IDX.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + IDX.RDB$INDEX_NAME EQ work->dfw_name.c_str() { if (!relation) { relation = MET_relation(tdbb, REL.RDB$RELATION_ID); - if (relation->rel_name.length() == 0) - relation->rel_name = REL.RDB$RELATION_NAME; + if (relation->rel_name.object.isEmpty()) + relation->rel_name = QualifiedName(REL.RDB$RELATION_NAME, REL.RDB$SCHEMA_NAME); if (IDX.RDB$INDEX_ID && IDX.RDB$STATISTICS < 0.0) { SelectivityList selectivity(*tdbb->getDefaultPool()); const USHORT localId = IDX.RDB$INDEX_ID - 1; IDX_statistics(tdbb, relation, localId, selectivity); - DFW_update_index(work->dfw_name.c_str(), localId, selectivity, transaction); + DFW_update_index(work->getQualifiedName(), localId, selectivity, transaction); return false; } @@ -2600,8 +2629,8 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* if (IDX.RDB$INDEX_ID) { IDX_delete_index(tdbb, relation, IDX.RDB$INDEX_ID - 1); - MET_delete_dependencies(tdbb, work->dfw_name, obj_index_expression, transaction); - MET_delete_dependencies(tdbb, work->dfw_name, obj_index_condition, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), obj_index_expression, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), obj_index_condition, transaction); MODIFY IDX IDX.RDB$INDEX_ID.NULL = TRUE; END_MODIFY @@ -2614,7 +2643,7 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* { // Msg359: segments not allowed in expression index %s ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_no_segments_err) << Arg::Str(work->dfw_name)); + Arg::Gds(isc_no_segments_err) << work->getQualifiedName().toQuotedString()); } if (IDX.RDB$UNIQUE_FLAG) idx.idx_flags |= idx_unique; @@ -2632,7 +2661,7 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* Jrd::ContextPoolHolder context(tdbb, new_pool); MET_get_dependencies(tdbb, relation, nullptr, 0, nullptr, &IDX.RDB$EXPRESSION_BLR, - nullptr, &csb, work->dfw_name, obj_index_expression, 0, + nullptr, &csb, work->getQualifiedName(), obj_index_expression, 0, transaction); idx.idx_expression_statement = Statement::makeValueExpression(tdbb, @@ -2643,7 +2672,7 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* idx.idx_count = 1; idx.idx_flags |= idx_expression; idx.idx_rpt[0].idx_itype = - DFW_assign_index_type(tdbb, work->dfw_name, + DFW_assign_index_type(tdbb, work->getQualifiedName(), idx.idx_expression_desc.dsc_dtype, idx.idx_expression_desc.dsc_sub_type); idx.idx_rpt[0].idx_selectivity = 0; @@ -2665,7 +2694,7 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* Jrd::ContextPoolHolder context(tdbb, new_pool); MET_get_dependencies(tdbb, relation, nullptr, 0, nullptr, &IDX.RDB$CONDITION_BLR, - nullptr, &csb, work->dfw_name, obj_index_condition, 0, + nullptr, &csb, work->getQualifiedName(), obj_index_condition, 0, transaction); idx.idx_condition_statement = Statement::makeBoolExpression(tdbb, @@ -2687,7 +2716,7 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* { // Msg308: can't create index %s ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_idx_create_err) << Arg::Str(work->dfw_name)); + Arg::Gds(isc_idx_create_err) << work->getQualifiedName().toQuotedString()); } delete csb; @@ -2706,7 +2735,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_create_index(tdbb, relation, &idx, work->dfw_name.c_str(), &work->dfw_id, + IDX_create_index(tdbb, relation, &idx, work->getQualifiedName(), &work->dfw_id, transaction, selectivity); fb_assert(work->dfw_id == idx.idx_id); @@ -2727,7 +2756,7 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* tdbb->setTransaction(current_transaction); tdbb->setRequest(current_request); - DFW_update_index(work->dfw_name.c_str(), idx.idx_id, selectivity, transaction); + DFW_update_index(work->getQualifiedName(), idx.idx_id, selectivity, transaction); // Get rid of the expression/condition statements idx.idx_expression_statement->release(tdbb); @@ -2745,7 +2774,7 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* static void check_computed_dependencies(thread_db* tdbb, jrd_tra* transaction, - const MetaName& fieldName) + const QualifiedName& fieldName) { /************************************** * @@ -2760,8 +2789,8 @@ static void check_computed_dependencies(thread_db* tdbb, jrd_tra* transaction, SET_TDBB(tdbb); bool err = false; - Firebird::SortedObjectsArray sortedNames(*tdbb->getDefaultPool()); - Firebird::ObjectsArray names; + Firebird::SortedObjectsArray sortedNames(*tdbb->getDefaultPool()); + Firebird::ObjectsArray names; sortedNames.add(fieldName); names.add(fieldName); @@ -2771,15 +2800,17 @@ static void check_computed_dependencies(thread_db* tdbb, jrd_tra* transaction, AutoCacheRequest request(tdbb, irq_comp_circ_dpd, IRQ_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - DEP IN RDB$DEPENDENCIES CROSS - RFL IN RDB$RELATION_FIELDS WITH - DEP.RDB$DEPENDENT_NAME EQ names[pos].c_str() AND - DEP.RDB$DEPENDENT_TYPE EQ obj_computed AND - DEP.RDB$DEPENDED_ON_TYPE = obj_relation AND - RFL.RDB$RELATION_NAME = DEP.RDB$DEPENDED_ON_NAME AND - RFL.RDB$FIELD_NAME = DEP.RDB$FIELD_NAME + DEP IN RDB$DEPENDENCIES + CROSS RFL IN RDB$RELATION_FIELDS + WITH DEP.RDB$DEPENDENT_SCHEMA_NAME EQ names[pos].schema.c_str() AND + DEP.RDB$DEPENDENT_NAME EQ names[pos].object.c_str() AND + DEP.RDB$DEPENDENT_TYPE EQ obj_computed AND + DEP.RDB$DEPENDED_ON_TYPE = obj_relation AND + RFL.RDB$SCHEMA_NAME = DEP.RDB$DEPENDED_ON_SCHEMA_NAME AND + RFL.RDB$RELATION_NAME = DEP.RDB$DEPENDED_ON_NAME AND + RFL.RDB$FIELD_NAME = DEP.RDB$FIELD_NAME { - MetaName fieldSource(RFL.RDB$FIELD_SOURCE); + const QualifiedName fieldSource(RFL.RDB$FIELD_SOURCE, RFL.RDB$FIELD_SOURCE_SCHEMA_NAME); if (fieldName == fieldSource) { @@ -2805,9 +2836,8 @@ static void check_computed_dependencies(thread_db* tdbb, jrd_tra* transaction, static void check_dependencies(thread_db* tdbb, - const TEXT* dpdo_name, - const TEXT* field_name, - const TEXT* package_name, + const QualifiedName& dpdo_name, + const MetaName& field_name, int dpdo_type, jrd_tra* transaction) { @@ -2825,28 +2855,27 @@ static void check_dependencies(thread_db* tdbb, SET_TDBB(tdbb); Jrd::Attachment* attachment = tdbb->getAttachment(); - const MetaName packageName(package_name); + SLONG dep_counts[obj_type_MAX] = {0}; - SLONG dep_counts[obj_type_MAX]; - for (int i = 0; i < obj_type_MAX; i++) - dep_counts[i] = 0; - - if (field_name) + if (field_name.hasData()) { AutoCacheRequest request(tdbb, irq_ch_f_dpd, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) DEP IN RDB$DEPENDENCIES - WITH DEP.RDB$DEPENDED_ON_NAME EQ dpdo_name - AND DEP.RDB$DEPENDED_ON_TYPE = dpdo_type - AND DEP.RDB$FIELD_NAME EQ field_name - AND DEP.RDB$PACKAGE_NAME EQUIV NULLIF(packageName.c_str(), '') - REDUCED TO DEP.RDB$DEPENDENT_NAME + WITH DEP.RDB$DEPENDED_ON_SCHEMA_NAME EQUIV NULLIF(dpdo_name.schema.c_str(), '') AND + DEP.RDB$DEPENDED_ON_NAME EQ dpdo_name.object.c_str() AND + DEP.RDB$DEPENDED_ON_TYPE = dpdo_type AND + DEP.RDB$FIELD_NAME EQ field_name.c_str() AND + DEP.RDB$PACKAGE_NAME EQUIV NULLIF(dpdo_name.package.c_str(), '') + REDUCED TO DEP.RDB$DEPENDENT_SCHEMA_NAME, DEP.RDB$DEPENDENT_NAME, DEP.RDB$DEPENDENT_TYPE { // If the found object is also being deleted, there's no dependency - if (!find_depend_in_dfw(tdbb, DEP.RDB$DEPENDENT_NAME, DEP.RDB$DEPENDENT_TYPE, - 0, transaction)) + if (!find_depend_in_dfw(tdbb, + QualifiedName(DEP.RDB$DEPENDENT_NAME, + (DEP.RDB$DEPENDENT_SCHEMA_NAME.NULL ? "" : DEP.RDB$DEPENDENT_SCHEMA_NAME)), + DEP.RDB$DEPENDENT_TYPE, 0, transaction)) { ++dep_counts[DEP.RDB$DEPENDENT_TYPE]; } @@ -2859,14 +2888,18 @@ static void check_dependencies(thread_db* tdbb, FOR(REQUEST_HANDLE request) DEP IN RDB$DEPENDENCIES - WITH DEP.RDB$DEPENDED_ON_NAME EQ dpdo_name - AND DEP.RDB$DEPENDED_ON_TYPE = dpdo_type - AND DEP.RDB$PACKAGE_NAME EQUIV NULLIF(packageName.c_str(), '') - REDUCED TO DEP.RDB$DEPENDENT_NAME + WITH DEP.RDB$DEPENDED_ON_SCHEMA_NAME EQUIV NULLIF(dpdo_name.schema.c_str(), '') AND + DEP.RDB$DEPENDED_ON_NAME EQ dpdo_name.object.c_str() AND + DEP.RDB$DEPENDED_ON_TYPE = dpdo_type AND + DEP.RDB$PACKAGE_NAME EQUIV NULLIF(dpdo_name.package.c_str(), '') + REDUCED TO DEP.RDB$DEPENDENT_SCHEMA_NAME, DEP.RDB$DEPENDENT_NAME, DEP.RDB$DEPENDENT_TYPE { // If the found object is also being deleted, there's no dependency - if (!find_depend_in_dfw(tdbb, DEP.RDB$DEPENDENT_NAME, DEP.RDB$DEPENDENT_TYPE, + if (!find_depend_in_dfw(tdbb, + QualifiedName(DEP.RDB$DEPENDENT_NAME, + (DEP.RDB$DEPENDENT_SCHEMA_NAME.NULL ? "" : DEP.RDB$DEPENDENT_SCHEMA_NAME)), + DEP.RDB$DEPENDENT_TYPE, 0, transaction)) { ++dep_counts[DEP.RDB$DEPENDENT_TYPE]; @@ -2882,11 +2915,11 @@ static void check_dependencies(thread_db* tdbb, if (!total) return; - if (field_name) + if (field_name.hasData()) { - string fld_name(dpdo_name); + string fld_name(dpdo_name.toQuotedString()); fld_name.append("."); - fld_name.append(field_name); + fld_name.append(field_name.toQuotedString()); ERR_post(Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_no_delete) << // Msg353: can not delete @@ -2898,7 +2931,7 @@ static void check_dependencies(thread_db* tdbb, ERR_post(Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_no_delete) << // can not delete Arg::Gds(getErrorCodeByObjectType(dpdo_type)) << - Arg::Str(QualifiedName(dpdo_name, packageName).toString()) << + dpdo_name.toQuotedString() << Arg::Gds(isc_dependency) << Arg::Num(total)); // there are %ld dependencies } } @@ -2939,13 +2972,16 @@ static void cleanup_index_creation(thread_db* tdbb, DeferredWork* work, jrd_tra* AutoRequest request; - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) IDXN IN RDB$INDICES CROSS - IREL IN RDB$RELATIONS OVER RDB$RELATION_NAME - WITH IDXN.RDB$INDEX_NAME EQ work->dfw_name.c_str() + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + IDXN IN RDB$INDICES + CROSS IREL IN RDB$RELATIONS OVER RDB$SCHEMA_NAME, RDB$RELATION_NAME + WITH IDXN.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + IDXN.RDB$INDEX_NAME EQ work->dfw_name.c_str() AND // dimitr: I have no idea why the condition below is required here - AND IREL.RDB$VIEW_BLR MISSING // views do not have indices + IREL.RDB$VIEW_BLR MISSING // views do not have indices { - jrd_rel* const relation = MET_lookup_relation(tdbb, IDXN.RDB$RELATION_NAME); + const auto relation = MET_lookup_relation(tdbb, + QualifiedName(IDXN.RDB$RELATION_NAME, IDXN.RDB$SCHEMA_NAME)); RelationPages* const relPages = relation->getPages(tdbb, MAX_TRA_NUMBER, false); if (relPages && relPages->rel_index_root) @@ -2993,7 +3029,7 @@ static void cleanup_index_creation(thread_db* tdbb, DeferredWork* work, jrd_tra* idx.idx_flags = idx_foreign; jrd_rel* partner_relation = NULL; - if (MET_lookup_partner(tdbb, relation, &idx, work->dfw_name.c_str())) + if (MET_lookup_partner(tdbb, relation, &idx, work->getQualifiedName())) { partner_relation = MET_lookup_relation_id(tdbb, idx.idx_primary_relation, true); } @@ -3083,15 +3119,20 @@ static bool compute_security(thread_db* tdbb, SSHORT phase, DeferredWork* work, case 3: { + fb_assert(work->dfw_schema.isEmpty()); + // Get security class. This may return NULL if it doesn't exist - SCL_clear_classes(tdbb, work->dfw_name.c_str()); + SCL_clear_classes(tdbb, work->dfw_name); - AutoRequest handle; - FOR(REQUEST_HANDLE handle) X IN RDB$DATABASE + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + + FOR(REQUEST_HANDLE requestHandle) + X IN RDB$DATABASE WITH X.RDB$SECURITY_CLASS EQ work->dfw_name.c_str() { - attachment->att_security_class = SCL_get_class(tdbb, work->dfw_name.c_str()); + attachment->att_security_class = SCL_get_class(tdbb, work->dfw_name); } END_FOR } @@ -3159,8 +3200,9 @@ static bool modify_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ sql << "select" << sql("rel.rdb$relation_id,", rdbRelationID) << sql("rel.rdb$relation_type", rdbRelationType) - << "from rdb$indices idx join rdb$relations rel using (rdb$relation_name)" - << "where idx.rdb$index_name = " << work->dfw_name + << "from system.rdb$indices idx join system.rdb$relations rel using (rdb$schema_name, rdb$relation_name)" + << "where idx.rdb$schema_name = " << work->dfw_schema + << " and idx.rdb$index_name = " << work->dfw_name << " and rel.rdb$relation_id is not null"; AutoPreparedStatement ps(attachment->prepareStatement(tdbb, attachment->getSysTransaction(), sql)); @@ -3246,15 +3288,16 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ request.reset(tdbb, irq_c_index, IRQ_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - IDX IN RDB$INDICES CROSS - REL IN RDB$RELATIONS OVER RDB$RELATION_NAME - WITH IDX.RDB$INDEX_NAME EQ work->dfw_name.c_str() + IDX IN RDB$INDICES + CROSS REL IN RDB$RELATIONS OVER RDB$SCHEMA_NAME, RDB$RELATION_NAME + WITH IDX.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + IDX.RDB$INDEX_NAME EQ work->dfw_name.c_str() { relation = MET_lookup_relation_id(tdbb, REL.RDB$RELATION_ID, false); if (!relation) { ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_idx_create_err) << Arg::Str(work->dfw_name)); + Arg::Gds(isc_idx_create_err) << work->getQualifiedName().toQuotedString()); // Msg308: can't create index %s } @@ -3273,7 +3316,7 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ SelectivityList selectivity(*tdbb->getDefaultPool()); const USHORT id = IDX.RDB$INDEX_ID - 1; IDX_statistics(tdbb, relation, id, selectivity); - DFW_update_index(work->dfw_name.c_str(), id, selectivity, transaction); + DFW_update_index(work->getQualifiedName(), id, selectivity, transaction); } return false; @@ -3286,7 +3329,9 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ AutoCacheRequest request2(tdbb, irq_c_index_m, IRQ_REQUESTS); FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) - IDXM IN RDB$INDICES WITH IDXM.RDB$INDEX_NAME EQ work->dfw_name.c_str() + IDXM IN RDB$INDICES + WITH IDXM.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + IDXM.RDB$INDEX_NAME EQ work->dfw_name.c_str() { MODIFY IDXM IDXM.RDB$INDEX_ID.NULL = TRUE; @@ -3305,13 +3350,13 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ if (!idx.idx_count) { ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_idx_seg_err) << Arg::Str(work->dfw_name)); + Arg::Gds(isc_idx_seg_err) << work->getQualifiedName().toQuotedString()); // Msg304: segment count of 0 defined for index %s } else { ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_idx_key_err) << Arg::Str(work->dfw_name)); + Arg::Gds(isc_idx_key_err) << work->getQualifiedName().toQuotedString()); // Msg311: too many keys defined for index %s } } @@ -3326,9 +3371,10 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ AutoCacheRequest rc_request(tdbb, irq_c_index_rc, IRQ_REQUESTS); FOR(REQUEST_HANDLE rc_request TRANSACTION_HANDLE transaction) - RC IN RDB$RELATION_CONSTRAINTS WITH - RC.RDB$INDEX_NAME EQ work->dfw_name.c_str() AND - RC.RDB$CONSTRAINT_TYPE = PRIMARY_KEY + RC IN RDB$RELATION_CONSTRAINTS + WITH RC.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + RC.RDB$INDEX_NAME EQ work->dfw_name.c_str() AND + RC.RDB$CONSTRAINT_TYPE = PRIMARY_KEY { idx.idx_flags |= idx_primary; } @@ -3349,7 +3395,7 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ Jrd::ContextPoolHolder context(tdbb, new_pool); MET_get_dependencies(tdbb, relation, nullptr, 0, nullptr, &IDX.RDB$CONDITION_BLR, - nullptr, &csb, work->dfw_name, obj_index_condition, 0, + nullptr, &csb, work->getQualifiedName(), obj_index_condition, 0, transaction); idx.idx_condition_statement = Statement::makeBoolExpression(tdbb, @@ -3377,10 +3423,13 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ SEG IN RDB$INDEX_SEGMENTS CROSS RFR IN RDB$RELATION_FIELDS CROSS FLD IN RDB$FIELDS - WITH SEG.RDB$INDEX_NAME EQ work->dfw_name.c_str() - AND RFR.RDB$RELATION_NAME EQ relation->rel_name.c_str() - AND RFR.RDB$FIELD_NAME EQ SEG.RDB$FIELD_NAME - AND FLD.RDB$FIELD_NAME EQ RFR.RDB$FIELD_SOURCE + WITH SEG.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + SEG.RDB$INDEX_NAME EQ work->dfw_name.c_str() AND + RFR.RDB$SCHEMA_NAME EQ SEG.RDB$SCHEMA_NAME AND + RFR.RDB$RELATION_NAME EQ relation->rel_name.object.c_str() AND + RFR.RDB$FIELD_NAME EQ SEG.RDB$FIELD_NAME AND + FLD.RDB$SCHEMA_NAME EQ RFR.RDB$FIELD_SOURCE_SCHEMA_NAME AND + FLD.RDB$FIELD_NAME EQ RFR.RDB$FIELD_SOURCE { if (++key_count > idx.idx_count || SEG.RDB$FIELD_POSITION > idx.idx_count || FLD.RDB$FIELD_TYPE == blr_blob || !FLD.RDB$DIMENSIONS.NULL) @@ -3388,7 +3437,7 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ if (key_count > idx.idx_count) { ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_idx_key_err) << Arg::Str(work->dfw_name)); + Arg::Gds(isc_idx_key_err) << work->getQualifiedName().toQuotedString()); // Msg311: too many keys defined for index %s } else if (SEG.RDB$FIELD_POSITION > idx.idx_count) @@ -3398,18 +3447,18 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ Arg::Gds(isc_inval_key_posn) << // Msg358: invalid key position Arg::Gds(isc_field_name) << Arg::Str(RFR.RDB$FIELD_NAME) << - Arg::Gds(isc_index_name) << Arg::Str(work->dfw_name)); + Arg::Gds(isc_index_name) << work->getQualifiedName().toQuotedString()); } else if (FLD.RDB$FIELD_TYPE == blr_blob) { ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_blob_idx_err) << Arg::Str(work->dfw_name)); + Arg::Gds(isc_blob_idx_err) << work->getQualifiedName().toQuotedString()); // Msg350: attempt to index blob column in index %s } else { ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_array_idx_err) << Arg::Str(work->dfw_name)); + Arg::Gds(isc_array_idx_err) << work->getQualifiedName().toQuotedString()); // Msg351: attempt to index array column in index %s } } @@ -3429,7 +3478,7 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ const SSHORT text_type = INTL_CS_COLL_TO_TTYPE(FLD.RDB$CHARACTER_SET_ID, collate); idx.idx_rpt[SEG.RDB$FIELD_POSITION].idx_itype = - DFW_assign_index_type(tdbb, work->dfw_name, gds_cvt_blr_dtype[FLD.RDB$FIELD_TYPE], text_type); + DFW_assign_index_type(tdbb, work->getQualifiedName(), gds_cvt_blr_dtype[FLD.RDB$FIELD_TYPE], text_type); // Initialize selectivity to zero. Otherwise random rubbish makes its way into database idx.idx_rpt[SEG.RDB$FIELD_POSITION].idx_selectivity = 0; @@ -3448,7 +3497,7 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ if (key_count != idx.idx_count) { ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_key_field_err) << Arg::Str(work->dfw_name)); + Arg::Gds(isc_key_field_err) << work->getQualifiedName().toQuotedString()); // Msg352: too few key columns found for index %s (incorrect column name?) } @@ -3459,7 +3508,7 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ if (relation->rel_view_rse) { ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_idx_create_err) << Arg::Str(work->dfw_name)); + Arg::Gds(isc_idx_create_err) << work->getQualifiedName().toQuotedString()); // Msg308: can't create index %s } @@ -3475,7 +3524,7 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ { idx.idx_id = idx_invalid; - if (MET_lookup_partner(tdbb, relation, &idx, work->dfw_name.c_str())) + if (MET_lookup_partner(tdbb, relation, &idx, work->getQualifiedName())) { partner_relation = MET_lookup_relation_id(tdbb, idx.idx_primary_relation, true); } @@ -3483,7 +3532,7 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ if (!partner_relation) { MetaName constraint_name; - MET_lookup_cnstrt_for_index(tdbb, constraint_name, work->dfw_name); + MET_lookup_cnstrt_for_index(tdbb, constraint_name, work->getQualifiedName()); ERR_post(Arg::Gds(isc_partner_idx_not_found) << Arg::Str(constraint_name)); } @@ -3528,10 +3577,10 @@ 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; SelectivityList selectivity(*tdbb->getDefaultPool()); - IDX_create_index(tdbb, relation, &idx, work->dfw_name.c_str(), + IDX_create_index(tdbb, relation, &idx, work->getQualifiedName(), &work->dfw_id, transaction, selectivity); fb_assert(work->dfw_id == idx.idx_id); - DFW_update_index(work->dfw_name.c_str(), idx.idx_id, selectivity, transaction); + DFW_update_index(work->getQualifiedName(), idx.idx_id, selectivity, transaction); if (idx.idx_condition_statement) idx.idx_condition_statement->release(tdbb); @@ -3592,9 +3641,10 @@ static bool create_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, j request.reset(tdbb, irq_c_relation3, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - X IN RDB$RELATIONS WITH - X.RDB$RELATION_NAME EQ work->dfw_name.c_str() AND - X.RDB$RELATION_ID NOT MISSING + X IN RDB$RELATIONS + WITH X.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + X.RDB$RELATION_NAME EQ work->dfw_name.c_str() AND + X.RDB$RELATION_ID NOT MISSING { rel_id = X.RDB$RELATION_ID; @@ -3646,8 +3696,10 @@ static bool create_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, j request.reset(tdbb, irq_c_relation, IRQ_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - X IN RDB$DATABASE CROSS Y IN RDB$RELATIONS WITH - Y.RDB$RELATION_NAME EQ work->dfw_name.c_str() + X IN RDB$DATABASE + CROSS Y IN RDB$RELATIONS + WITH Y.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + Y.RDB$RELATION_NAME EQ work->dfw_name.c_str() { blob_id = Y.RDB$VIEW_BLR; external_flag = Y.RDB$EXTERNAL_FILE[0]; @@ -3668,7 +3720,7 @@ static bool create_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, j if (rel_id == X.RDB$RELATION_ID) { ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_table_name) << Arg::Str(work->dfw_name) << + Arg::Gds(isc_table_name) << work->getQualifiedName().toQuotedString() << Arg::Gds(isc_imp_exc)); } } @@ -3687,11 +3739,14 @@ static bool create_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, j handle.reset(); FOR(REQUEST_HANDLE handle) - Z IN RDB$VIEW_RELATIONS CROSS - R IN RDB$RELATIONS OVER RDB$RELATION_NAME - WITH Z.RDB$VIEW_NAME = work->dfw_name.c_str() AND + Z IN RDB$VIEW_RELATIONS + CROSS R IN RDB$RELATIONS + WITH Z.RDB$SCHEMA_NAME = work->dfw_schema.c_str() AND + Z.RDB$VIEW_NAME = work->dfw_name.c_str() AND (Z.RDB$CONTEXT_TYPE = VCT_TABLE OR - Z.RDB$CONTEXT_TYPE = VCT_VIEW) + Z.RDB$CONTEXT_TYPE = VCT_VIEW) AND + R.RDB$SCHEMA_NAME EQ Z.RDB$RELATION_SCHEMA_NAME AND + R.RDB$RELATION_NAME EQ Z.RDB$RELATION_NAME { Y.RDB$DBKEY_LENGTH += R.RDB$DBKEY_LENGTH; } @@ -3724,15 +3779,16 @@ static bool create_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, j request.reset(tdbb, irq_c_relation2, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - X IN RDB$RELATIONS WITH - X.RDB$RELATION_NAME EQ work->dfw_name.c_str() + X IN RDB$RELATIONS + WITH X.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + X.RDB$RELATION_NAME EQ work->dfw_name.c_str() { rel_id = X.RDB$RELATION_ID; relation = MET_relation(tdbb, rel_id); relation->rel_flags |= REL_get_dependencies; relation->rel_flags &= ~REL_scanned; - DFW_post_work(transaction, dfw_scan_relation, NULL, rel_id); + DFW_post_work(transaction, dfw_scan_relation, nullptr, nullptr, rel_id); } END_FOR @@ -3844,7 +3900,7 @@ public: } // namespace DbgRebuildIntl -static string remove_icu_info_from_attributes(const string& charsetName, const string& specificAttributes) +static string remove_icu_info_from_attributes(const QualifiedName& charsetName, const string& specificAttributes) { DbgRebuildIntl::Lvl debLevel; @@ -3853,7 +3909,7 @@ static string remove_icu_info_from_attributes(const string& charsetName, const s if (IntlManager::lookupCharSet(charsetName, cs)) { - DbgRebuildIntl::out("Remove_icu_info_from_attributes for charset '%s'\n", charsetName.c_str()); + DbgRebuildIntl::out("Remove_icu_info_from_attributes for charset '%s'\n", charsetName.toQuotedString().c_str()); AutoPtr charSet(Firebird::CharSet::createInstance(*getDefaultMemoryPool(), 0, cs)); IntlUtil::SpecificAttributesMap map; @@ -3866,14 +3922,14 @@ static string remove_icu_info_from_attributes(const string& charsetName, const s } } else - DbgRebuildIntl::out("Remove_icu_info_from_attributes - NO CHARSET '%s'\n", charsetName.c_str()); + DbgRebuildIntl::out("Remove_icu_info_from_attributes - NO CHARSET '%s'\n", charsetName.toQuotedString().c_str()); return specificAttributes; } static void setupSpecificCollationAttributes(thread_db* tdbb, jrd_tra* transaction, - const USHORT charSetId, const char* collationName, bool dropIcuInfo) + const USHORT charSetId, const QualifiedName& collationName, bool dropIcuInfo) { /************************************** * @@ -3894,11 +3950,16 @@ static void setupSpecificCollationAttributes(thread_db* tdbb, jrd_tra* transacti FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) COLL IN RDB$COLLATIONS - CROSS CS IN RDB$CHARACTER_SETS - OVER RDB$CHARACTER_SET_ID - WITH COLL.RDB$COLLATION_NAME EQ collationName AND + CROSS CS IN RDB$CHARACTER_SETS OVER RDB$CHARACTER_SET_ID + WITH COLL.RDB$SCHEMA_NAME EQ collationName.schema.c_str() AND + COLL.RDB$COLLATION_NAME EQ collationName.object.c_str() AND COLL.RDB$CHARACTER_SET_ID EQ charSetId { + fb_utils::exact_name(COLL.RDB$COLLATION_NAME); + + if (!COLL.RDB$BASE_COLLATION_NAME.NULL) + fb_utils::exact_name(COLL.RDB$BASE_COLLATION_NAME); + SLONG length = 0; HalfStaticArray buffer; @@ -3910,11 +3971,11 @@ static void setupSpecificCollationAttributes(thread_db* tdbb, jrd_tra* transacti } const string specificAttributes((const char*) buffer.begin(), length); - DbgRebuildIntl::out("Try collation %s with %s\n", collationName, specificAttributes.c_str()); + DbgRebuildIntl::out("Try collation %s with %s\n", collationName.toQuotedString().c_str(), specificAttributes.c_str()); - MetaName charsetName(CS.RDB$CHARACTER_SET_NAME); + QualifiedName charsetName(CS.RDB$CHARACTER_SET_NAME, CS.RDB$SCHEMA_NAME); string icuLessAttributes = dropIcuInfo ? - remove_icu_info_from_attributes(charsetName.c_str(), specificAttributes) : specificAttributes; + remove_icu_info_from_attributes(charsetName, specificAttributes) : specificAttributes; DbgRebuildIntl::out("dropIcuInfo %d icuLessAttributes %s\n", dropIcuInfo, icuLessAttributes.c_str()); string newSpecificAttributes; @@ -3922,13 +3983,12 @@ static void setupSpecificCollationAttributes(thread_db* tdbb, jrd_tra* transacti // attributes. This should be what we want for new databases // and restores. CREATE COLLATION will fail in DYN. if (IntlManager::setupCollationAttributes( - fb_utils::exact_name(COLL.RDB$BASE_COLLATION_NAME.NULL ? - COLL.RDB$COLLATION_NAME : COLL.RDB$BASE_COLLATION_NAME), - fb_utils::exact_name(CS.RDB$CHARACTER_SET_NAME), + (COLL.RDB$BASE_COLLATION_NAME.NULL ? COLL.RDB$COLLATION_NAME : COLL.RDB$BASE_COLLATION_NAME), + QualifiedMetaString(CS.RDB$CHARACTER_SET_NAME, CS.RDB$SCHEMA_NAME), icuLessAttributes, newSpecificAttributes) && newSpecificAttributes != specificAttributes) // if nothing changed, we do nothing { - DbgRebuildIntl::out(" Recreate collation %s\n", collationName); + DbgRebuildIntl::out(" Recreate collation %s\n", collationName.toQuotedString().c_str()); MODIFY COLL USING if (newSpecificAttributes.isEmpty()) @@ -3968,15 +4028,16 @@ static bool create_collation(thread_db* tdbb, SSHORT phase, DeferredWork* work, switch (phase) { case 1: - setupSpecificCollationAttributes(tdbb, transaction, TTYPE_TO_CHARSET(work->dfw_id), - work->dfw_name.c_str(), false); + setupSpecificCollationAttributes(tdbb, transaction, + TTYPE_TO_CHARSET(work->dfw_id), work->getQualifiedName(), false); if (!(transaction->tra_flags & TRA_system) && // avoid run during database creation !INTL_defined_type(tdbb, work->dfw_id)) { - setupSpecificCollationAttributes(tdbb, transaction, TTYPE_TO_CHARSET(work->dfw_id), - work->dfw_name.c_str(), true); + setupSpecificCollationAttributes(tdbb, transaction, + TTYPE_TO_CHARSET(work->dfw_id), work->getQualifiedName(), true); } + break; } @@ -4010,62 +4071,86 @@ void DFW_reset_icu(thread_db* tdbb) transaction = TRA_start(tdbb, 0, 0); tdbb->setTransaction(transaction); - SortedArray indices; + SortedArray indices; ProtectRelations tables(tdbb, transaction); // Get list of affected indices & tables - const char* indSql = - "select ind.RDB$INDEX_NAME, rel.RDB$RELATION_ID," - " coalesce(coll.RDB$BASE_COLLATION_NAME, coll.RDB$COLLATION_NAME), cs.RDB$CHARACTER_SET_NAME, " - " coll.RDB$SPECIFIC_ATTRIBUTES " - "from RDB$INDICES ind " - "join RDB$RELATIONS rel on ind.RDB$RELATION_NAME = rel.RDB$RELATION_NAME " - "join RDB$INDEX_SEGMENTS seg on ind.RDB$INDEX_NAME = seg.RDB$INDEX_NAME " - "join RDB$RELATION_FIELDS rfl on rfl.RDB$RELATION_NAME = ind.RDB$RELATION_NAME " - " and rfl.RDB$FIELD_NAME = seg.RDB$FIELD_NAME " - "join RDB$FIELDS fld on rfl.RDB$FIELD_SOURCE = fld.RDB$FIELD_NAME " - "join RDB$COLLATIONS coll on fld.RDB$CHARACTER_SET_ID = coll.RDB$CHARACTER_SET_ID " - " and coalesce(rfl.RDB$COLLATION_ID, fld.RDB$COLLATION_ID) = coll.RDB$COLLATION_ID " - "join RDB$CHARACTER_SETS cs on coll.RDB$CHARACTER_SET_ID = cs.RDB$CHARACTER_SET_ID " - "where coll.RDB$SPECIFIC_ATTRIBUTES like '%COLL-VERSION=%' " - " and coalesce(ind.RDB$INDEX_INACTIVE, 0) = 0 " - " and coalesce(rel.RDB$RELATION_TYPE, 0) = 0 " // rel_persistent - "group by ind.RDB$INDEX_NAME, rel.RDB$RELATION_ID, coll.RDB$BASE_COLLATION_NAME, " - " coll.RDB$COLLATION_NAME, cs.RDB$CHARACTER_SET_NAME, coll.RDB$SPECIFIC_ATTRIBUTES"; - + const char* indSql = R""( + select ind.RDB$SCHEMA_NAME, + ind.RDB$INDEX_NAME, + rel.RDB$RELATION_ID, + rtrim(coalesce(coll.RDB$BASE_COLLATION_NAME, coll.RDB$COLLATION_NAME)), + cs.RDB$SCHEMA_NAME, + cs.RDB$CHARACTER_SET_NAME, + coll.RDB$SPECIFIC_ATTRIBUTES + from SYSTEM.RDB$INDICES ind + join SYSTEM.RDB$RELATIONS rel + on ind.RDB$SCHEMA_NAME = rel.RDB$SCHEMA_NAME and + ind.RDB$RELATION_NAME = rel.RDB$RELATION_NAME + join SYSTEM.RDB$INDEX_SEGMENTS seg + on ind.RDB$SCHEMA_NAME = seg.RDB$SCHEMA_NAME and + ind.RDB$INDEX_NAME = seg.RDB$INDEX_NAME + join SYSTEM.RDB$RELATION_FIELDS rfl + on rfl.RDB$SCHEMA_NAME = ind.RDB$SCHEMA_NAME and + rfl.RDB$RELATION_NAME = ind.RDB$RELATION_NAME and + rfl.RDB$FIELD_NAME = seg.RDB$FIELD_NAME + join SYSTEM.RDB$FIELDS fld + on rfl.RDB$FIELD_SOURCE_SCHEMA_NAME = fld.RDB$SCHEMA_NAME and + rfl.RDB$FIELD_SOURCE = fld.RDB$FIELD_NAME + join SYSTEM.RDB$COLLATIONS coll + on fld.RDB$CHARACTER_SET_ID = coll.RDB$CHARACTER_SET_ID and + coalesce(rfl.RDB$COLLATION_ID, fld.RDB$COLLATION_ID) = coll.RDB$COLLATION_ID + join SYSTEM.RDB$CHARACTER_SETS cs + on coll.RDB$CHARACTER_SET_ID = cs.RDB$CHARACTER_SET_ID + where coll.RDB$SPECIFIC_ATTRIBUTES like '%COLL-VERSION=%' and + coalesce(ind.RDB$INDEX_INACTIVE, 0) = 0 and + coalesce(rel.RDB$RELATION_TYPE, 0) = 0 -- rel_persistent + group by ind.RDB$SCHEMA_NAME, + ind.RDB$INDEX_NAME, + rel.RDB$RELATION_ID, + rtrim(coll.RDB$BASE_COLLATION_NAME), + coll.RDB$SCHEMA_NAME, + coll.RDB$COLLATION_NAME, + cs.RDB$SCHEMA_NAME, + cs.RDB$CHARACTER_SET_NAME, + coll.RDB$SPECIFIC_ATTRIBUTES + )""; { // scope AutoPreparedStatement ps(attachment->prepareStatement(tdbb, transaction, indSql)); AutoResultSet rs(ps->executeQuery(tdbb, transaction)); - while(rs->fetch(tdbb)) - { - MetaName t(rs->getMetaName(tdbb, 1)); - const MetaName collationName(rs->getMetaName(tdbb, 3)); - const MetaName charsetName(rs->getMetaName(tdbb, 4)); - const string specificAttributes(rs->getString(tdbb, 5)); - string icuLessAttributes = remove_icu_info_from_attributes(charsetName.c_str(), specificAttributes); - DbgRebuildIntl::out("check index %s SA:'%s' ILA:'%s'\n", - t.c_str(), specificAttributes.c_str(), icuLessAttributes.c_str()); + while (rs->fetch(tdbb)) + { + const QualifiedName indexName(rs->getMetaName(tdbb, 2), rs->getMetaName(tdbb, 1)); + const USHORT rel_id = rs->getInt(tdbb, 3); + const string collationName(rs->getMetaName(tdbb, 4)); + const QualifiedName charsetName(rs->getMetaName(tdbb, 6), rs->getMetaName(tdbb, 5)); + const string specificAttributes(rs->getString(tdbb, 7)); + + string icuLessAttributes = remove_icu_info_from_attributes(charsetName, specificAttributes); string newSpecificAttributes; - if (!IntlManager::setupCollationAttributes(collationName.c_str(), - charsetName.c_str(), icuLessAttributes, newSpecificAttributes)) + + DbgRebuildIntl::out("check index %s SA:'%s' ILA:'%s'\n", + indexName.toQuotedString().c_str(), specificAttributes.c_str(), icuLessAttributes.c_str()); + + if (!IntlManager::setupCollationAttributes(collationName, + charsetName, icuLessAttributes, newSpecificAttributes)) { DbgRebuildIntl::out("setupCollationAttributes failed for %s\n", collationName.c_str()); continue; } + DbgRebuildIntl::out("newSpecificAttributes '%s'\n", newSpecificAttributes.c_str()); if (newSpecificAttributes == specificAttributes) continue; DbgRebuildIntl::out("Add index\n"); - if (!indices.exist(t)) - indices.add(rs->getMetaName(tdbb, 1)); + if (!indices.exist(indexName)) + indices.add(indexName); - USHORT rel_id = rs->getInt(tdbb, 2); if (!tables.exists(rel_id)) { - jrd_rel* relation = MET_lookup_relation_id(tdbb, rel_id, false); - if (relation) + if (const auto relation = MET_lookup_relation_id(tdbb, rel_id, false)) tables.addRelation(relation); } } @@ -4078,32 +4163,33 @@ void DFW_reset_icu(thread_db* tdbb) // Change collation's attributes const char* collSql = - "select coll.RDB$COLLATION_NAME, coll.RDB$CHARACTER_SET_ID from RDB$COLLATIONS coll " + "select coll.RDB$SCHEMA_NAME, coll.RDB$COLLATION_NAME, coll.RDB$CHARACTER_SET_ID from RDB$COLLATIONS coll " "where coll.RDB$SPECIFIC_ATTRIBUTES like '%COLL-VERSION=%'"; { // scope AutoPreparedStatement ps(attachment->prepareStatement(tdbb, transaction, collSql)); AutoResultSet rs(ps->executeQuery(tdbb, transaction)); while(rs->fetch(tdbb)) { - MetaName collName(rs->getMetaName(tdbb, 1)); - const USHORT charSetId(rs->getSmallInt(tdbb, 2)); + QualifiedName collName(rs->getMetaName(tdbb, 2), rs->getMetaName(tdbb, 1)); + const USHORT charSetId(rs->getSmallInt(tdbb, 3)); - setupSpecificCollationAttributes(tdbb, transaction, charSetId, collName.c_str(), true); + setupSpecificCollationAttributes(tdbb, transaction, charSetId, collName, true); } } // Reactivate indices { // scope - for (MetaName* idx = indices.begin(); idx != indices.end(); ++idx) + for (const auto& idx : indices) { AutoRequest request; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) IDX IN RDB$INDICES - WITH IDX.RDB$INDEX_NAME EQ idx->c_str() + WITH IDX.RDB$SCHEMA_NAME EQ idx.schema.c_str() AND + IDX.RDB$INDEX_NAME EQ idx.object.c_str() { MODIFY IDX - DbgRebuildIntl::out("Re-activate index %s\n", idx->c_str()); + DbgRebuildIntl::out("Re-activate index %s\n", idx.toQuotedString().c_str()); IDX.RDB$INDEX_INACTIVE.NULL = FALSE; IDX.RDB$INDEX_INACTIVE = FALSE; END_MODIFY @@ -4149,7 +4235,7 @@ static bool delete_collation(thread_db* tdbb, SSHORT phase, DeferredWork* work, switch (phase) { case 1: - check_dependencies(tdbb, work->dfw_name.c_str(), NULL, NULL, obj_collation, transaction); + check_dependencies(tdbb, work->getQualifiedName(), NULL, obj_collation, transaction); return true; case 2: @@ -4183,7 +4269,7 @@ static bool delete_exception(thread_db* tdbb, SSHORT phase, DeferredWork* work, switch (phase) { case 1: - check_dependencies(tdbb, work->dfw_name.c_str(), NULL, NULL, obj_exception, transaction); + check_dependencies(tdbb, work->getQualifiedName(), NULL, obj_exception, transaction); break; } @@ -4216,7 +4302,7 @@ static bool set_generator(thread_db* tdbb, case 3: { - const SLONG id = MET_lookup_generator(tdbb, work->dfw_name); + const SLONG id = MET_lookup_generator(tdbb, work->getQualifiedName()); if (id >= 0) { fb_assert(id == work->dfw_id); @@ -4229,7 +4315,9 @@ static bool set_generator(thread_db* tdbb, } #ifdef DEV_BUILD else // This is a test only - status_exception::raise(Arg::Gds(isc_cant_modify_sysobj) << "generator" << work->dfw_name); + status_exception::raise(Arg::Gds(isc_cant_modify_sysobj) << + "generator" << + work->getQualifiedName().toQuotedString()); #endif } break; @@ -4255,12 +4343,11 @@ static bool delete_generator(thread_db* tdbb, SSHORT phase, DeferredWork* work, **************************************/ SET_TDBB(tdbb); - const char* gen_name = work->dfw_name.c_str(); switch (phase) { case 1: - check_dependencies(tdbb, gen_name, NULL, NULL, obj_generator, transaction); + check_dependencies(tdbb, work->getQualifiedName(), NULL, obj_generator, transaction); break; } @@ -4288,14 +4375,15 @@ static bool create_field(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ { case 1: { - const MetaName depName(work->dfw_name); + const auto depName(work->getQualifiedName()); AutoRequest handle; bid validation; validation.clear(); FOR(REQUEST_HANDLE handle) - FLD IN RDB$FIELDS WITH - FLD.RDB$FIELD_NAME EQ depName.c_str() + FLD IN RDB$FIELDS + WITH FLD.RDB$FIELD_NAME EQ depName.schema.c_str() AND + FLD.RDB$FIELD_NAME EQ depName.object.c_str() { if (!FLD.RDB$VALIDATION_BLR.NULL) validation = FLD.RDB$VALIDATION_BLR; @@ -4320,7 +4408,7 @@ static bool create_field(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ return true; case 4: // after scan_relation (phase 3) - check_computed_dependencies(tdbb, transaction, work->dfw_name); + check_computed_dependencies(tdbb, transaction, work->getQualifiedName()); break; } @@ -4358,13 +4446,13 @@ static bool delete_field(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ field_count = 0; FOR(REQUEST_HANDLE handle) - RFR IN RDB$RELATION_FIELDS CROSS - REL IN RDB$RELATIONS - OVER RDB$RELATION_NAME - WITH RFR.RDB$FIELD_SOURCE EQ work->dfw_name.c_str() + RFR IN RDB$RELATION_FIELDS + CROSS REL IN RDB$RELATIONS OVER RDB$SCHEMA_NAME, RDB$RELATION_NAME + WITH RFR.RDB$FIELD_SOURCE_SCHEMA_NAME EQ work->dfw_schema.c_str() AND + RFR.RDB$FIELD_SOURCE EQ work->dfw_name.c_str() { // If the rfr field is also being deleted, there's no dependency - if (!find_depend_in_dfw(tdbb, RFR.RDB$FIELD_NAME, obj_computed, REL.RDB$RELATION_ID, + if (!find_depend_in_dfw(tdbb, QualifiedName(RFR.RDB$FIELD_NAME), obj_computed, REL.RDB$RELATION_ID, transaction)) { field_count++; @@ -4376,18 +4464,18 @@ static bool delete_field(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ { ERR_post(Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_no_delete) << // Msg353: can not delete - Arg::Gds(isc_domain_name) << Arg::Str(work->dfw_name) << + Arg::Gds(isc_domain_name) << work->getQualifiedName().toQuotedString() << Arg::Gds(isc_dependency) << Arg::Num(field_count)); // Msg310: there are %ld dependencies } - check_dependencies(tdbb, work->dfw_name.c_str(), NULL, NULL, obj_field, transaction); + check_dependencies(tdbb, work->getQualifiedName(), NULL, obj_field, transaction); case 2: return true; case 3: - MET_delete_dependencies(tdbb, work->dfw_name, obj_computed, transaction); - MET_delete_dependencies(tdbb, work->dfw_name, obj_validation, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), obj_computed, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), obj_validation, transaction); break; } @@ -4415,7 +4503,7 @@ static bool modify_field(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ { case 1: { - const MetaName depName(work->dfw_name); + const auto depName(work->getQualifiedName()); AutoRequest handle; // If a domain is being changed to NOT NULL, schedule validation of involved relations. @@ -4424,17 +4512,23 @@ static bool modify_field(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ FOR(REQUEST_HANDLE handle) RFL IN RDB$RELATION_FIELDS CROSS REL IN RDB$RELATIONS - WITH REL.RDB$RELATION_NAME EQ RFL.RDB$RELATION_NAME AND - RFL.RDB$FIELD_SOURCE EQ depName.c_str() AND + WITH REL.RDB$SCHEMA_NAME EQ RFL.RDB$SCHEMA_NAME AND + REL.RDB$RELATION_NAME EQ RFL.RDB$RELATION_NAME AND + RFL.RDB$FIELD_SOURCE_SCHEMA_NAME EQ depName.schema.c_str() AND + RFL.RDB$FIELD_SOURCE EQ depName.object.c_str() AND (RFL.RDB$NULL_FLAG MISSING OR RFL.RDB$NULL_FLAG = FALSE) AND REL.RDB$VIEW_BLR MISSING - REDUCED TO RFL.RDB$RELATION_NAME, RFL.RDB$FIELD_ID + REDUCED TO RFL.RDB$SCHEMA_NAME, RFL.RDB$RELATION_NAME, RFL.RDB$FIELD_ID { - dsc desc; - desc.makeText(static_cast(strlen(RFL.RDB$RELATION_NAME)), CS_METADATA, + dsc schemaDesc; + schemaDesc.makeText(static_cast(strlen(RFL.RDB$SCHEMA_NAME)), CS_METADATA, + (UCHAR*) RFL.RDB$SCHEMA_NAME); + + dsc nameDesc; + nameDesc.makeText(static_cast(strlen(RFL.RDB$RELATION_NAME)), CS_METADATA, (UCHAR*) RFL.RDB$RELATION_NAME); - DeferredWork* work = DFW_post_work(transaction, dfw_check_not_null, &desc, 0); + DeferredWork* work = DFW_post_work(transaction, dfw_check_not_null, &nameDesc, &schemaDesc, 0); SortedArray& ids = DFW_get_ids(work); FB_SIZE_T pos; @@ -4450,8 +4544,9 @@ static bool modify_field(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ handle.reset(); FOR(REQUEST_HANDLE handle) - FLD IN RDB$FIELDS WITH - FLD.RDB$FIELD_NAME EQ depName.c_str() + FLD IN RDB$FIELDS + WITH FLD.RDB$SCHEMA_NAME EQ depName.schema.c_str() AND + FLD.RDB$FIELD_NAME EQ depName.object.c_str() { if (!FLD.RDB$VALIDATION_BLR.NULL) validation = FLD.RDB$VALIDATION_BLR; @@ -4461,8 +4556,8 @@ static bool modify_field(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ const DeferredWork* const arg = work->findArg(dfw_arg_new_name); // ASF: If there are procedures depending on the domain, it can't be renamed. - if (arg && depName != arg->dfw_name.c_str()) - check_dependencies(tdbb, depName.c_str(), NULL, NULL, obj_field, transaction); + if (arg && depName != arg->getQualifiedName()) + check_dependencies(tdbb, depName, NULL, obj_field, transaction); MET_delete_dependencies(tdbb, depName, obj_validation, transaction); @@ -4484,7 +4579,7 @@ static bool modify_field(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ return true; case 4: // after scan_relation (phase 3) - check_computed_dependencies(tdbb, transaction, work->dfw_name); + check_computed_dependencies(tdbb, transaction, work->getQualifiedName()); break; } @@ -4522,11 +4617,12 @@ static bool delete_global(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd { AutoRequest handle; FOR(REQUEST_HANDLE handle) - FLD IN RDB$FIELDS WITH - FLD.RDB$FIELD_NAME EQ work->dfw_name.c_str() AND - FLD.RDB$COMPUTED_BLR NOT MISSING + FLD IN RDB$FIELDS + WITH FLD.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + FLD.RDB$FIELD_NAME EQ work->dfw_name.c_str() AND + FLD.RDB$COMPUTED_BLR NOT MISSING { - MET_delete_dependencies(tdbb, work->dfw_name, obj_computed, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), obj_computed, transaction); } END_FOR } @@ -4617,7 +4713,7 @@ static bool delete_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ return false; case 1: - check_dependencies(tdbb, arg->dfw_name.c_str(), NULL, NULL, obj_index, transaction); + check_dependencies(tdbb, arg->getQualifiedName(), NULL, obj_index, transaction); return true; case 2: @@ -4662,7 +4758,7 @@ static bool delete_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ index->idl_count++; } - raiseObjectInUseError("INDEX", arg->dfw_name); + raiseObjectInUseError("INDEX", arg->getQualifiedName()); } index->idl_count++; } @@ -4679,8 +4775,8 @@ static bool delete_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ if (isTempIndex) return false; - MET_delete_dependencies(tdbb, arg->dfw_name, obj_index_expression, transaction); - MET_delete_dependencies(tdbb, arg->dfw_name, obj_index_condition, transaction); + MET_delete_dependencies(tdbb, arg->getQualifiedName(), obj_index_expression, transaction); + MET_delete_dependencies(tdbb, arg->getQualifiedName(), obj_index_condition, transaction); // if index was bound to deleted FK constraint // then work->dfw_args was set in VIO_erase @@ -4782,7 +4878,7 @@ static bool delete_parameter(thread_db* tdbb, SSHORT phase, DeferredWork*, jrd_t const DeferredWork* arg = work->dfw_args; fb_assert(arg && (arg->dfw_type == dfw_arg_proc_name)); - check_dependencies(tdbb, arg->dfw_name.c_str(), work->dfw_name.c_str(), + check_dependencies(tdbb, arg->dfw_name, work->dfw_name.c_str(), obj_procedure, transaction); } */ @@ -4843,11 +4939,12 @@ static bool delete_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, j request.reset(); view_count = 0; FOR(REQUEST_HANDLE request) - X IN RDB$VIEW_RELATIONS WITH - X.RDB$RELATION_NAME EQ work->dfw_name.c_str() + X IN RDB$VIEW_RELATIONS + WITH X.RDB$RELATION_SCHEMA_NAME EQ work->dfw_schema.c_str() AND + X.RDB$RELATION_NAME EQ work->dfw_name.c_str() { // If the view is also being deleted, there's no dependency - if (!find_depend_in_dfw(tdbb, X.RDB$VIEW_NAME, obj_view, 0, transaction)) + if (!find_depend_in_dfw(tdbb, QualifiedName(X.RDB$VIEW_NAME, X.RDB$SCHEMA_NAME), obj_view, 0, transaction)) { view_count++; } @@ -4858,7 +4955,7 @@ static bool delete_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, j { ERR_post(Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_no_delete) << // Msg353: can not delete - Arg::Gds(isc_table_name) << Arg::Str(work->dfw_name) << + Arg::Gds(isc_table_name) << work->getQualifiedName().toQuotedString() << Arg::Gds(isc_dependency) << Arg::Num(view_count)); // Msg310: there are %ld dependencies } @@ -4867,7 +4964,7 @@ static bool delete_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, j if (!relation) return false; - check_dependencies(tdbb, work->dfw_name.c_str(), NULL, NULL, + check_dependencies(tdbb, work->getQualifiedName(), NULL, (relation->isView() ? obj_view : obj_relation), transaction); return true; @@ -4976,7 +5073,7 @@ static bool delete_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, j // if this is a view (or even if we don't know), delete dependency lists if (relation->rel_view_rse || !(relation->rel_flags & REL_scanned)) { - MET_delete_dependencies(tdbb, work->dfw_name, obj_view, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), obj_view, transaction); } // Now that the data, pointer, and index pages are gone, @@ -5054,16 +5151,20 @@ static bool delete_rfr(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tr handle.reset(); field_count = 0; FOR(REQUEST_HANDLE handle) - REL IN RDB$RELATIONS CROSS - VR IN RDB$VIEW_RELATIONS OVER RDB$RELATION_NAME CROSS - VFLD IN RDB$RELATION_FIELDS WITH - REL.RDB$RELATION_ID EQ work->dfw_id AND - VFLD.RDB$VIEW_CONTEXT EQ VR.RDB$VIEW_CONTEXT AND - VFLD.RDB$RELATION_NAME EQ VR.RDB$VIEW_NAME AND - VFLD.RDB$BASE_FIELD EQ work->dfw_name.c_str() + REL IN RDB$RELATIONS + CROSS VR IN RDB$VIEW_RELATIONS + CROSS VFLD IN RDB$RELATION_FIELDS + WITH REL.RDB$RELATION_ID EQ work->dfw_id AND + VR.RDB$RELATION_SCHEMA_NAME EQ REL.RDB$SCHEMA_NAME AND + VR.RDB$RELATION_NAME EQ REL.RDB$RELATION_NAME AND + VFLD.RDB$VIEW_CONTEXT EQ VR.RDB$VIEW_CONTEXT AND + VFLD.RDB$SCHEMA_NAME EQ VR.RDB$SCHEMA_NAME AND + VFLD.RDB$RELATION_NAME EQ VR.RDB$VIEW_NAME AND + VFLD.RDB$BASE_FIELD EQ work->dfw_name.c_str() { // If the view is also being deleted, there's no dependency - if (!find_depend_in_dfw(tdbb, VR.RDB$VIEW_NAME, obj_view, 0, transaction)) + if (!find_depend_in_dfw(tdbb, QualifiedName(VR.RDB$VIEW_NAME, VR.RDB$SCHEMA_NAME), + obj_view, 0, transaction)) { f = VFLD.RDB$BASE_FIELD; field_count++; @@ -5085,7 +5186,7 @@ static bool delete_rfr(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tr if ( (relation = MET_lookup_relation_id(tdbb, work->dfw_id, false)) ) { - check_dependencies(tdbb, relation->rel_name.c_str(), work->dfw_name.c_str(), NULL, + check_dependencies(tdbb, relation->rel_name, work->dfw_name.c_str(), (relation->isView() ? obj_view : obj_relation), transaction); } @@ -5109,10 +5210,12 @@ static bool delete_rfr(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tr handle.reset(); FOR(REQUEST_HANDLE handle) - REL IN RDB$RELATIONS CROSS - RFLD IN RDB$RELATION_FIELDS OVER RDB$RELATION_NAME - WITH REL.RDB$RELATION_ID EQ work->dfw_id + REL IN RDB$RELATIONS + CROSS RFLD IN RDB$RELATION_FIELDS OVER RDB$SCHEMA_NAME, RDB$RELATION_NAME + WITH REL.RDB$RELATION_ID EQ work->dfw_id + { field_count++; + } END_FOR if (!field_count) @@ -5204,7 +5307,7 @@ static bool delete_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr case 3: // get rid of dependencies - MET_delete_dependencies(tdbb, work->dfw_name, obj_trigger, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), obj_trigger, transaction); return true; case 4: @@ -5222,13 +5325,13 @@ static bool delete_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr { MET_release_trigger(tdbb, &tdbb->getAttachment()->att_triggers[arg->dfw_id & ~TRIGGER_TYPE_DB], - work->dfw_name); + work->getQualifiedName()); } else if ((arg->dfw_id & TRIGGER_TYPE_MASK) == TRIGGER_TYPE_DDL) { MET_release_trigger(tdbb, &tdbb->getAttachment()->att_ddl_triggers, - work->dfw_name); + work->getQualifiedName()); } } } @@ -5241,7 +5344,7 @@ static bool delete_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr static bool find_depend_in_dfw(thread_db* tdbb, - TEXT* object_name, + const QualifiedName& object_name, USHORT dep_type, USHORT rel_id, jrd_tra* transaction) @@ -5261,8 +5364,8 @@ static bool find_depend_in_dfw(thread_db* tdbb, SET_TDBB(tdbb); Jrd::Attachment* attachment = tdbb->getAttachment(); - fb_utils::exact_name(object_name); enum dfw_t dfw_type; + switch (dep_type) { case obj_view: @@ -5307,7 +5410,8 @@ static bool find_depend_in_dfw(thread_db* tdbb, (work->dfw_type == dfw_modify_field && dfw_type == dfw_delete_global) || (work->dfw_type == dfw_modify_trigger && dfw_type == dfw_delete_trigger) || (work->dfw_type == dfw_modify_function && dfw_type == dfw_delete_function)) && - work->dfw_name == object_name && work->dfw_package.isEmpty() && + work->dfw_schema == object_name.schema && + work->dfw_name == object_name.object.c_str() && work->dfw_package.isEmpty() && (!rel_id || rel_id == work->dfw_id)) { if (work->dfw_type == dfw_modify_procedure || work->dfw_type == dfw_modify_function) @@ -5328,7 +5432,7 @@ static bool find_depend_in_dfw(thread_db* tdbb, { const DeferredWork* arg = work->dfw_args[i]; if (arg->dfw_type == dfw_arg_index_name && - arg->dfw_name == object_name) + QualifiedName(arg->dfw_name, work->dfw_schema) == object_name) { return true; } @@ -5347,13 +5451,16 @@ static bool find_depend_in_dfw(thread_db* tdbb, FOR(REQUEST_HANDLE request) FLD IN RDB$FIELDS CROSS - RFR IN RDB$RELATION_FIELDS CROSS - REL IN RDB$RELATIONS - WITH FLD.RDB$FIELD_NAME EQ RFR.RDB$FIELD_SOURCE - AND FLD.RDB$FIELD_NAME EQ object_name - AND REL.RDB$RELATION_NAME EQ RFR.RDB$RELATION_NAME + RFR IN RDB$RELATION_FIELDS CROSS + REL IN RDB$RELATIONS + WITH FLD.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + FLD.RDB$FIELD_NAME EQ object_name.object.c_str() AND + RFR.RDB$FIELD_SOURCE_SCHEMA_NAME EQ FLD.RDB$SCHEMA_NAME AND + RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND + REL.RDB$SCHEMA_NAME EQ RFR.RDB$SCHEMA_NAME AND + REL.RDB$RELATION_NAME EQ RFR.RDB$RELATION_NAME { - if (!find_depend_in_dfw(tdbb, RFR.RDB$FIELD_NAME, obj_computed, + if (!find_depend_in_dfw(tdbb, QualifiedName(RFR.RDB$FIELD_NAME), obj_computed, REL.RDB$RELATION_ID, transaction)) { return false; @@ -5370,8 +5477,9 @@ static bool find_depend_in_dfw(thread_db* tdbb, AutoRequest request; FOR(REQUEST_HANDLE request) - FLD IN RDB$FIELDS WITH - FLD.RDB$FIELD_NAME EQ object_name + FLD IN RDB$FIELDS + WITH FLD.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + FLD.RDB$FIELD_NAME EQ object_name.object.c_str() { if (!FLD.RDB$VALIDATION_BLR.NULL) return false; @@ -5460,12 +5568,13 @@ static void get_trigger_dependencies(DeferredWork* work, bool compile, jrd_tra* AutoCacheRequest handle(tdbb, irq_c_trigger, IRQ_REQUESTS); FOR(REQUEST_HANDLE handle) - X IN RDB$TRIGGERS WITH - X.RDB$TRIGGER_NAME EQ work->dfw_name.c_str() + X IN RDB$TRIGGERS + WITH X.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + X.RDB$TRIGGER_NAME EQ work->dfw_name.c_str() { blob_id = X.RDB$TRIGGER_BLR; type = (ISC_UINT64) X.RDB$TRIGGER_TYPE; - relation = MET_lookup_relation(tdbb, X.RDB$RELATION_NAME); + relation = MET_lookup_relation(tdbb, QualifiedName(X.RDB$RELATION_NAME, X.RDB$SCHEMA_NAME)); } END_FOR @@ -5484,7 +5593,7 @@ static void get_trigger_dependencies(DeferredWork* work, bool compile, jrd_tra* par_flags = 0; Jrd::ContextPoolHolder context(tdbb, new_pool); - const MetaName depName(work->dfw_name); + const auto depName(work->getQualifiedName()); MET_get_dependencies(tdbb, relation, NULL, 0, NULL, &blob_id, (compile ? &statement : NULL), NULL, depName, obj_trigger, par_flags, transaction); @@ -5609,7 +5718,7 @@ static Format* make_format(thread_db* tdbb, jrd_rel* relation, USHORT* version, delete format; ERR_post(Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_rec_size_err) << Arg::Num(offset) << - Arg::Gds(isc_table_name) << Arg::Str(relation->rel_name)); + Arg::Gds(isc_table_name) << relation->rel_name.toQuotedString()); // Msg361: new record size of %ld bytes is too big } @@ -5750,7 +5859,9 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ // all required dirty reads are performed in metadata cache. AP-2008. FOR(REQUEST_HANDLE request_fmt1 TRANSACTION_HANDLE transaction) - REL IN RDB$RELATIONS WITH REL.RDB$RELATION_NAME EQ work->dfw_name.c_str() + REL IN RDB$RELATIONS + WITH REL.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + REL.RDB$RELATION_NAME EQ work->dfw_name.c_str() { relation = MET_lookup_relation_id(tdbb, REL.RDB$RELATION_ID, false); if (!relation) @@ -5763,12 +5874,12 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ if (REL.RDB$VIEW_BLR.NULL) { if (REL.RDB$FORMAT == MAX_TABLE_VERSIONS) - raiseTooManyVersionsError(obj_relation, work->dfw_name); + raiseTooManyVersionsError(obj_relation, work->getQualifiedName()); } else { if (REL.RDB$FORMAT == MAX_VIEW_VERSIONS) - raiseTooManyVersionsError(obj_view, work->dfw_name); + raiseTooManyVersionsError(obj_view, work->getQualifiedName()); } MODIFY REL USING @@ -5777,9 +5888,11 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ FOR(REQUEST_HANDLE request_fmtx TRANSACTION_HANDLE transaction) RFR IN RDB$RELATION_FIELDS CROSS - FLD IN RDB$FIELDS WITH - RFR.RDB$RELATION_NAME EQ work->dfw_name.c_str() AND - RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME + FLD IN RDB$FIELDS + WITH RFR.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + RFR.RDB$RELATION_NAME EQ work->dfw_name.c_str() AND + FLD.RDB$SCHEMA_NAME EQ RFR.RDB$FIELD_SOURCE_SCHEMA_NAME AND + FLD.RDB$FIELD_NAME EQ RFR.RDB$FIELD_SOURCE SORTED BY RFR.RDB$FIELD_POSITION { // Update RFR to reflect new fields id @@ -5823,12 +5936,16 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ if (notNull) { - dsc desc; - desc.makeText(static_cast(strlen(REL.RDB$RELATION_NAME)), - CS_METADATA, (UCHAR*) REL.RDB$RELATION_NAME); + dsc schemaDesc; + schemaDesc.makeText(static_cast(strlen(REL.RDB$SCHEMA_NAME)), CS_METADATA, + (UCHAR*) REL.RDB$SCHEMA_NAME); + + dsc nameDesc; + nameDesc.makeText(static_cast(strlen(REL.RDB$RELATION_NAME)), CS_METADATA, + (UCHAR*) REL.RDB$RELATION_NAME); DeferredWork* work = DFW_post_work(transaction, - dfw_check_not_null, &desc, 0); + dfw_check_not_null, &nameDesc, &schemaDesc, 0); SortedArray& ids = DFW_get_ids(work); FB_SIZE_T pos; @@ -5852,9 +5969,10 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ { AutoRequest temp; RFR.RDB$UPDATE_FLAG = 0; - FOR(REQUEST_HANDLE temp) X IN RDB$TRIGGERS WITH - X.RDB$RELATION_NAME EQ work->dfw_name.c_str() AND - X.RDB$TRIGGER_TYPE EQ 1 + FOR(REQUEST_HANDLE temp) X IN RDB$TRIGGERS + WITH X.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + X.RDB$RELATION_NAME EQ work->dfw_name.c_str() AND + X.RDB$TRIGGER_TYPE EQ 1 { RFR.RDB$UPDATE_FLAG = 1; } @@ -5945,7 +6063,7 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ DPM_delete_relation(tdbb, relation); ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_random) << Arg::Str(work->dfw_name)); + Arg::Gds(isc_random) << work->getQualifiedName().toQuotedString()); } // Make sure the text type specified is implemented @@ -5955,7 +6073,7 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ DPM_delete_relation(tdbb, relation); ERR_post_nothrow(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_random) << Arg::Str(work->dfw_name)); + Arg::Gds(isc_random) << work->getQualifiedName().toQuotedString()); INTL_texttype_lookup(tdbb, (DTYPE_IS_TEXT(tfb->tfb_desc.dsc_dtype) ? tfb->tfb_desc.dsc_ttype() : tfb->tfb_desc.dsc_blob_ttype())); // should punt @@ -5973,7 +6091,7 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ try { ValueExprNode* defaultNode = static_cast(MET_parse_blob( - tdbb, relation, defaultValue, NULL, &defaultStatement, false, false)); + tdbb, &work->dfw_schema, relation, defaultValue, NULL, &defaultStatement, false, false)); Request* const defaultRequest = defaultStatement->findRequest(tdbb); @@ -6077,7 +6195,7 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ DPM_delete_relation(tdbb, relation); ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_table_name) << Arg::Str(work->dfw_name) << + Arg::Gds(isc_table_name) << work->getQualifiedName().toQuotedString() << Arg::Gds(isc_must_have_phys_field)); } @@ -6099,8 +6217,11 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ AutoRequest handle; FOR(REQUEST_HANDLE handle) Z IN RDB$VIEW_RELATIONS - CROSS R IN RDB$RELATIONS OVER RDB$RELATION_NAME - WITH Z.RDB$VIEW_NAME = work->dfw_name.c_str() + CROSS R IN RDB$RELATIONS + WITH Z.RDB$SCHEMA_NAME = work->dfw_schema.c_str() AND + Z.RDB$VIEW_NAME = work->dfw_name.c_str() AND + R.RDB$SCHEMA_NAME EQ Z.RDB$RELATION_SCHEMA_NAME AND + R.RDB$RELATION_NAME EQ Z.RDB$RELATION_NAME { REL.RDB$DBKEY_LENGTH += R.RDB$DBKEY_LENGTH; } @@ -6124,14 +6245,14 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ // and setting a flag for MET_scan_relation to find the new ones if (!null_view) - MET_delete_dependencies(tdbb, work->dfw_name, obj_view, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), obj_view, transaction); { // begin scope const DeferredWork* arg = work->findArg(dfw_arg_force_computed); if (arg) { computed_field = true; - MET_delete_dependencies(tdbb, arg->dfw_name, obj_computed, transaction); + MET_delete_dependencies(tdbb, arg->getQualifiedName(), obj_computed, transaction); } } // end scope @@ -6153,7 +6274,7 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ } relation->rel_flags &= ~REL_scanned; - DFW_post_work(transaction, dfw_scan_relation, NULL, relation->rel_id); + DFW_post_work(transaction, dfw_scan_relation, nullptr, nullptr, relation->rel_id); // signal others about new format presence LCK_lock(tdbb, relation->rel_rescan_lock, LCK_EX, LCK_WAIT); @@ -6194,7 +6315,7 @@ static bool modify_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr bool compile = !work->findArg(dfw_arg_check_blr); // get rid of old dependencies, bring in the new - MET_delete_dependencies(tdbb, work->dfw_name, obj_trigger, transaction); + MET_delete_dependencies(tdbb, work->getQualifiedName(), obj_trigger, transaction); get_trigger_dependencies(work, compile, transaction); } return true; @@ -6226,7 +6347,7 @@ static bool modify_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr const DeferredWork* arg = work->findArg(dfw_arg_check_blr); if (arg) { - const MetaName relation_name(arg->dfw_name); + const auto relation_name(arg->getQualifiedName()); SSHORT valid_blr = FALSE; try @@ -6249,7 +6370,7 @@ static bool modify_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr { Jrd::ContextPoolHolder context(tdbb, new_pool); - MET_load_trigger(tdbb, relation, work->dfw_name, triggers); + MET_load_trigger(tdbb, relation, work->getQualifiedName(), triggers); for (int i = 0; i < TRIGGER_MAX; ++i) { @@ -6280,8 +6401,10 @@ static bool modify_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr AutoCacheRequest request(tdbb, irq_trg_validate, IRQ_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - TRG IN RDB$TRIGGERS WITH - TRG.RDB$TRIGGER_NAME EQ work->dfw_name.c_str() AND TRG.RDB$TRIGGER_BLR NOT MISSING + TRG IN RDB$TRIGGERS + WITH TRG.RDB$SCHEMA_NAME EQ work->dfw_schema.c_str() AND + TRG.RDB$TRIGGER_NAME EQ work->dfw_name.c_str() AND + TRG.RDB$TRIGGER_BLR NOT MISSING { MODIFY TRG USING TRG.RDB$VALID_BLR = valid_blr; @@ -6539,12 +6662,16 @@ static blb* setup_triggers(thread_db* tdbb, jrd_rel* relation, bool null_view, FOR (REQUEST_HANDLE request_fmtx) TRG IN RDB$TRIGGERS - WITH TRG.RDB$RELATION_NAME = relation->rel_name.c_str() - AND TRG.RDB$SYSTEM_FLAG = 1 + WITH TRG.RDB$SCHEMA_NAME = relation->rel_name.schema.c_str() AND + TRG.RDB$RELATION_NAME = relation->rel_name.object.c_str() AND + TRG.RDB$SYSTEM_FLAG = 1 SORTED BY TRG.RDB$TRIGGER_SEQUENCE { if (!TRG.RDB$TRIGGER_INACTIVE) - setup_trigger_details(tdbb, relation, blob, triggers, TRG.RDB$TRIGGER_NAME, null_view); + { + setup_trigger_details(tdbb, relation, blob, triggers, + QualifiedName(TRG.RDB$TRIGGER_NAME, TRG.RDB$SCHEMA_NAME), null_view); + } } END_FOR @@ -6554,20 +6681,26 @@ static blb* setup_triggers(thread_db* tdbb, jrd_rel* relation, bool null_view, FOR (REQUEST_HANDLE request_fmtx) TRG IN RDB$TRIGGERS - WITH TRG.RDB$RELATION_NAME EQ relation->rel_name.c_str() - AND TRG.RDB$SYSTEM_FLAG = 0 - AND (NOT ANY - CHK IN RDB$CHECK_CONSTRAINTS CROSS - RCN IN RDB$RELATION_CONSTRAINTS - WITH TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME - AND CHK.RDB$CONSTRAINT_NAME EQ RCN.RDB$CONSTRAINT_NAME - AND (RCN.RDB$CONSTRAINT_TYPE EQ CHECK_CNSTRT - OR RCN.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY) + WITH TRG.RDB$SCHEMA_NAME EQ relation->rel_name.schema.c_str() AND + TRG.RDB$RELATION_NAME EQ relation->rel_name.object.c_str() AND + TRG.RDB$SYSTEM_FLAG = 0 AND + (NOT ANY + CHK IN RDB$CHECK_CONSTRAINTS + CROSS RCN IN RDB$RELATION_CONSTRAINTS + WITH TRG.RDB$SCHEMA_NAME EQ CHK.RDB$SCHEMA_NAME AND + TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME AND + CHK.RDB$CONSTRAINT_NAME EQ RCN.RDB$CONSTRAINT_NAME AND + CHK.RDB$SCHEMA_NAME EQ RCN.RDB$SCHEMA_NAME AND + (RCN.RDB$CONSTRAINT_TYPE EQ CHECK_CNSTRT OR + RCN.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY) ) SORTED BY TRG.RDB$TRIGGER_SEQUENCE { if (!TRG.RDB$TRIGGER_INACTIVE) - setup_trigger_details(tdbb, relation, blob, triggers, TRG.RDB$TRIGGER_NAME, null_view); + { + setup_trigger_details(tdbb, relation, blob, triggers, + QualifiedName(TRG.RDB$TRIGGER_NAME, TRG.RDB$SCHEMA_NAME), null_view); + } } END_FOR @@ -6579,21 +6712,28 @@ static blb* setup_triggers(thread_db* tdbb, jrd_rel* relation, bool null_view, FOR (REQUEST_HANDLE request_fmtx) TRG IN RDB$TRIGGERS - WITH TRG.RDB$RELATION_NAME = relation->rel_name.c_str() - AND (TRG.RDB$SYSTEM_FLAG BT fb_sysflag_check_constraint AND fb_sysflag_view_check - OR (TRG.RDB$SYSTEM_FLAG = 0 AND ANY - CHK IN RDB$CHECK_CONSTRAINTS CROSS - RCN IN RDB$RELATION_CONSTRAINTS - WITH TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME - AND CHK.RDB$CONSTRAINT_NAME EQ RCN.RDB$CONSTRAINT_NAME - AND (RCN.RDB$CONSTRAINT_TYPE EQ CHECK_CNSTRT - OR RCN.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY) - ) - ) + WITH TRG.RDB$SCHEMA_NAME EQ relation->rel_name.schema.c_str() AND + TRG.RDB$RELATION_NAME = relation->rel_name.object.c_str() AND + (TRG.RDB$SYSTEM_FLAG BT fb_sysflag_check_constraint AND fb_sysflag_view_check OR + (TRG.RDB$SYSTEM_FLAG = 0 AND + ANY + CHK IN RDB$CHECK_CONSTRAINTS + CROSS RCN IN RDB$RELATION_CONSTRAINTS + WITH TRG.RDB$SCHEMA_NAME EQ CHK.RDB$SCHEMA_NAME AND + TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME AND + CHK.RDB$CONSTRAINT_NAME EQ RCN.RDB$CONSTRAINT_NAME AND + CHK.RDB$SCHEMA_NAME EQ RCN.RDB$SCHEMA_NAME AND + (RCN.RDB$CONSTRAINT_TYPE EQ CHECK_CNSTRT OR + RCN.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY) + ) + ) SORTED BY TRG.RDB$TRIGGER_SEQUENCE { if (!TRG.RDB$TRIGGER_INACTIVE) - setup_trigger_details(tdbb, relation, blob, triggers, TRG.RDB$TRIGGER_NAME, null_view); + { + setup_trigger_details(tdbb, relation, blob, triggers, + QualifiedName(TRG.RDB$TRIGGER_NAME, TRG.RDB$SCHEMA_NAME), null_view); + } } END_FOR @@ -6605,7 +6745,7 @@ static void setup_trigger_details(thread_db* tdbb, jrd_rel* relation, blb* blob, TrigVector** triggers, - const TEXT* trigger_name, + const QualifiedName& trigger_name, bool null_view) { /************************************** @@ -6625,7 +6765,7 @@ static void setup_trigger_details(thread_db* tdbb, **************************************/ put_summary_record(tdbb, blob, RSR_trigger_name, - (const UCHAR*) trigger_name, fb_utils::name_length(trigger_name)); + (const UCHAR*) trigger_name.object.c_str(), fb_utils::name_length(trigger_name.object.c_str())); if (!null_view) { MET_load_trigger(tdbb, relation, trigger_name, triggers); diff --git a/src/jrd/dfw_proto.h b/src/jrd/dfw_proto.h index 1681e9d727..d424e9a035 100644 --- a/src/jrd/dfw_proto.h +++ b/src/jrd/dfw_proto.h @@ -31,19 +31,21 @@ namespace Jrd enum dfw_t; } -USHORT DFW_assign_index_type(Jrd::thread_db*, const Jrd::MetaName&, SSHORT, SSHORT); +USHORT DFW_assign_index_type(Jrd::thread_db*, const Jrd::QualifiedName&, SSHORT, SSHORT); void DFW_delete_deferred(Jrd::jrd_tra*, SavNumber); Firebird::SortedArray& DFW_get_ids(Jrd::DeferredWork* work); void DFW_merge_work(Jrd::jrd_tra*, SavNumber, SavNumber); void DFW_perform_work(Jrd::thread_db*, Jrd::jrd_tra*); void DFW_perform_post_commit_work(Jrd::jrd_tra*); -Jrd::DeferredWork* DFW_post_work(Jrd::jrd_tra*, Jrd::dfw_t, const dsc*, USHORT, - const Jrd::MetaName& package = NULL); -Jrd::DeferredWork* DFW_post_work(Jrd::jrd_tra*, Jrd::dfw_t, const Firebird::string&, USHORT, - const Jrd::MetaName& package = NULL); -Jrd::DeferredWork* DFW_post_work_arg(Jrd::jrd_tra*, Jrd::DeferredWork*, const dsc*, USHORT); -Jrd::DeferredWork* DFW_post_work_arg(Jrd::jrd_tra*, Jrd::DeferredWork*, const dsc*, USHORT, Jrd::dfw_t); -void DFW_update_index(const TEXT*, USHORT, const Jrd::SelectivityList&, Jrd::jrd_tra*); +Jrd::DeferredWork* DFW_post_work(Jrd::jrd_tra*, Jrd::dfw_t, const dsc* nameDesc, const dsc* schemaDesc, USHORT, + const Jrd::MetaName& package = {}); +Jrd::DeferredWork* DFW_post_work(Jrd::jrd_tra*, Jrd::dfw_t, const Firebird::string&, const Jrd::MetaName& schema, + USHORT, const Jrd::MetaName& package = {}); +Jrd::DeferredWork* DFW_post_work_arg(Jrd::jrd_tra*, Jrd::DeferredWork*, const dsc* nameDesc, const dsc* schemaDesc, + USHORT); +Jrd::DeferredWork* DFW_post_work_arg(Jrd::jrd_tra*, Jrd::DeferredWork*, const dsc* nameDesc, const dsc* schemaDesc, + USHORT, Jrd::dfw_t); +void DFW_update_index(const Jrd::QualifiedName&, USHORT, const Jrd::SelectivityList&, Jrd::jrd_tra*); void DFW_reset_icu(Jrd::thread_db*); #endif // JRD_DFW_PROTO_H diff --git a/src/jrd/drq.h b/src/jrd/drq.h index d3b3c5a7fb..1f8e344d3b 100644 --- a/src/jrd/drq.h +++ b/src/jrd/drq.h @@ -69,7 +69,6 @@ enum drq_type_t drq_s_lfields, // store local fields drq_s_gfields2, // store global fields drq_s_rels, // store relations - drq_l_rel_name, // lookup relation name drq_l_view_rels, // lookup relations in view drq_s_usr_prvs, // store user privileges drq_s_sql_gfld, // store sql fields @@ -98,11 +97,8 @@ enum drq_type_t drq_l_grant1, // lookup grant drq_s_grant, // store grant drq_l_fld_src2, // lookup a field source - drq_m_database, // modify database drq_m_index, // modify index drq_m_set_statistics, // modify index (set statistics) - drq_e_grant1, // erase grant - drq_e_grant2, // erase grant drq_s_indices, // store indices drq_l_lfield, // lookup local field drq_s_idx_segs, // store index segments @@ -110,7 +106,6 @@ enum drq_type_t drq_l_primary, // lookup a primary something drq_e_trg_msgs2, // erase trigger messages drq_e_trigger2, // erase trigger - drq_l_prc_name, // lookup procedure name drq_s_xcp, // store an exception drq_m_xcp, // modify an exception drq_e_trg_prv, // erase trigger's privileges @@ -164,14 +159,11 @@ enum drq_type_t drq_l_arg_coll, // lookup function argument collation drq_map_sto, // store login mapping drq_map_mod, // modify/erase login mapping - drq_l_idx_name, // lookup index name drq_l_collation, // DSQL/DdlNodes: lookup collation drq_m_charset, // DSQL/DdlNodes: modify character set drq_g_nxt_gen_id, // generate next generator id drq_g_nxt_prc_id, // generate next procedure id drq_g_nxt_xcp_id, // generate next exception id - drq_l_xcp_name, // lookup exception name - drq_l_gen_name, // lookup generator name drq_e_grant3, // revoke all on all drq_s_funcs2, // store functions (CreateAlterFunctionNode) drq_s_func_args2, // store function arguments (CreateAlterFunctionNode) @@ -208,7 +200,6 @@ enum drq_type_t drq_e_pkg_prv, // erase package privileges drq_s2_difference, // Store backup difference file, DYN_mod's change_backup_mode drq_l_relation, // lookup relation before erase - drq_l_fun_name, // lookup function name drq_g_nxt_fun_id, // lookup next function ID drq_e_arg_gfld, // erase argument's global field drq_e_fun_prv, // erase function privileges @@ -249,10 +240,6 @@ 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_l_trg_name, // lookup trigger name - drq_l_fld_name, // lookup field name - drq_l_coll_name, // lookup collation name - drq_l_pkg_name, // lookup package name drq_l_rel_con, // lookup relation constraint drq_l_rel_fld_name, // lookup relation field name diff --git a/src/jrd/dyn.h b/src/jrd/dyn.h index 50b4040ed2..87324bd1b7 100644 --- a/src/jrd/dyn.h +++ b/src/jrd/dyn.h @@ -26,6 +26,7 @@ #include "../common/classes/MsgPrint.h" #include "../jrd/MetaName.h" +#include "../jrd/QualifiedName.h" #include "../common/classes/array.h" #include "../common/classes/fb_string.h" #include "../common/dsc.h" @@ -33,6 +34,7 @@ const char* const ALL_PRIVILEGES = "SIUDR"; // all applicable grant/revoke privileges const char* const EXEC_PRIVILEGES = "X"; // execute privilege const char* const USAGE_PRIVILEGES = "G"; // usage privilege +const char* const ALL_DDL_PRIVILEGES = "CLO"; const int DYN_MSG_FAC = 8; @@ -53,9 +55,9 @@ public: SSHORT dyn_collation; SSHORT dyn_charset; SSHORT dyn_sub_type; - MetaName dyn_fld_source; - MetaName dyn_rel_name; - MetaName dyn_fld_name; + QualifiedName dyn_fld_source; + QualifiedName dyn_rel_name; + QualifiedName dyn_fld_name; USHORT dyn_charbytelen; // Used to check modify operations on string types. const UCHAR* dyn_default_src; const UCHAR* dyn_default_val; diff --git a/src/jrd/dyn_ut_proto.h b/src/jrd/dyn_ut_proto.h index 16abba7e43..08d11d5326 100644 --- a/src/jrd/dyn_ut_proto.h +++ b/src/jrd/dyn_ut_proto.h @@ -26,21 +26,20 @@ #define JRD_DYN_UT_PROTO_H void DYN_UTIL_store_check_constraints(Jrd::thread_db*, Jrd::jrd_tra*, - const Jrd::MetaName&, const Jrd::MetaName&); + const Jrd::QualifiedName&, const Jrd::MetaName&); bool DYN_UTIL_find_field_source(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction, - const Jrd::MetaName& view_name, USHORT context, const TEXT* local_name, - TEXT* output_field_name); -void DYN_UTIL_generate_generator_name(Jrd::thread_db*, Jrd::MetaName&); -void DYN_UTIL_generate_trigger_name(Jrd::thread_db*, Jrd::jrd_tra*, Jrd::MetaName&); -void DYN_UTIL_generate_index_name(Jrd::thread_db*, Jrd::jrd_tra*, Jrd::MetaName&, UCHAR); -void DYN_UTIL_generate_field_position(Jrd::thread_db*, const Jrd::MetaName&, SLONG*); -void DYN_UTIL_generate_field_name(Jrd::thread_db*, TEXT*); -void DYN_UTIL_generate_field_name(Jrd::thread_db*, Jrd::MetaName&); -void DYN_UTIL_generate_constraint_name(Jrd::thread_db*, Jrd::MetaName&); + const Jrd::QualifiedName& view_name, USHORT context, const TEXT* local_name, + TEXT* output_field_schema_name, TEXT* output_field_name); +void DYN_UTIL_generate_generator_name(Jrd::thread_db*, Jrd::QualifiedName&); +void DYN_UTIL_generate_trigger_name(Jrd::thread_db*, Jrd::jrd_tra*, Jrd::QualifiedName&); +void DYN_UTIL_generate_index_name(Jrd::thread_db*, Jrd::jrd_tra*, Jrd::QualifiedName&, UCHAR); +void DYN_UTIL_generate_field_position(Jrd::thread_db*, const Jrd::QualifiedName&, SLONG*); +void DYN_UTIL_generate_field_name(Jrd::thread_db*, Jrd::QualifiedName&); +void DYN_UTIL_generate_constraint_name(Jrd::thread_db*, Jrd::QualifiedName&); bool DYN_UTIL_check_unique_name_nothrow(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction, - const Jrd::MetaName& object_name, int object_type, USHORT* errorCode = nullptr); + const Jrd::QualifiedName& object_name, int object_type, USHORT* errorCode = nullptr); void DYN_UTIL_check_unique_name(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction, - const Jrd::MetaName& object_name, int object_type); + const Jrd::QualifiedName& object_name, int object_type); SINT64 DYN_UTIL_gen_unique_id(Jrd::thread_db*, SSHORT, const char*); #endif // JRD_DYN_UT_PROTO_H diff --git a/src/jrd/dyn_util.epp b/src/jrd/dyn_util.epp index 4aa1d2569e..422fa28ff2 100644 --- a/src/jrd/dyn_util.epp +++ b/src/jrd/dyn_util.epp @@ -69,18 +69,21 @@ static const UCHAR gen_id_blr1[] = blr_send, 0, blr_begin, blr_assignment, - blr_gen_id + blr_gen_id3, + 6, 'S', 'Y', 'S', 'T', 'E', 'M' // SYSTEM_SCHEMA }; static const UCHAR gen_id_blr2[] = { + 1, blr_literal, blr_long, 0, 1, 0, 0, 0, - blr_parameter, 0, 0, 0, blr_end, blr_end, blr_end, blr_eoc + blr_parameter, 0, 0, 0, + blr_end, blr_end, blr_end, blr_eoc }; // Check if an object already exists. If yes, return false. bool DYN_UTIL_check_unique_name_nothrow(thread_db* tdbb, jrd_tra* transaction, - const MetaName& object_name, int object_type, USHORT* errorCode) + const QualifiedName& object_name, int object_type, USHORT* errorCode) { SET_TDBB(tdbb); @@ -88,137 +91,197 @@ bool DYN_UTIL_check_unique_name_nothrow(thread_db* tdbb, jrd_tra* transaction, errorCode = errorCode ? errorCode : &tempErrorCode; *errorCode = 0; - AutoCacheRequest request; + AutoCacheRequest requestHandle; switch (object_type) { case obj_relation: case obj_procedure: - request.reset(tdbb, drq_l_rel_name, DYN_REQUESTS); + { + static const CachedRequestId relationHandleId; + requestHandle.reset(tdbb, relationHandleId); - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - EREL IN RDB$RELATIONS WITH EREL.RDB$RELATION_NAME EQ object_name.c_str() + FOR(REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + EREL IN RDB$RELATIONS + WITH EREL.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + EREL.RDB$RELATION_NAME EQ object_name.object.c_str() { - *errorCode = 132; + *errorCode = 132; // isc_dyn_dup_table } END_FOR if (!*errorCode) { - request.reset(tdbb, drq_l_prc_name, DYN_REQUESTS); + static const CachedRequestId procedureHandleId; + requestHandle.reset(tdbb, procedureHandleId); - FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) EPRC IN RDB$PROCEDURES - WITH EPRC.RDB$PROCEDURE_NAME EQ object_name.c_str() AND + WITH EPRC.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + EPRC.RDB$PROCEDURE_NAME EQ object_name.object.c_str() AND EPRC.RDB$PACKAGE_NAME MISSING { - *errorCode = 135; + *errorCode = 135; // isc_dyn_dup_procedure } END_FOR } break; + } case obj_index: - request.reset(tdbb, drq_l_idx_name, DYN_REQUESTS); + { + static const CachedRequestId indexHandleId; + requestHandle.reset(tdbb, indexHandleId); - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - EIDX IN RDB$INDICES WITH EIDX.RDB$INDEX_NAME EQ object_name.c_str() + FOR(REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + EIDX IN RDB$INDICES + WITH EIDX.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + EIDX.RDB$INDEX_NAME EQ object_name.object.c_str() { - *errorCode = 251; + *errorCode = 251; // isc_dyn_dup_index } END_FOR break; + } case obj_exception: - request.reset(tdbb, drq_l_xcp_name, DYN_REQUESTS); + { + static const CachedRequestId exceptionHandleId; + requestHandle.reset(tdbb, exceptionHandleId); - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - EXCP IN RDB$EXCEPTIONS WITH EXCP.RDB$EXCEPTION_NAME EQ object_name.c_str() + FOR(REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + EXCP IN RDB$EXCEPTIONS + WITH EXCP.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + EXCP.RDB$EXCEPTION_NAME EQ object_name.object.c_str() { - *errorCode = 253; + *errorCode = 253; // isc_dyn_dup_exception } END_FOR break; + } case obj_generator: - request.reset(tdbb, drq_l_gen_name, DYN_REQUESTS); + { + static const CachedRequestId generatorHandleId; + requestHandle.reset(tdbb, generatorHandleId); - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - EGEN IN RDB$GENERATORS WITH EGEN.RDB$GENERATOR_NAME EQ object_name.c_str() + FOR(REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + EGEN IN RDB$GENERATORS + WITH EGEN.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + EGEN.RDB$GENERATOR_NAME EQ object_name.object.c_str() { - *errorCode = 254; + *errorCode = 254; // isc_dyn_dup_generator } END_FOR break; + } case obj_udf: - request.reset(tdbb, drq_l_fun_name, DYN_REQUESTS); + { + static const CachedRequestId udfHandleId; + requestHandle.reset(tdbb, udfHandleId); - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + FOR(REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) EFUN IN RDB$FUNCTIONS - WITH EFUN.RDB$FUNCTION_NAME EQ object_name.c_str() AND + WITH EFUN.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + EFUN.RDB$FUNCTION_NAME EQ object_name.object.c_str() AND EFUN.RDB$PACKAGE_NAME MISSING { - *errorCode = 268; + *errorCode = 268; // isc_dyn_dup_function } END_FOR break; + } case obj_trigger: - request.reset(tdbb, drq_l_trg_name, DYN_REQUESTS); + { + static const CachedRequestId triggerHandleId; + requestHandle.reset(tdbb, triggerHandleId); - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + FOR(REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) TRG IN RDB$TRIGGERS - WITH TRG.RDB$TRIGGER_NAME EQ object_name.c_str() + WITH TRG.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + TRG.RDB$TRIGGER_NAME EQ object_name.object.c_str() { - *errorCode = 310; + *errorCode = 310; // isc_dyn_dup_trigger } END_FOR break; + } case obj_field: - request.reset(tdbb, drq_l_fld_name, DYN_REQUESTS); + { + static const CachedRequestId fieldHandleId; + requestHandle.reset(tdbb, fieldHandleId); - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + FOR(REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) FLD IN RDB$FIELDS - WITH FLD.RDB$FIELD_NAME EQ object_name.c_str() + WITH FLD.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + FLD.RDB$FIELD_NAME EQ object_name.object.c_str() { - *errorCode = 311; + *errorCode = 311; // isc_dyn_dup_domain } END_FOR break; + } case obj_collation: - request.reset(tdbb, drq_l_coll_name, DYN_REQUESTS); + { + static const CachedRequestId collationHandleId; + requestHandle.reset(tdbb, collationHandleId); - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + FOR(REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) COLL IN RDB$COLLATIONS - WITH COLL.RDB$COLLATION_NAME EQ object_name.c_str() + WITH COLL.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + COLL.RDB$COLLATION_NAME EQ object_name.object.c_str() { - *errorCode = 312; + *errorCode = 312; // isc_dyn_dup_collation } END_FOR break; + } case obj_package_header: - request.reset(tdbb, drq_l_pkg_name, DYN_REQUESTS); + { + static const CachedRequestId packageHandleId; + requestHandle.reset(tdbb, packageHandleId); - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + FOR(REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PKG IN RDB$PACKAGES - WITH PKG.RDB$PACKAGE_NAME EQ object_name.c_str() + WITH PKG.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + PKG.RDB$PACKAGE_NAME EQ object_name.object.c_str() { - *errorCode = 313; + *errorCode = 313; // isc_dyn_dup_package } END_FOR break; + } + + case obj_schema: + { + fb_assert(object_name.schema.isEmpty()); + + static const CachedRequestId schemaHandleId; + requestHandle.reset(tdbb, schemaHandleId); + + FOR(REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + SCH IN RDB$SCHEMAS + WITH SCH.RDB$SCHEMA_NAME EQ object_name.object.c_str() + { + *errorCode = 316; // isc_dyn_dup_schema + } + END_FOR + + break; + } default: fb_assert(false); @@ -228,12 +291,13 @@ bool DYN_UTIL_check_unique_name_nothrow(thread_db* tdbb, jrd_tra* transaction, } // Check if an object already exists. If yes, throw error. -void DYN_UTIL_check_unique_name(thread_db* tdbb, jrd_tra* transaction, const MetaName& object_name, int object_type) +void DYN_UTIL_check_unique_name(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& object_name, + int object_type) { USHORT errorCode; if (!DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, object_name, object_type, &errorCode)) - status_exception::raise(Arg::PrivateDyn(errorCode) << object_name.c_str()); + status_exception::raise(Arg::PrivateDyn(errorCode) << object_name.toQuotedString()); } @@ -284,7 +348,7 @@ SINT64 DYN_UTIL_gen_unique_id(thread_db* tdbb, SSHORT id, const char* generator_ } -void DYN_UTIL_generate_constraint_name(thread_db* tdbb, MetaName& buffer) +void DYN_UTIL_generate_constraint_name(thread_db* tdbb, QualifiedName& buffer) { /************************************** * @@ -297,13 +361,15 @@ void DYN_UTIL_generate_constraint_name(thread_db* tdbb, MetaName& buffer) * **************************************/ SET_TDBB(tdbb); - Jrd::Attachment* attachment = tdbb->getAttachment(); + fb_assert(buffer.schema.hasData()); + + Jrd::Attachment* attachment = tdbb->getAttachment(); bool found = false; do { - buffer.printf("INTEG_%" SQUADFORMAT, + buffer.object.printf("INTEG_%" SQUADFORMAT, DYN_UTIL_gen_unique_id(tdbb, drq_g_nxt_con, "RDB$CONSTRAINT_NAME")); AutoCacheRequest request(tdbb, drq_f_nxt_con, DYN_REQUESTS); @@ -311,7 +377,8 @@ void DYN_UTIL_generate_constraint_name(thread_db* tdbb, MetaName& buffer) found = false; FOR(REQUEST_HANDLE request) FIRST 1 X IN RDB$RELATION_CONSTRAINTS - WITH X.RDB$CONSTRAINT_NAME EQ buffer.c_str() + WITH X.RDB$SCHEMA_NAME EQ buffer.schema.c_str() AND + X.RDB$CONSTRAINT_NAME EQ buffer.object.c_str() { found = true; } @@ -320,25 +387,7 @@ void DYN_UTIL_generate_constraint_name(thread_db* tdbb, MetaName& buffer) } -void DYN_UTIL_generate_field_name(thread_db* tdbb, TEXT* buffer) -{ -/************************************** - * - * D Y N _ U T I L _ g e n e r a t e _ f i e l d _ n a m e - * - ************************************** - * - * Functional description - * Stub to make it work with char* too. - * - **************************************/ - MetaName temp; - DYN_UTIL_generate_field_name(tdbb, temp); - strcpy(buffer, temp.c_str()); -} - - -void DYN_UTIL_generate_field_name(thread_db* tdbb, MetaName& buffer) +void DYN_UTIL_generate_field_name(thread_db* tdbb, QualifiedName& buffer) { /************************************** * @@ -351,12 +400,15 @@ void DYN_UTIL_generate_field_name(thread_db* tdbb, MetaName& buffer) * **************************************/ SET_TDBB(tdbb); + + fb_assert(buffer.schema.hasData()); + Jrd::Attachment* attachment = tdbb->getAttachment(); bool found = false; do { - buffer.printf("RDB$%" SQUADFORMAT, + buffer.object.printf("RDB$%" SQUADFORMAT, DYN_UTIL_gen_unique_id(tdbb, drq_g_nxt_fld, "RDB$FIELD_NAME")); AutoCacheRequest request(tdbb, drq_f_nxt_fld, DYN_REQUESTS); @@ -364,7 +416,8 @@ void DYN_UTIL_generate_field_name(thread_db* tdbb, MetaName& buffer) found = false; FOR(REQUEST_HANDLE request) FIRST 1 X IN RDB$FIELDS - WITH X.RDB$FIELD_NAME EQ buffer.c_str() + WITH X.RDB$SCHEMA_NAME EQ buffer.schema.c_str() AND + X.RDB$FIELD_NAME EQ buffer.object.c_str() { found = true; } @@ -373,7 +426,7 @@ void DYN_UTIL_generate_field_name(thread_db* tdbb, MetaName& buffer) } -void DYN_UTIL_generate_field_position(thread_db* tdbb, const MetaName& relation_name, +void DYN_UTIL_generate_field_position(thread_db* tdbb, const QualifiedName& relation_name, SLONG* field_pos) { /************************************** @@ -395,7 +448,8 @@ void DYN_UTIL_generate_field_position(thread_db* tdbb, const MetaName& relation_ FOR(REQUEST_HANDLE request) X IN RDB$RELATION_FIELDS - WITH X.RDB$RELATION_NAME EQ relation_name.c_str() + WITH X.RDB$SCHEMA_NAME EQ relation_name.schema.c_str() AND + X.RDB$RELATION_NAME EQ relation_name.object.c_str() { if (X.RDB$FIELD_POSITION.NULL) continue; @@ -409,7 +463,7 @@ void DYN_UTIL_generate_field_position(thread_db* tdbb, const MetaName& relation_ void DYN_UTIL_generate_index_name(thread_db* tdbb, jrd_tra* /*transaction*/, - MetaName& buffer, UCHAR verb) + QualifiedName& buffer, UCHAR verb) { /************************************** * @@ -422,6 +476,9 @@ void DYN_UTIL_generate_index_name(thread_db* tdbb, jrd_tra* /*transaction*/, * **************************************/ SET_TDBB(tdbb); + + fb_assert(buffer.schema.hasData()); + Jrd::Attachment* attachment = tdbb->getAttachment(); bool found = false; @@ -440,7 +497,7 @@ void DYN_UTIL_generate_index_name(thread_db* tdbb, jrd_tra* /*transaction*/, format = "RDB$%" SQUADFORMAT; } - buffer.printf(format, + buffer.object.printf(format, DYN_UTIL_gen_unique_id(tdbb, drq_g_nxt_idx, "RDB$INDEX_NAME")); AutoCacheRequest request(tdbb, drq_f_nxt_idx, DYN_REQUESTS); @@ -448,7 +505,8 @@ void DYN_UTIL_generate_index_name(thread_db* tdbb, jrd_tra* /*transaction*/, found = false; FOR(REQUEST_HANDLE request) FIRST 1 X IN RDB$INDICES - WITH X.RDB$INDEX_NAME EQ buffer.c_str() + WITH X.RDB$SCHEMA_NAME EQ buffer.schema.c_str() AND + X.RDB$INDEX_NAME EQ buffer.object.c_str() { found = true; } @@ -458,9 +516,12 @@ void DYN_UTIL_generate_index_name(thread_db* tdbb, jrd_tra* /*transaction*/, // Generate a name unique to RDB$GENERATORS. -void DYN_UTIL_generate_generator_name(thread_db* tdbb, MetaName& buffer) +void DYN_UTIL_generate_generator_name(thread_db* tdbb, QualifiedName& buffer) { SET_TDBB(tdbb); + + fb_assert(buffer.schema.hasData()); + Jrd::Attachment* attachment = tdbb->getAttachment(); AutoCacheRequest request(tdbb, drq_f_nxt_gen, DYN_REQUESTS); @@ -468,13 +529,15 @@ void DYN_UTIL_generate_generator_name(thread_db* tdbb, MetaName& buffer) do { - buffer.printf("RDB$%" SQUADFORMAT, + buffer.object.printf("RDB$%" SQUADFORMAT, DYN_UTIL_gen_unique_id(tdbb, drq_g_nxt_gen, "RDB$GENERATOR_NAME")); found = false; FOR (REQUEST_HANDLE request) - FIRST 1 X IN RDB$GENERATORS WITH X.RDB$GENERATOR_NAME EQ buffer.c_str() + FIRST 1 X IN RDB$GENERATORS + WITH X.RDB$SCHEMA_NAME EQ buffer.schema.c_str() AND + X.RDB$GENERATOR_NAME EQ buffer.object.c_str() { found = true; } @@ -483,7 +546,7 @@ void DYN_UTIL_generate_generator_name(thread_db* tdbb, MetaName& buffer) } -void DYN_UTIL_generate_trigger_name(thread_db* tdbb, jrd_tra* /*transaction*/, MetaName& buffer) +void DYN_UTIL_generate_trigger_name(thread_db* tdbb, jrd_tra* /*transaction*/, QualifiedName& buffer) { /************************************** * @@ -496,12 +559,15 @@ void DYN_UTIL_generate_trigger_name(thread_db* tdbb, jrd_tra* /*transaction*/, M * **************************************/ SET_TDBB(tdbb); + + fb_assert(buffer.schema.hasData()); + Jrd::Attachment* attachment = tdbb->getAttachment(); bool found = false; do { - buffer.printf("CHECK_%" SQUADFORMAT, + buffer.object.printf("CHECK_%" SQUADFORMAT, DYN_UTIL_gen_unique_id(tdbb, drq_g_nxt_trg, "RDB$TRIGGER_NAME")); AutoCacheRequest request(tdbb, drq_f_nxt_trg, DYN_REQUESTS); @@ -509,7 +575,8 @@ void DYN_UTIL_generate_trigger_name(thread_db* tdbb, jrd_tra* /*transaction*/, M found = false; FOR(REQUEST_HANDLE request) FIRST 1 X IN RDB$TRIGGERS - WITH X.RDB$TRIGGER_NAME EQ buffer.c_str() + WITH X.RDB$SCHEMA_NAME EQ buffer.schema.c_str() AND + X.RDB$TRIGGER_NAME EQ buffer.object.c_str() { found = true; } @@ -520,9 +587,10 @@ void DYN_UTIL_generate_trigger_name(thread_db* tdbb, jrd_tra* /*transaction*/, M bool DYN_UTIL_find_field_source(thread_db* tdbb, jrd_tra* transaction, - const MetaName& view_name, + const QualifiedName& view_name, USHORT context, const TEXT* local_name, + TEXT* output_field_schema_name, TEXT* output_field_name) { /************************************** @@ -541,15 +609,22 @@ bool DYN_UTIL_find_field_source(thread_db* tdbb, bool found = false; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - VRL IN RDB$VIEW_RELATIONS CROSS - RFR IN RDB$RELATION_FIELDS OVER RDB$RELATION_NAME - WITH VRL.RDB$VIEW_NAME EQ view_name.c_str() AND - VRL.RDB$VIEW_CONTEXT EQ context AND - VRL.RDB$CONTEXT_TYPE BETWEEN VCT_TABLE AND VCT_VIEW AND - VRL.RDB$PACKAGE_NAME MISSING AND - RFR.RDB$FIELD_NAME EQ local_name + VRL IN RDB$VIEW_RELATIONS + CROSS RFR IN RDB$RELATION_FIELDS + WITH VRL.RDB$SCHEMA_NAME EQ view_name.schema.c_str() AND + VRL.RDB$VIEW_NAME EQ view_name.object.c_str() AND + VRL.RDB$VIEW_CONTEXT EQ context AND + VRL.RDB$CONTEXT_TYPE BETWEEN VCT_TABLE AND VCT_VIEW AND + VRL.RDB$PACKAGE_NAME MISSING AND + RFR.RDB$SCHEMA_NAME EQ VRL.RDB$RELATION_SCHEMA_NAME AND + RFR.RDB$RELATION_NAME EQ VRL.RDB$RELATION_NAME AND + RFR.RDB$FIELD_NAME EQ local_name { found = true; + + fb_utils::exact_name_limit(RFR.RDB$FIELD_SOURCE_SCHEMA_NAME, sizeof(RFR.RDB$FIELD_SOURCE_SCHEMA_NAME)); + strcpy(output_field_schema_name, RFR.RDB$FIELD_SOURCE_SCHEMA_NAME); + fb_utils::exact_name_limit(RFR.RDB$FIELD_SOURCE, sizeof(RFR.RDB$FIELD_SOURCE)); strcpy(output_field_name, RFR.RDB$FIELD_SOURCE); } @@ -560,15 +635,17 @@ bool DYN_UTIL_find_field_source(thread_db* tdbb, request.reset(tdbb, drq_l_fld_src3, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - VRL IN RDB$VIEW_RELATIONS CROSS - PPR IN RDB$PROCEDURE_PARAMETERS - WITH VRL.RDB$RELATION_NAME EQ PPR.RDB$PROCEDURE_NAME AND - VRL.RDB$VIEW_NAME EQ view_name.c_str() AND - VRL.RDB$VIEW_CONTEXT EQ context AND - VRL.RDB$CONTEXT_TYPE EQ VCT_PROCEDURE AND - PPR.RDB$PACKAGE_NAME EQUIV VRL.RDB$PACKAGE_NAME AND - PPR.RDB$PARAMETER_TYPE = 1 AND // output - PPR.RDB$PARAMETER_NAME EQ local_name + VRL IN RDB$VIEW_RELATIONS + CROSS PPR IN RDB$PROCEDURE_PARAMETERS + WITH VRL.RDB$RELATION_SCHEMA_NAME EQ PPR.RDB$SCHEMA_NAME AND + VRL.RDB$RELATION_NAME EQ PPR.RDB$PROCEDURE_NAME AND + VRL.RDB$SCHEMA_NAME EQ view_name.schema.c_str() AND + VRL.RDB$VIEW_NAME EQ view_name.object.c_str() AND + VRL.RDB$VIEW_CONTEXT EQ context AND + VRL.RDB$CONTEXT_TYPE EQ VCT_PROCEDURE AND + PPR.RDB$PACKAGE_NAME EQUIV VRL.RDB$PACKAGE_NAME AND + PPR.RDB$PARAMETER_TYPE = 1 AND // output + PPR.RDB$PARAMETER_NAME EQ local_name { found = true; fb_utils::exact_name_limit(PPR.RDB$FIELD_SOURCE, sizeof(PPR.RDB$FIELD_SOURCE)); @@ -582,7 +659,7 @@ bool DYN_UTIL_find_field_source(thread_db* tdbb, void DYN_UTIL_store_check_constraints(thread_db* tdbb, jrd_tra* transaction, - const MetaName& constraint_name, const MetaName& trigger_name) + const QualifiedName& constraint_name, const MetaName& trigger_name) { /************************************** * @@ -602,7 +679,8 @@ void DYN_UTIL_store_check_constraints(thread_db* tdbb, jrd_tra* transaction, STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) CHK IN RDB$CHECK_CONSTRAINTS { - strcpy(CHK.RDB$CONSTRAINT_NAME, constraint_name.c_str()); + strcpy(CHK.RDB$SCHEMA_NAME, constraint_name.schema.c_str()); + strcpy(CHK.RDB$CONSTRAINT_NAME, constraint_name.object.c_str()); strcpy(CHK.RDB$TRIGGER_NAME, trigger_name.c_str()); } END_STORE diff --git a/src/jrd/exe.cpp b/src/jrd/exe.cpp index 61eccec95d..0951dcc4a2 100644 --- a/src/jrd/exe.cpp +++ b/src/jrd/exe.cpp @@ -121,7 +121,7 @@ using namespace Firebird; string Item::getDescription(Request* request, const ItemInfo* itemInfo) const { if (itemInfo && itemInfo->name.hasData()) - return itemInfo->name.c_str(); + return itemInfo->name.toQuotedString(); int oneBasedIndex = index + 1; string s; @@ -1502,20 +1502,20 @@ bool EXE_get_stack_trace(const Request* request, string& sTrace) string context, name; - if (statement->triggerName.length()) + if (statement->triggerName.object.length()) { context = "At trigger"; - name = statement->triggerName.c_str(); + name = statement->triggerName.toQuotedString(); } else if (statement->procedure) { context = statement->parentStatement ? "At sub procedure" : "At procedure"; - name = statement->procedure->getName().toString(); + name = statement->procedure->getName().toQuotedString(); } else if (statement->function) { context = statement->parentStatement ? "At sub function" : "At function"; - name = statement->function->getName().toString(); + name = statement->function->getName().toQuotedString(); } else if (req->req_src_line) { @@ -1527,7 +1527,7 @@ bool EXE_get_stack_trace(const Request* request, string& sTrace) name.trim(); if (name.hasData()) - context += string(" '") + name + string("'"); + context += string(" ") + name; if (sTrace.length() + context.length() > MAX_STACK_TRACE) break; diff --git a/src/jrd/exe.h b/src/jrd/exe.h index 3e34821702..71e8ca38fb 100644 --- a/src/jrd/exe.h +++ b/src/jrd/exe.h @@ -106,6 +106,7 @@ const int csb_reuse_context = 128; // allow context reusage const int csb_subroutine = 256; // sub routine const int csb_reload = 512; // request's BLR should be loaded and parsed again const int csb_computed_field = 1024; // computed field expression +const int csb_search_system_schema = 2048; // search system schema // CompilerScratch.csb_rpt[].csb_flags's values. const int csb_active = 1; // stream is active @@ -216,8 +217,8 @@ struct AccessItem { MetaName acc_security_name; SLONG acc_ss_rel_id; // Relation Id which owner will be used to check permissions - MetaName acc_name; - MetaName acc_r_name; + QualifiedName acc_name; + MetaName acc_col_name; ObjectType acc_type; SecurityClass::flags_t acc_mask; @@ -243,20 +244,20 @@ struct AccessItem if (i1.acc_mask != i2.acc_mask) return i1.acc_mask > i2.acc_mask; - if ((v = i1.acc_name.compare(i2.acc_name)) != 0) - return v > 0; + if (i1.acc_name != i2.acc_name) + return i1.acc_name > i2.acc_name; - if ((v = i1.acc_r_name.compare(i2.acc_r_name)) != 0) - return v > 0; + if (i1.acc_col_name != i2.acc_col_name) + return i1.acc_col_name > i2.acc_col_name; return false; // Equal } AccessItem(const MetaName& security_name, SLONG view_id, - const MetaName& name, ObjectType type, - SecurityClass::flags_t mask, const MetaName& relName) + const QualifiedName& name, ObjectType type, + SecurityClass::flags_t mask, const MetaName& columnName) : acc_security_name(security_name), acc_ss_rel_id(view_id), acc_name(name), - acc_r_name(relName), acc_type(type), acc_mask(mask) + acc_col_name(columnName), acc_type(type), acc_mask(mask) {} }; @@ -422,13 +423,13 @@ public: public: MetaName name; - MetaNamePair field; + QualifiedNameMetaNamePair field; bool nullable; bool explicitCollation; bool fullDomain; }; -typedef Firebird::LeftPooledMap MapFieldInfo; +typedef Firebird::LeftPooledMap MapFieldInfo; typedef Firebird::RightPooledMap MapItemInfo; // Compile scratch block @@ -451,7 +452,7 @@ public: jrd_rel* relation; const Function* function; const jrd_prc* procedure; - const MetaName* name; + const QualifiedName* name; SLONG number; }; @@ -493,6 +494,7 @@ public: subProcedures(p), outerMessagesMap(p), outerVarsMap(p), + csb_schema(p), csb_currentForNode(NULL), csb_currentDMLNode(NULL), csb_currentAssignTarget(NULL), @@ -530,6 +532,28 @@ public: dependencies.add(dependency); } + void qualifyExistingName(thread_db* tdbb, QualifiedName& name, ObjectType objType) + { + if (!(name.schema.isEmpty() && name.object.hasData())) + return; + + const auto attachment = tdbb->getAttachment(); + + if (csb_schema.hasData()) + { + Firebird::ObjectsArray schemaSearchPath; + + if (csb_g_flags & csb_search_system_schema) + schemaSearchPath.push(SYSTEM_SCHEMA); + + schemaSearchPath.push(csb_schema); + + attachment->qualifyExistingName(tdbb, name, objType, &schemaSearchPath); + } + else + attachment->qualifyExistingName(tdbb, name, objType); + } + #ifdef CMP_DEBUG void dump(const char* format, ...) { @@ -577,7 +601,7 @@ public: // Map of message number to field number to pad for external routines. Firebird::GenericMap > > csb_message_pad; - MetaName csb_domain_validation; // Parsing domain constraint in PSQL + QualifiedName csb_domain_validation; // Parsing domain constraint in PSQL // used in cmp.cpp/pass1 jrd_rel* csb_view; @@ -594,6 +618,8 @@ public: Firebird::NonPooledMap outerMessagesMap; // Firebird::NonPooledMap outerVarsMap; // + MetaName csb_schema; + ForNode* csb_currentForNode; StmtNode* csb_currentDMLNode; // could be StoreNode or ModifyNode ExprNode* csb_currentAssignTarget; diff --git a/src/jrd/extds/InternalDS.cpp b/src/jrd/extds/InternalDS.cpp index a576b986a2..f4254f7217 100644 --- a/src/jrd/extds/InternalDS.cpp +++ b/src/jrd/extds/InternalDS.cpp @@ -477,24 +477,15 @@ void InternalStatement::doPrepare(thread_db* tdbb, const string& sql) tran->getHandle()->tra_caller_name = CallerName(obj_trigger, statement->triggerName, statement->triggerInvoker->getUserName()); } - else if (statement->triggerName.hasData()) + else if (statement->triggerName.object.hasData()) { tran->getHandle()->tra_caller_name = CallerName(obj_trigger, statement->triggerName, ""); } - else if ((routine = statement->getRoutine()) && routine->getName().identifier.hasData()) + else if ((routine = statement->getRoutine()) && routine->getName().object.hasData()) { const MetaString& userName = routine->invoker ? routine->invoker->getUserName() : ""; - if (routine->getName().package.isEmpty()) - { - tran->getHandle()->tra_caller_name = CallerName(routine->getObjectType(), - routine->getName().identifier, userName); - } - else - { - tran->getHandle()->tra_caller_name = CallerName(obj_package_header, - routine->getName().package, userName); - } + tran->getHandle()->tra_caller_name = CallerName(routine->getObjectType(), routine->getName(), userName); } } else diff --git a/src/jrd/fields.h b/src/jrd/fields.h index c67cfb2234..4ed85bd373 100644 --- a/src/jrd/fields.h +++ b/src/jrd/fields.h @@ -52,7 +52,7 @@ FIELD(fld_v_blr , nam_v_blr , dtype_blob , BLOB_SIZE , isc_blob_blr , NULL , true , ODS_13_0) FIELD(fld_validation , nam_vl_blr , dtype_blob , BLOB_SIZE , isc_blob_blr , NULL , true , ODS_13_0) FIELD(fld_value , nam_value , dtype_blob , BLOB_SIZE , isc_blob_blr , NULL , true , ODS_13_0) - FIELD(fld_class , nam_class , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) + FIELD(fld_class , nam_class , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_13_0) // FIXME: increase, must be MAX_SQL_IDENTIFIER_LEN + max length of DDL security class name + 1 FIELD(fld_acl , nam_acl , dtype_blob , BLOB_SIZE , isc_blob_acl , NULL , true , ODS_13_0) FIELD(fld_file_name , nam_file_name , dtype_varying , 255 , 0 , NULL , true , ODS_13_0) FIELD(fld_file_name2 , nam_file_name2 , dtype_varying , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true , ODS_13_0) @@ -234,3 +234,6 @@ FIELD(fld_integer , nam_integer , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_1) FIELD(fld_par_workers , nam_par_workers , dtype_long , sizeof(SLONG) , 0 , NULL , true , ODS_13_1) + + FIELD(fld_sch_name , nam_sch_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true , ODS_14_0) + FIELD(fld_text_max , nam_text_max , dtype_varying, MAX_VARY_COLUMN_SIZE / METADATA_BYTES_PER_CHAR * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata, NULL, true, ODS_14_0) diff --git a/src/jrd/filters.cpp b/src/jrd/filters.cpp index 387b73f095..0c14851fe2 100644 --- a/src/jrd/filters.cpp +++ b/src/jrd/filters.cpp @@ -178,7 +178,7 @@ ISC_STATUS filter_acl(USHORT action, BlobControl* control) USHORT length; const ISC_STATUS status = caller(isc_blob_filter_get_segment, control, (USHORT) l, temp, &length); - TEXT line[BUFFER_SMALL]; + TEXT line[BUFFER_LARGE]; if (!status) { @@ -198,10 +198,27 @@ ISC_STATUS filter_acl(USHORT action, BlobControl* control) while ((c = *p++) != 0) { all_wild = false; - sprintf(out, "%s%.*s, ", acl_ids[c], *p, p + 1); + sprintf(out, "%s%.*s", acl_ids[c], *p, p + 1); p += *p + 1; while (*out) ++out; + + switch (c) + { + case id_view: + case id_package: + case id_procedure: + case id_trigger: + case id_function: + sprintf(out, ".%.*s", *p, p + 1); + p += *p + 1; + while (*out) + ++out; + break; + } + + *out++ = ','; + *out++ = ' '; } if (all_wild) { diff --git a/src/jrd/fun.epp b/src/jrd/fun.epp index bc1eb70395..76a096cd59 100644 --- a/src/jrd/fun.epp +++ b/src/jrd/fun.epp @@ -330,7 +330,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra if (!function->fun_entrypoint) { Firebird::status_exception::raise(Arg::Gds(isc_funnotdef) << - Arg::Str(function->getName().toString()) << + Arg::Str(function->getName().toQuotedString()) << Arg::Gds(isc_modnotfound)); } @@ -787,13 +787,13 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra { status_exception::raise(Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_udf_fp_overflow) << - Arg::Str(function->getName().toString())); + Arg::Str(function->getName().toQuotedString())); } else if (std::isnan(value->vlu_misc.vlu_double)) { status_exception::raise(Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_udf_fp_nan) << - Arg::Str(function->getName().toString())); + Arg::Str(function->getName().toQuotedString())); } break; @@ -802,13 +802,13 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra { status_exception::raise(Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_udf_fp_overflow) << - Arg::Str(function->getName().toString())); + Arg::Str(function->getName().toQuotedString())); } else if (value->vlu_misc.vlu_dec64.isNan()) { status_exception::raise(Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_udf_fp_nan) << - Arg::Str(function->getName().toString())); + Arg::Str(function->getName().toQuotedString())); } break; @@ -817,13 +817,13 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra { status_exception::raise(Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_udf_fp_overflow) << - Arg::Str(function->getName().toString())); + Arg::Str(function->getName().toQuotedString())); } else if (value->vlu_misc.vlu_dec128.isNan()) { status_exception::raise(Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_udf_fp_nan) << - Arg::Str(function->getName().toString())); + Arg::Str(function->getName().toQuotedString())); } break; } @@ -837,7 +837,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra catch (const Exception& ex) { Arg::StatusVector v(ex); - const string msg = "UDF: " + function->getName().toString(); + const string msg = "UDF: " + function->getName().toQuotedString(); v << Arg::Gds(isc_random) << msg; status->setErrors(v.value()); diff --git a/src/jrd/grant.epp b/src/jrd/grant.epp index aabe8453cf..cd934bab22 100644 --- a/src/jrd/grant.epp +++ b/src/jrd/grant.epp @@ -55,12 +55,11 @@ #include "../common/classes/array.h" #include "../jrd/constants.h" +using namespace Firebird; using namespace Jrd; // privileges given to the owner of a relation -const SecurityClass::flags_t OWNER_PRIVS = SCL_control | SCL_drop | SCL_alter; - inline void CHECK_AND_MOVE(Acl& to, UCHAR from) { to.add(from); @@ -68,24 +67,24 @@ inline void CHECK_AND_MOVE(Acl& to, UCHAR from) DATABASE DB = STATIC "yachts.lnk"; -static void define_default_class(thread_db*, const TEXT*, MetaName&, const Acl&, +static void define_default_class(thread_db*, const QualifiedName&, MetaName&, const Acl&, jrd_tra*); static void finish_security_class(Acl&, SecurityClass::flags_t); -static void get_object_info(thread_db*, const TEXT*, ObjectType, +static void get_object_info(thread_db*, const QualifiedName&, ObjectType, MetaName&, MetaName&, MetaName&, bool&); -static SecurityClass::flags_t get_public_privs(thread_db*, const TEXT*, SSHORT); -static void get_user_privs(thread_db*, Acl&, const TEXT*, SSHORT, const MetaName&, +static SecurityClass::flags_t get_public_privs(thread_db*, const QualifiedName&, SSHORT); +static void get_user_privs(thread_db*, Acl&, const QualifiedName&, SSHORT, const MetaName&, SecurityClass::flags_t); -static void grant_user(Acl&, const MetaName&, SSHORT, SecurityClass::flags_t); -static SecurityClass::flags_t save_field_privileges(thread_db*, Acl&, const TEXT*, +static void grant_user(Acl&, const QualifiedName&, SSHORT, SecurityClass::flags_t); +static SecurityClass::flags_t save_field_privileges(thread_db*, Acl&, const QualifiedName&, const MetaName&, SecurityClass::flags_t, jrd_tra*); static void save_security_class(thread_db*, const MetaName&, const Acl&, jrd_tra*); static SecurityClass::flags_t trans_sql_priv(const TEXT*); -static SecurityClass::flags_t squeeze_acl(Acl&, const MetaName&, SSHORT); +static SecurityClass::flags_t squeeze_acl(Acl&, const QualifiedName&, SSHORT); static bool check_string(const UCHAR*, const MetaName&); -void GRANT_privileges(thread_db* tdbb, const Firebird::string& name, ObjectType id, jrd_tra* transaction) +void GRANT_privileges(thread_db* tdbb, const QualifiedName& name, ObjectType id, jrd_tra* transaction) { /************************************** * @@ -104,20 +103,20 @@ void GRANT_privileges(thread_db* tdbb, const Firebird::string& name, ObjectType bool restrct = false; - MetaName s_class, owner, default_class; + MetaName s_class, default_class; + MetaName owner; bool view; // unused after being retrieved. - get_object_info(tdbb, name.c_str(), id, owner, s_class, default_class, view); + get_object_info(tdbb, name, id, owner, s_class, default_class, view); - if (s_class.length() == 0) { + if (s_class.isEmpty()) return; - } // start the acl off by giving the owner all privileges Acl acl, default_acl; CHECK_AND_MOVE(acl, ACL_version); - SecurityClass::flags_t priv = OWNER_PRIVS; + SecurityClass::flags_t priv = SCL_control | SCL_drop | SCL_alter; switch (id) { @@ -138,21 +137,22 @@ void GRANT_privileges(thread_db* tdbb, const Firebird::string& name, ObjectType case obj_generator: case obj_charset: case obj_collation: + case obj_schema: priv |= SCL_usage; break; default: if (isDdlObject(id)) - priv = OWNER_PRIVS; + priv = SCL_create | SCL_drop | SCL_alter; break; } - grant_user(acl, owner, obj_user, priv); + grant_user(acl, QualifiedName(owner), obj_user, priv); // Pick up core privileges - const SecurityClass::flags_t public_priv = get_public_privs(tdbb, name.c_str(), id); - get_user_privs(tdbb, acl, name.c_str(), id, owner, public_priv); + const SecurityClass::flags_t public_priv = get_public_privs(tdbb, name, id); + get_user_privs(tdbb, acl, name, id, owner, public_priv); if (id == obj_relation) { @@ -164,8 +164,7 @@ void GRANT_privileges(thread_db* tdbb, const Firebird::string& name, ObjectType default_acl.assign(acl); const SecurityClass::flags_t aggregate_public = - save_field_privileges(tdbb, acl, name.c_str(), owner, public_priv, - transaction); + save_field_privileges(tdbb, acl, name, owner, public_priv, transaction); // finish off and store the security class for the relation @@ -183,8 +182,7 @@ void GRANT_privileges(thread_db* tdbb, const Firebird::string& name, ObjectType if (restrct) { finish_security_class(default_acl, public_priv); - define_default_class(tdbb, name.c_str(), default_class, default_acl, - transaction); + define_default_class(tdbb, name, default_class, default_acl, transaction); } } else @@ -196,7 +194,7 @@ void GRANT_privileges(thread_db* tdbb, const Firebird::string& name, ObjectType static void define_default_class(thread_db* tdbb, - const TEXT* relation_name, + const QualifiedName& relationName, MetaName& default_class, const Acl& acl, jrd_tra* transaction) @@ -219,21 +217,21 @@ static void define_default_class(thread_db* tdbb, **************************************/ SET_TDBB(tdbb); - if (default_class.length() == 0) + if (default_class.isEmpty()) { default_class.printf("%s%" SQUADFORMAT, DEFAULT_CLASS, - DPM_gen_id(tdbb, MET_lookup_generator(tdbb, DEFAULT_CLASS), false, 1)); + DPM_gen_id(tdbb, MET_lookup_generator(tdbb, QualifiedName(DEFAULT_CLASS, SYSTEM_SCHEMA)), false, 1)); AutoCacheRequest request(tdbb, irq_grant7, IRQ_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) REL IN RDB$RELATIONS - WITH REL.RDB$RELATION_NAME EQ relation_name + WITH REL.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + REL.RDB$RELATION_NAME EQ relationName.object.c_str() { MODIFY REL USING REL.RDB$DEFAULT_CLASS.NULL = FALSE; - jrd_vtof(default_class.c_str(), REL.RDB$DEFAULT_CLASS, - sizeof(REL.RDB$DEFAULT_CLASS)); + jrd_vtof(default_class.c_str(), REL.RDB$DEFAULT_CLASS, sizeof(REL.RDB$DEFAULT_CLASS)); END_MODIFY } END_FOR @@ -241,14 +239,10 @@ static void define_default_class(thread_db* tdbb, save_security_class(tdbb, default_class, acl, transaction); - dsc desc; - desc.dsc_dtype = dtype_text; - desc.dsc_sub_type = 0; - desc.dsc_scale = 0; - desc.dsc_ttype() = ttype_metadata; - desc.dsc_address = (UCHAR *) relation_name; - desc.dsc_length = static_cast(strlen(relation_name)); - DFW_post_work(transaction, dfw_scan_relation, &desc, 0); + dsc schemaDesc, nameDesc; + schemaDesc.makeText((USHORT) strlen(relationName.schema.c_str()), CS_METADATA, (UCHAR*) relationName.schema.c_str()); + nameDesc.makeText((USHORT) strlen(relationName.object.c_str()), CS_METADATA, (UCHAR*) relationName.object.c_str()); + DFW_post_work(transaction, dfw_scan_relation, &nameDesc, &schemaDesc, 0); } @@ -276,7 +270,7 @@ static void finish_security_class(Acl& acl, SecurityClass::flags_t public_priv) static SecurityClass::flags_t get_public_privs(thread_db* tdbb, - const TEXT* object_name, + const QualifiedName& object_name, SSHORT obj_type) { /************************************** @@ -298,13 +292,14 @@ static SecurityClass::flags_t get_public_privs(thread_db* tdbb, FOR(REQUEST_HANDLE request) PRV IN RDB$USER_PRIVILEGES - WITH PRV.RDB$RELATION_NAME EQ object_name AND - PRV.RDB$OBJECT_TYPE EQ obj_type AND - PRV.RDB$USER EQ "PUBLIC" AND - PRV.RDB$USER_TYPE EQ obj_user AND - PRV.RDB$FIELD_NAME MISSING + WITH PRV.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(object_name.schema.c_str(), '') AND + PRV.RDB$RELATION_NAME EQUIV NULLIF(object_name.object.c_str(), '') AND + PRV.RDB$OBJECT_TYPE EQ obj_type AND + PRV.RDB$USER EQ "PUBLIC" AND + PRV.RDB$USER_TYPE EQ obj_user AND + PRV.RDB$FIELD_NAME MISSING { - public_priv |= trans_sql_priv(PRV.RDB$PRIVILEGE); + public_priv |= trans_sql_priv(PRV.RDB$PRIVILEGE); } END_FOR @@ -313,7 +308,7 @@ static SecurityClass::flags_t get_public_privs(thread_db* tdbb, static void get_object_info(thread_db* tdbb, - const TEXT* object_name, + const QualifiedName& object_name, ObjectType obj_type, MetaName& owner, MetaName& s_class, @@ -335,7 +330,9 @@ static void get_object_info(thread_db* tdbb, SET_TDBB(tdbb); Jrd::Attachment* attachment = tdbb->getAttachment(); - owner = s_class = default_class = ""; + owner = ""; + s_class = ""; + default_class = ""; view = false; if (obj_type == obj_relation) @@ -343,8 +340,9 @@ static void get_object_info(thread_db* tdbb, AutoCacheRequest request(tdbb, irq_grant1, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - REL IN RDB$RELATIONS WITH - REL.RDB$RELATION_NAME EQ object_name + REL IN RDB$RELATIONS + WITH REL.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + REL.RDB$RELATION_NAME EQ object_name.object.c_str() { s_class = REL.RDB$SECURITY_CLASS; default_class = REL.RDB$DEFAULT_CLASS; @@ -359,7 +357,8 @@ static void get_object_info(thread_db* tdbb, FOR (REQUEST_HANDLE request) PKG IN RDB$PACKAGES - WITH PKG.RDB$PACKAGE_NAME EQ object_name + WITH PKG.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + PKG.RDB$PACKAGE_NAME EQ object_name.object.c_str() { s_class = PKG.RDB$SECURITY_CLASS; default_class = ""; @@ -373,9 +372,10 @@ static void get_object_info(thread_db* tdbb, AutoCacheRequest request(tdbb, irq_grant9, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - PRC IN RDB$PROCEDURES WITH - PRC.RDB$PROCEDURE_NAME EQ object_name AND - PRC.RDB$PACKAGE_NAME MISSING + PRC IN RDB$PROCEDURES + WITH PRC.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + PRC.RDB$PROCEDURE_NAME EQ object_name.object.c_str() AND + PRC.RDB$PACKAGE_NAME MISSING { s_class = PRC.RDB$SECURITY_CLASS; default_class = ""; @@ -389,9 +389,10 @@ static void get_object_info(thread_db* tdbb, AutoCacheRequest request(tdbb, irq_grant11, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - FUN IN RDB$FUNCTIONS WITH - FUN.RDB$FUNCTION_NAME EQ object_name AND - FUN.RDB$PACKAGE_NAME MISSING + FUN IN RDB$FUNCTIONS + WITH FUN.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + FUN.RDB$FUNCTION_NAME EQ object_name.object.c_str() AND + FUN.RDB$PACKAGE_NAME MISSING { s_class = FUN.RDB$SECURITY_CLASS; default_class = ""; @@ -405,8 +406,9 @@ static void get_object_info(thread_db* tdbb, AutoCacheRequest request(tdbb, irq_grant12, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - CS IN RDB$CHARACTER_SETS WITH - CS.RDB$CHARACTER_SET_NAME EQ object_name + CS IN RDB$CHARACTER_SETS + WITH CS.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + CS.RDB$CHARACTER_SET_NAME EQ object_name.object.c_str() { s_class = CS.RDB$SECURITY_CLASS; default_class = ""; @@ -420,8 +422,9 @@ static void get_object_info(thread_db* tdbb, AutoCacheRequest request(tdbb, irq_grant13, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - COLL IN RDB$COLLATIONS WITH - COLL.RDB$COLLATION_NAME EQ object_name + COLL IN RDB$COLLATIONS + WITH COLL.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + COLL.RDB$COLLATION_NAME EQ object_name.object.c_str() { s_class = COLL.RDB$SECURITY_CLASS; default_class = ""; @@ -435,8 +438,9 @@ static void get_object_info(thread_db* tdbb, AutoCacheRequest request(tdbb, irq_grant14, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - XCP IN RDB$EXCEPTIONS WITH - XCP.RDB$EXCEPTION_NAME EQ object_name + XCP IN RDB$EXCEPTIONS + WITH XCP.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + XCP.RDB$EXCEPTION_NAME EQ object_name.object.c_str() { s_class = XCP.RDB$SECURITY_CLASS; default_class = ""; @@ -450,8 +454,9 @@ static void get_object_info(thread_db* tdbb, AutoCacheRequest request(tdbb, irq_grant15, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - GEN IN RDB$GENERATORS WITH - GEN.RDB$GENERATOR_NAME EQ object_name + GEN IN RDB$GENERATORS + WITH GEN.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + GEN.RDB$GENERATOR_NAME EQ object_name.object.c_str() { s_class = GEN.RDB$SECURITY_CLASS; default_class = ""; @@ -465,8 +470,9 @@ static void get_object_info(thread_db* tdbb, AutoCacheRequest request(tdbb, irq_grant16, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - FLD IN RDB$FIELDS WITH - FLD.RDB$FIELD_NAME EQ object_name + FLD IN RDB$FIELDS + WITH FLD.RDB$SCHEMA_NAME EQ object_name.schema.c_str() AND + FLD.RDB$FIELD_NAME EQ object_name.object.c_str() { s_class = FLD.RDB$SECURITY_CLASS; default_class = ""; @@ -477,6 +483,8 @@ static void get_object_info(thread_db* tdbb, } else if (obj_type == obj_database) { + fb_assert(object_name.schema.isEmpty() && object_name.object.isEmpty()); + AutoCacheRequest request(tdbb, irq_grant17, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) @@ -489,13 +497,33 @@ static void get_object_info(thread_db* tdbb, } END_FOR } + else if (obj_type == obj_schema) + { + fb_assert(object_name.object.hasData() && object_name.schema.isEmpty()); + + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + + FOR(REQUEST_HANDLE requestHandle) + SCH IN RDB$SCHEMAS + WITH SCH.RDB$SCHEMA_NAME EQ object_name.object.c_str() + { + s_class = SCH.RDB$SECURITY_CLASS; + default_class = ""; + owner = SCH.RDB$OWNER_NAME; + view = false; + } + END_FOR + } else if (obj_type == obj_blob_filter) { + fb_assert(object_name.schema.isEmpty()); + AutoCacheRequest request(tdbb, irq_grant18, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - FLT IN RDB$FILTERS WITH - FLT.RDB$FUNCTION_NAME EQ object_name + FLT IN RDB$FILTERS + WITH FLT.RDB$FUNCTION_NAME EQ object_name.object.c_str() { s_class = FLT.RDB$SECURITY_CLASS; default_class = ""; @@ -506,11 +534,13 @@ static void get_object_info(thread_db* tdbb, } else if (obj_type == obj_sql_role) { + fb_assert(object_name.schema.isEmpty()); + AutoCacheRequest request(tdbb, irq_grant19, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - ROL IN RDB$ROLES WITH - ROL.RDB$ROLE_NAME EQ object_name + ROL IN RDB$ROLES + WITH ROL.RDB$ROLE_NAME EQ object_name.object.c_str() { s_class = ROL.RDB$SECURITY_CLASS; default_class = ""; @@ -521,17 +551,46 @@ static void get_object_info(thread_db* tdbb, } else { - s_class = getSecurityClassName(obj_type); - default_class = ""; - owner = tdbb->getDatabase()->dbb_owner; - view = false; + bool noSchemaOrSchemaFound = true; + + if (bool useSchema; isDdlObject(obj_type, &useSchema) && useSchema) + { + noSchemaOrSchemaFound = false; + + fb_assert(object_name.schema.hasData()); + + static const CachedRequestId requestHandleId; + AutoCacheRequest requestHandle(tdbb, requestHandleId); + + FOR(REQUEST_HANDLE requestHandle) + SCH IN RDB$SCHEMAS + WITH SCH.RDB$SCHEMA_NAME EQ object_name.schema.c_str() + { + noSchemaOrSchemaFound = true; + } + END_FOR + + } + + if (noSchemaOrSchemaFound) + { + s_class = getSecurityClassName(obj_type); + + // FIXME: if security class can be greather than MAX_SQL_IDENTIFIER_LEN, it cannot be MetaName + if (object_name.schema.hasData()) + s_class = string(s_class.c_str()) + "$" + object_name.schema.c_str(); + + default_class = ""; + owner = tdbb->getDatabase()->dbb_owner; + view = false; + } } } static void get_user_privs(thread_db* tdbb, Acl& acl, - const TEXT* object_name, + const QualifiedName& object_name, SSHORT obj_type, const MetaName& owner, SecurityClass::flags_t public_priv) @@ -549,7 +608,7 @@ static void get_user_privs(thread_db* tdbb, SET_TDBB(tdbb); Jrd::Attachment* attachment = tdbb->getAttachment(); - MetaName user; + QualifiedName user; SSHORT user_type = -2; SecurityClass::flags_t priv = 0; @@ -557,45 +616,46 @@ static void get_user_privs(thread_db* tdbb, FOR(REQUEST_HANDLE request) PRV IN RDB$USER_PRIVILEGES - WITH PRV.RDB$RELATION_NAME EQ object_name AND - PRV.RDB$OBJECT_TYPE EQ obj_type AND - (PRV.RDB$USER NE "PUBLIC" OR PRV.RDB$USER_TYPE NE obj_user) AND - (PRV.RDB$USER NE owner.c_str() OR PRV.RDB$USER_TYPE NE obj_user) AND - ((PRV.RDB$OBJECT_TYPE NE obj_sql_role AND - PRV.RDB$FIELD_NAME MISSING) OR - (PRV.RDB$OBJECT_TYPE EQ obj_sql_role AND - PRV.RDB$GRANT_OPTION EQ WITH_ADMIN_OPTION)) - SORTED BY PRV.RDB$USER, PRV.RDB$USER_TYPE + WITH PRV.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(object_name.schema.c_str(), '') AND + PRV.RDB$RELATION_NAME EQUIV NULLIF(object_name.object.c_str(), '') AND + PRV.RDB$OBJECT_TYPE EQ obj_type AND + (PRV.RDB$USER NE "PUBLIC" OR PRV.RDB$USER_TYPE NE obj_user) AND + (PRV.RDB$USER NE owner.c_str() OR PRV.RDB$USER_TYPE NE obj_user) AND + ((PRV.RDB$OBJECT_TYPE NE obj_sql_role AND + PRV.RDB$FIELD_NAME MISSING) OR + (PRV.RDB$OBJECT_TYPE EQ obj_sql_role AND + PRV.RDB$GRANT_OPTION EQ WITH_ADMIN_OPTION)) + SORTED BY PRV.RDB$USER, PRV.RDB$USER_SCHEMA_NAME, PRV.RDB$USER_TYPE { - fb_utils::exact_name_limit(PRV.RDB$USER, sizeof(PRV.RDB$USER)); - if (user != PRV.RDB$USER || user_type != PRV.RDB$USER_TYPE) + const QualifiedName thisUser(PRV.RDB$USER, + (PRV.RDB$USER_SCHEMA_NAME.NULL ? "" : PRV.RDB$USER_SCHEMA_NAME)); + + if (user != thisUser || user_type != PRV.RDB$USER_TYPE) { - if (user.length()) - { + if (user.object.hasData()) grant_user(acl, user, user_type, priv); - } + user_type = PRV.RDB$USER_TYPE; + if (user_type == obj_user) - { priv = public_priv; - } else - { priv = 0; - } - user = PRV.RDB$USER; + + user = thisUser; } + priv |= trans_sql_priv(obj_type == obj_sql_role ? "O" : PRV.RDB$PRIVILEGE); } END_FOR - if (user.length()) + if (user.object.length()) grant_user(acl, user, user_type, priv); } static void grant_user(Acl& acl, - const MetaName& user, + const QualifiedName& user, SSHORT user_type, SecurityClass::flags_t privs) { @@ -648,19 +708,38 @@ static void grant_user(Acl& acl, case obj_privilege: CHECK_AND_MOVE(acl, id_privilege); - fb_assert(isdigit(user[0])); + fb_assert(isdigit(user.object[0])); break; default: BUGCHECK(292); // Illegal user_type - } - const UCHAR length = user.length(); + switch (user_type) + { + case obj_package_header: + case obj_procedure: + case obj_udf: + case obj_trigger: + case obj_view: + { + fb_assert(user.schema.hasData()); + + const UCHAR length = user.schema.length(); + CHECK_AND_MOVE(acl, length); + + if (length) + acl.add(reinterpret_cast(user.schema.c_str()), length); + + break; + } + } + + const UCHAR length = user.object.length(); CHECK_AND_MOVE(acl, length); - if (length) { - acl.add(reinterpret_cast(user.c_str()), length); - } + + if (length) + acl.add(reinterpret_cast(user.object.c_str()), length); if (!SCL_move_priv(privs, acl)) acl.shrink(back); @@ -669,7 +748,7 @@ static void grant_user(Acl& acl, static SecurityClass::flags_t save_field_privileges(thread_db* tdbb, Acl& relation_acl, - const TEXT* relation_name, + const QualifiedName& relation_name, const MetaName& owner, SecurityClass::flags_t public_priv, jrd_tra* transaction) @@ -693,7 +772,9 @@ static SecurityClass::flags_t save_field_privileges(thread_db* tdbb, Acl field_acl(relation_acl); const Acl acl_start(relation_acl); - MetaName field_name, user, s_class; + QualifiedName user; + MetaName field_name; + MetaName s_class; SecurityClass::flags_t aggregate_public = public_priv; SecurityClass::flags_t priv = 0; SecurityClass::flags_t field_public = 0; @@ -703,27 +784,28 @@ static SecurityClass::flags_t save_field_privileges(thread_db* tdbb, AutoRequest request2, request3; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - FLD IN RDB$RELATION_FIELDS CROSS - PRV IN RDB$USER_PRIVILEGES - OVER RDB$RELATION_NAME, RDB$FIELD_NAME - WITH PRV.RDB$OBJECT_TYPE EQ obj_relation AND - PRV.RDB$RELATION_NAME EQ relation_name AND - PRV.RDB$FIELD_NAME NOT MISSING AND - (PRV.RDB$USER NE owner.c_str() OR PRV.RDB$USER_TYPE NE obj_user) - SORTED BY PRV.RDB$FIELD_NAME, PRV.RDB$USER + FLD IN RDB$RELATION_FIELDS + CROSS PRV IN RDB$USER_PRIVILEGES OVER RDB$RELATION_NAME, RDB$FIELD_NAME + WITH PRV.RDB$RELATION_SCHEMA_NAME EQ FLD.RDB$SCHEMA_NAME AND + PRV.RDB$OBJECT_TYPE EQ obj_relation AND + PRV.RDB$RELATION_SCHEMA_NAME EQ relation_name.schema.c_str() AND + PRV.RDB$RELATION_NAME EQ relation_name.object.c_str() AND + PRV.RDB$FIELD_NAME NOT MISSING AND + (PRV.RDB$USER NE owner.c_str() OR PRV.RDB$USER_TYPE NE obj_user) + SORTED BY PRV.RDB$FIELD_NAME, PRV.RDB$USER, PRV.RDB$USER_SCHEMA_NAME { - fb_utils::exact_name_limit(PRV.RDB$USER, sizeof(PRV.RDB$USER)); - fb_utils::exact_name_limit(PRV.RDB$FIELD_NAME, sizeof(PRV.RDB$FIELD_NAME)); + const QualifiedName thisUser(PRV.RDB$USER, + (PRV.RDB$USER_SCHEMA_NAME.NULL ? "" : PRV.RDB$USER_SCHEMA_NAME)); // create a control break on field_name,user - if (user != PRV.RDB$USER || field_name != PRV.RDB$FIELD_NAME) + if (user != thisUser || field_name != PRV.RDB$FIELD_NAME) { // flush out information for old user - if (user.length()) + if (user.object.hasData()) { - if (user != "PUBLIC") + if (!(user.schema.isEmpty() && user.object == "PUBLIC")) { const SecurityClass::flags_t field_priv = public_priv | priv | squeeze_acl(field_acl, user, user_type); @@ -734,15 +816,12 @@ static SecurityClass::flags_t save_field_privileges(thread_db* tdbb, grant_user(relation_acl, user, user_type, relation_priv); } else - { field_public = field_public | public_priv | priv; - } } // initialize for new user - priv = 0; - user = PRV.RDB$USER; + user = thisUser; user_type = PRV.RDB$USER_TYPE; } @@ -766,26 +845,29 @@ static SecurityClass::flags_t save_field_privileges(thread_db* tdbb, field_name = PRV.RDB$FIELD_NAME; s_class = FLD.RDB$SECURITY_CLASS; - if (FLD.RDB$SECURITY_CLASS.NULL || s_class.length() == 0) + if (FLD.RDB$SECURITY_CLASS.NULL || s_class.isEmpty()) { bool unique = false; FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) - RFR IN RDB$RELATION_FIELDS WITH - RFR.RDB$RELATION_NAME EQ FLD.RDB$RELATION_NAME - AND RFR.RDB$FIELD_NAME EQ FLD.RDB$FIELD_NAME + RFR IN RDB$RELATION_FIELDS + WITH RFR.RDB$SCHEMA_NAME EQ FLD.RDB$SCHEMA_NAME AND + RFR.RDB$RELATION_NAME EQ FLD.RDB$RELATION_NAME AND + RFR.RDB$FIELD_NAME EQ FLD.RDB$FIELD_NAME { MODIFY RFR while (!unique) { sprintf(RFR.RDB$SECURITY_CLASS, "%s%" SQUADFORMAT, SQL_FLD_SECCLASS_PREFIX, - DPM_gen_id(tdbb, MET_lookup_generator(tdbb, SQL_SECCLASS_GENERATOR), - false, 1)); + DPM_gen_id(tdbb, + MET_lookup_generator(tdbb, QualifiedName(SQL_SECCLASS_GENERATOR, SYSTEM_SCHEMA)), + false, 1)); unique = true; FOR (REQUEST_HANDLE request3) RFR2 IN RDB$RELATION_FIELDS - WITH RFR2.RDB$SECURITY_CLASS = RFR.RDB$SECURITY_CLASS + WITH RFR2.RDB$SCHEMA_NAME = RFR.RDB$SCHEMA_NAME AND + RFR2.RDB$SECURITY_CLASS = RFR.RDB$SECURITY_CLASS { unique = false; } @@ -811,9 +893,9 @@ static SecurityClass::flags_t save_field_privileges(thread_db* tdbb, // flush out the last user's info - if (user.length()) + if (user.object.hasData()) { - if (user != "PUBLIC") + if (!(user.schema.isEmpty() && user.object == "PUBLIC")) { const SecurityClass::flags_t field_priv = public_priv | priv | squeeze_acl(field_acl, user, user_type); @@ -837,14 +919,12 @@ static SecurityClass::flags_t save_field_privileges(thread_db* tdbb, finish_security_class(field_acl, (field_public | public_priv)); save_security_class(tdbb, s_class, field_acl, transaction); - dsc desc; - desc.dsc_dtype = dtype_text; - desc.dsc_sub_type = 0; - desc.dsc_scale = 0; - desc.dsc_ttype() = ttype_metadata; - desc.dsc_address = (UCHAR *) relation_name; - desc.dsc_length = static_cast(strlen(relation_name)); - DFW_post_work(transaction, dfw_update_format, &desc, 0); + dsc schemaDesc, nameDesc; + schemaDesc.makeText((USHORT) strlen(relation_name.schema.c_str()), CS_METADATA, + (UCHAR*) relation_name.schema.c_str()); + nameDesc.makeText((USHORT) strlen(relation_name.object.c_str()), CS_METADATA, + (UCHAR*) relation_name.object.c_str()); + DFW_post_work(transaction, dfw_update_format, &nameDesc, &schemaDesc, 0); } return aggregate_public; @@ -886,7 +966,7 @@ static void save_security_class(thread_db* tdbb, bool found = false; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) CLS IN RDB$SECURITY_CLASSES - WITH CLS.RDB$SECURITY_CLASS EQ s_class.c_str() + WITH CLS.RDB$SECURITY_CLASS EQ s_class.c_str() { found = true; MODIFY CLS @@ -902,7 +982,7 @@ static void save_security_class(thread_db* tdbb, STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) CLS IN RDB$SECURITY_CLASSES { - jrd_vtof(s_class.c_str(), CLS.RDB$SECURITY_CLASS, sizeof(CLS.RDB$SECURITY_CLASS)); + jrd_vtof(s_class.c_str(), CLS.RDB$SECURITY_CLASS, sizeof(CLS.RDB$SECURITY_CLASS)); CLS.RDB$ACL = blob_id; } END_STORE @@ -962,7 +1042,7 @@ static SecurityClass::flags_t trans_sql_priv(const TEXT* privileges) } -static SecurityClass::flags_t squeeze_acl(Acl& acl, const MetaName& user, SSHORT user_type) +static SecurityClass::flags_t squeeze_acl(Acl& acl, const QualifiedName& user, SSHORT user_type) { /************************************** * @@ -992,6 +1072,7 @@ static SecurityClass::flags_t squeeze_acl(Acl& acl, const MetaName& user, SSHORT bool hit = false; while ( (c = *a++) ) + { switch (c) { case ACL_id_list: @@ -1004,42 +1085,62 @@ static SecurityClass::flags_t squeeze_acl(Acl& acl, const MetaName& user, SSHORT case id_person: if (user_type != obj_user) hit = false; - if (check_string(a, user)) + if (check_string(a, user.object)) hit = false; break; case id_sql_role: if (user_type != obj_sql_role) hit = false; - if (check_string(a, user)) + if (check_string(a, user.object)) hit = false; break; case id_view: if (user_type != obj_view) hit = false; - if (check_string(a, user)) + + if (check_string(a, user.schema)) + hit = false; + a += *a + 1; + + if (check_string(a, user.object)) hit = false; break; case id_procedure: if (user_type != obj_procedure) hit = false; - if (check_string(a, user)) + + if (check_string(a, user.schema)) + hit = false; + a += *a + 1; + + if (check_string(a, user.object)) hit = false; break; case id_function: if (user_type != obj_udf) hit = false; - if (check_string(a, user)) + + if (check_string(a, user.schema)) + hit = false; + a += *a + 1; + + if (check_string(a, user.object)) hit = false; break; case id_trigger: if (user_type != obj_trigger) hit = false; - if (check_string(a, user)) + + if (check_string(a, user.schema)) + hit = false; + a += *a + 1; + + if (check_string(a, user.object)) hit = false; break; @@ -1048,7 +1149,7 @@ static SecurityClass::flags_t squeeze_acl(Acl& acl, const MetaName& user, SSHORT hit = false; // CVC: What's the idea of calling a function whose only // result is boolean without checking it? - check_string(a, user); + check_string(a, user.object); break; case id_views: @@ -1067,20 +1168,21 @@ static SecurityClass::flags_t squeeze_acl(Acl& acl, const MetaName& user, SSHORT case id_group: if (user_type != obj_user_group) hit = false; - if (check_string(a, user)) + if (check_string(a, user.object)) hit = false; break; case id_privilege: if (user_type != obj_privilege) hit = false; - if (check_string(a, user)) + if (check_string(a, user.object)) hit = false; break; default: BUGCHECK(293); // bad ACL } + a += *a + 1; } break; @@ -1158,6 +1260,7 @@ static SecurityClass::flags_t squeeze_acl(Acl& acl, const MetaName& user, SSHORT default: BUGCHECK(293); // bad ACL } + } // remove added extra '\0' byte acl.pop(); diff --git a/src/jrd/grant_proto.h b/src/jrd/grant_proto.h index b34db32028..b1fe0ffe70 100644 --- a/src/jrd/grant_proto.h +++ b/src/jrd/grant_proto.h @@ -25,13 +25,9 @@ #define JRD_GRANT_PROTO_H #include "../common/classes/fb_string.h" +#include "../jrd/QualifiedName.h" #include "../jrd/obj.h" -namespace Jrd -{ - class DeferredWork; -} - -void GRANT_privileges(Jrd::thread_db*, const Firebird::string&, ObjectType, Jrd::jrd_tra*); +void GRANT_privileges(Jrd::thread_db*, const Jrd::QualifiedName&, ObjectType, Jrd::jrd_tra*); #endif // JRD_GRANT_PROTO_H diff --git a/src/jrd/idx.cpp b/src/jrd/idx.cpp index 5c22b9b186..f7002cac06 100644 --- a/src/jrd/idx.cpp +++ b/src/jrd/idx.cpp @@ -112,7 +112,7 @@ void IDX_check_access(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view, jrd_ { // find the corresponding primary key index - if (!MET_lookup_partner(tdbb, relation, &idx, 0)) + if (!MET_lookup_partner(tdbb, relation, &idx, {})) continue; jrd_rel* referenced_relation = MET_relation(tdbb, idx.idx_primary_relation); @@ -138,17 +138,21 @@ void IDX_check_access(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view, jrd_ const index_desc::idx_repeat* idx_desc = referenced_idx.idx_rpt; for (USHORT i = 0; i < referenced_idx.idx_count; i++, idx_desc++) { - const jrd_fld* referenced_field = - MET_get_field(referenced_relation, idx_desc->idx_field); + const SLONG ssRelationId = view ? view->rel_id : 0; + const jrd_fld* referenced_field = MET_get_field(referenced_relation, idx_desc->idx_field); + + CMP_post_access(tdbb, csb, relation->rel_security_name.schema, ssRelationId, + SCL_usage, obj_schemas, QualifiedName(relation->rel_name.schema)); + CMP_post_access(tdbb, csb, - referenced_relation->rel_security_name, - (view ? view->rel_id : 0), + referenced_relation->rel_security_name.object, ssRelationId, SCL_references, obj_relations, referenced_relation->rel_name); + CMP_post_access(tdbb, csb, referenced_field->fld_security_name, 0, SCL_references, obj_column, - referenced_field->fld_name, referenced_relation->rel_name); + referenced_relation->rel_name, referenced_field->fld_name); } CCH_RELEASE(tdbb, &referenced_window); @@ -536,8 +540,8 @@ bool IndexCreateTask::handler(WorkItem& _item) CompilerScratch* csb = NULL; Jrd::ContextPoolHolder context(tdbb, attachment->createPool()); - idx->idx_expression = static_cast (MET_parse_blob(tdbb, relation, &m_exprBlob, - &csb, &idx->idx_expression_statement, false, false)); + idx->idx_expression = static_cast (MET_parse_blob(tdbb, &relation->rel_name.schema, + relation, &m_exprBlob, &csb, &idx->idx_expression_statement, false, false)); delete csb; } @@ -549,8 +553,8 @@ bool IndexCreateTask::handler(WorkItem& _item) CompilerScratch* csb = NULL; Jrd::ContextPoolHolder context(tdbb, attachment->createPool()); - idx->idx_condition = static_cast (MET_parse_blob(tdbb, relation, &m_condBlob, - &csb, &idx->idx_condition_statement, false, false)); + idx->idx_condition = static_cast (MET_parse_blob(tdbb, &relation->rel_name.schema, relation, + &m_condBlob, &csb, &idx->idx_condition_statement, false, false)); delete csb; } @@ -826,7 +830,7 @@ int IndexCreateTask::getMaxWorkers() void IDX_create_index(thread_db* tdbb, jrd_rel* relation, index_desc* idx, - const TEXT* index_name, + const QualifiedName& index_name, USHORT* index_id, jrd_tra* transaction, SelectivityList& selectivity) @@ -848,7 +852,7 @@ void IDX_create_index(thread_db* tdbb, if (relation->rel_file) { ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_extfile_uns_op) << Arg::Str(relation->rel_name)); + Arg::Gds(isc_extfile_uns_op) << relation->rel_name.toQuotedString()); } else if (relation->isVirtual()) { @@ -879,7 +883,7 @@ void IDX_create_index(thread_db* tdbb, if (key_length >= dbb->getMaxIndexKeyLength()) { ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_keytoobig) << Arg::Str(index_name)); + Arg::Gds(isc_keytoobig) << index_name.toQuotedString()); } if (isForeign) @@ -1388,7 +1392,7 @@ void IDX_modify_check_constraints(thread_db* tdbb, while (BTR_next_index(tdbb, org_rpb->rpb_relation, transaction, &idx, &window)) { if (!(idx.idx_flags & (idx_primary | idx_unique)) || - !MET_lookup_partner(tdbb, org_rpb->rpb_relation, &idx, 0)) + !MET_lookup_partner(tdbb, org_rpb->rpb_relation, &idx, {})) { continue; } @@ -1468,7 +1472,7 @@ void IDX_modify_flag_uk_modified(thread_db* tdbb, while (BTR_next_index(tdbb, relation, transaction, &idx, &window)) { if (!(idx.idx_flags & (idx_primary | idx_unique)) || - !MET_lookup_partner(tdbb, relation, &idx, 0)) + !MET_lookup_partner(tdbb, relation, &idx, {})) { continue; } @@ -1792,7 +1796,7 @@ static idx_e check_foreign_key(thread_db* tdbb, idx_e result = idx_e_ok; - if (!MET_lookup_partner(tdbb, relation, idx, 0)) + if (!MET_lookup_partner(tdbb, relation, idx, {})) return result; jrd_rel* partner_relation = NULL; diff --git a/src/jrd/idx.h b/src/jrd/idx.h index 3fd6225144..141c866a53 100644 --- a/src/jrd/idx.h +++ b/src/jrd/idx.h @@ -30,7 +30,7 @@ /* Indices to be created */ /* Maxinum number of segments in any existing system index */ -const int INI_IDX_MAX_SEGMENTS = 3; +const int INI_IDX_MAX_SEGMENTS = 4; struct ini_idx_t { @@ -60,71 +60,85 @@ using Jrd::idx_timestamp_tz; static const struct ini_idx_t indices[] = { - // define index RDB$INDEX_0 for RDB$RELATIONS unique RDB$RELATION_NAME; - INDEX(0, rel_relations, idx_unique, 1, ODS_13_0) + // define index RDB$INDEX_0 for RDB$RELATIONS unique RDB$SCHEMA_NAME, RDB$RELATION_NAME; + INDEX(0, rel_relations, idx_unique, 2, ODS_14_0) + SEGMENT(f_rel_schema, idx_metadata), // schema name SEGMENT(f_rel_name, idx_metadata) // relation name }}, // define index RDB$INDEX_1 for RDB$RELATIONS RDB$RELATION_ID; INDEX(1, rel_relations, 0, 1, ODS_13_0) SEGMENT(f_rel_id, idx_numeric) // relation id }}, - // define index RDB$INDEX_2 for RDB$FIELDS unique RDB$FIELD_NAME; - INDEX(2, rel_fields, idx_unique, 1, ODS_13_0) + // define index RDB$INDEX_2 for RDB$FIELDS unique RDB$SCHEMA_NAME, RDB$FIELD_NAME; + INDEX(2, rel_fields, idx_unique, 2, ODS_14_0) + SEGMENT(f_fld_schema, idx_metadata), // schema name SEGMENT(f_fld_name, idx_metadata) // field name }}, - // define index RDB$INDEX_3 for RDB$RELATION_FIELDS RDB$FIELD_SOURCE; - INDEX(3, rel_rfr, 0, 1, ODS_13_0) + // define index RDB$INDEX_3 for RDB$RELATION_FIELDS RDB$FIELD_SOURCE_SCHEMA_NAME, RDB$FIELD_SOURCE; + INDEX(3, rel_rfr, 0, 2, ODS_14_0) + SEGMENT(f_rfr_field_source_schema, idx_metadata), // field source schema name SEGMENT(f_rfr_sname, idx_metadata) // field source name }}, - // define index RDB$INDEX_4 for RDB$RELATION_FIELDS RDB$RELATION_NAME; - INDEX(4, rel_rfr, 0, 1, ODS_13_0) + // define index RDB$INDEX_4 for RDB$RELATION_FIELDS RDB$SCHEMA_NAME, RDB$RELATION_NAME; + INDEX(4, rel_rfr, 0, 2, ODS_14_0) + SEGMENT(f_rfr_schema, idx_metadata), // schema name SEGMENT(f_rfr_rname, idx_metadata) // relation name in RFR }}, - // define index RDB$INDEX_5 for RDB$INDICES unique RDB$INDEX_NAME; - INDEX(5, rel_indices, idx_unique, 1, ODS_13_0) + // define index RDB$INDEX_5 for RDB$INDICES unique RDB$SCHEMA_NAME, RDB$INDEX_NAME; + INDEX(5, rel_indices, idx_unique, 2, ODS_14_0) + SEGMENT(f_idx_schema, idx_metadata), // schema name SEGMENT(f_idx_name, idx_metadata) // index name }}, - // define index RDB$INDEX_6 for RDB$INDEX_SEGMENTS RDB$INDEX_NAME; - INDEX(6, rel_segments, 0, 1, ODS_13_0) + // define index RDB$INDEX_6 for RDB$INDEX_SEGMENTS RDB$SCHEMA_NAME, RDB$INDEX_NAME; + INDEX(6, rel_segments, 0, 2, ODS_14_0) + SEGMENT(f_seg_schema, idx_metadata), // schema name SEGMENT(f_seg_name, idx_metadata) // index name in seg }}, // define index RDB$INDEX_7 for RDB$SECURITY_CLASSES unique RDB$SECURITY_CLASS; INDEX(7, rel_classes, idx_unique, 1, ODS_13_0) SEGMENT(f_cls_class, idx_metadata) // security class }}, - // define index RDB$INDEX_8 for RDB$TRIGGERS unique RDB$TRIGGER_NAME; - INDEX(8, rel_triggers, idx_unique, 1, ODS_13_0) + // define index RDB$INDEX_8 for RDB$TRIGGERS unique RDB$SCHEMA_NAME, RDB$TRIGGER_NAME; + INDEX(8, rel_triggers, idx_unique, 2, ODS_14_0) + SEGMENT(f_trg_schema, idx_metadata), // schema name SEGMENT(f_trg_name, idx_metadata) // trigger name }}, - // define index RDB$INDEX_9 for RDB$FUNCTIONS unique RDB$PACKAGE_NAME, RDB$FUNCTION_NAME; - INDEX(9, rel_funs, idx_unique, 2, ODS_13_0) + // define index RDB$INDEX_9 for RDB$FUNCTIONS unique RDB$SCHEMA_NAME, RDB$PACKAGE_NAME, RDB$FUNCTION_NAME; + INDEX(9, rel_funs, idx_unique, 3, ODS_14_0) + SEGMENT(f_fun_schema, idx_metadata), // schema name SEGMENT(f_fun_pkg_name, idx_metadata), // package name SEGMENT(f_fun_name, idx_metadata) // function name }}, - // define index RDB$INDEX_10 for RDB$FUNCTION_ARGUMENTS RDB$PACKAGE_NAME, RDB$FUNCTION_NAME; - INDEX(10, rel_args, 0, 2, ODS_13_0) + // define index RDB$INDEX_10 for RDB$FUNCTION_ARGUMENTS RDB$SCHEMA_NAME, RDB$PACKAGE_NAME, RDB$FUNCTION_NAME; + INDEX(10, rel_args, 0, 3, ODS_14_0) + SEGMENT(f_arg_schema, idx_metadata), // schema name SEGMENT(f_arg_pkg_name, idx_metadata), // package name SEGMENT(f_arg_fun_name, idx_metadata) // function name }}, - // define index RDB$INDEX_11 for RDB$GENERATORS unique RDB$GENERATOR_NAME; - INDEX(11, rel_gens, idx_unique, 1, ODS_13_0) + // define index RDB$INDEX_11 for RDB$GENERATORS unique RDB$SCHEMA_NAME, RDB$GENERATOR_NAME; + INDEX(11, rel_gens, idx_unique, 2, ODS_14_0) + SEGMENT(f_gen_schema, idx_metadata), // schema name SEGMENT(f_gen_name, idx_metadata) // Generator name }}, - // define index RDB$INDEX_12 for RDB$RELATION_CONSTRAINTS unique RDB$CONSTRAINT_NAME; - INDEX(12, rel_rcon, idx_unique, 1, ODS_13_0) + // define index RDB$INDEX_12 for RDB$RELATION_CONSTRAINTS unique RDB$SCHEMA_NAME, RDB$CONSTRAINT_NAME; + INDEX(12, rel_rcon, idx_unique, 2, ODS_14_0) + SEGMENT(f_rcon_schema, idx_metadata), // schema name SEGMENT(f_rcon_cname, idx_metadata) // constraint name }}, - // define index RDB$INDEX_13 for RDB$REF_CONSTRAINTS unique RDB$CONSTRAINT_NAME; - INDEX(13, rel_refc, idx_unique, 1, ODS_13_0) + // define index RDB$INDEX_13 for RDB$REF_CONSTRAINTS unique RDB$SCHEMA_NAME, RDB$CONSTRAINT_NAME; + INDEX(13, rel_refc, idx_unique, 2, ODS_14_0) + SEGMENT(f_refc_schema, idx_metadata), // schema name SEGMENT(f_refc_cname, idx_metadata) // constraint name }}, - // define index RDB$INDEX_14 for RDB$CHECK_CONSTRAINTS RDB$CONSTRAINT_NAME; - INDEX(14, rel_ccon, 0, 1, ODS_13_0) + // define index RDB$INDEX_14 for RDB$CHECK_CONSTRAINTS RDB$SCHEMA_NAME, RDB$CONSTRAINT_NAME; + INDEX(14, rel_ccon, 0, 2, ODS_14_0) + SEGMENT(f_ccon_schema, idx_metadata), // schema name SEGMENT(f_ccon_cname, idx_metadata) // constraint name }}, - // define index RDB$INDEX_15 for RDB$RELATION_FIELDS unique RDB$FIELD_NAME, RDB$RELATION_NAME; - INDEX(15, rel_rfr, idx_unique, 2, ODS_13_0) + // define index RDB$INDEX_15 for RDB$RELATION_FIELDS unique RDB$FIELD_NAME, RDB$SCHEMA_NAME, RDB$RELATION_NAME; + INDEX(15, rel_rfr, idx_unique, 3, ODS_14_0) SEGMENT(f_rfr_fname, idx_metadata), // field name + SEGMENT(f_rfr_schema, idx_metadata), // schema name SEGMENT(f_rfr_rname, idx_metadata) // relation name }}, // define index RDB$INDEX_16 for RDB$FORMATS RDB$RELATION_ID, RDB$FORMAT; @@ -137,23 +151,27 @@ static const struct ini_idx_t indices[] = SEGMENT(f_flt_input, idx_numeric), // input subtype SEGMENT(f_flt_output, idx_numeric) // output subtype }}, - // define index RDB$INDEX_18 for RDB$PROCEDURE_PARAMETERS unique RDB$PACKAGE_NAME, + // define index RDB$INDEX_18 for RDB$PROCEDURE_PARAMETERS unique RDB$SCHEMA_NAME, RDB$PACKAGE_NAME, // RDB$PROCEDURE_NAME, RDB$PARAMETER_NAME; - INDEX(18, rel_prc_prms, idx_unique, 3, ODS_13_0) + INDEX(18, rel_prc_prms, idx_unique, 4, ODS_14_0) + SEGMENT(f_prm_schema, idx_metadata), // schema name SEGMENT(f_prm_pkg_name, idx_metadata), // package name SEGMENT(f_prm_procedure, idx_metadata), // procedure name SEGMENT(f_prm_name, idx_metadata) // parameter name }}, - // define index RDB$INDEX_19 for RDB$CHARACTER_SETS unique RDB$CHARACTER_SET_NAME; - INDEX(19, rel_charsets, idx_unique, 1, ODS_13_0) + // define index RDB$INDEX_19 for RDB$CHARACTER_SETS unique RDB$SCHEMA_NAME, RDB$CHARACTER_SET_NAME; + INDEX(19, rel_charsets, idx_unique, 2, ODS_14_0) + SEGMENT(f_cs_schema, idx_metadata), // schema name SEGMENT(f_cs_cs_name, idx_metadata) // character set name }}, - // define index RDB$INDEX_20 for RDB$COLLATIONS unique RDB$COLLATION_NAME; - INDEX(20, rel_collations, idx_unique, 1, ODS_13_0) + // define index RDB$INDEX_20 for RDB$COLLATIONS unique RDB$SCHEMA_NAME, RDB$COLLATION_NAME; + INDEX(20, rel_collations, idx_unique, 2, ODS_14_0) + SEGMENT(f_coll_schema, idx_metadata), // schema name SEGMENT(f_coll_name, idx_metadata) // collation name }}, - // define index RDB$INDEX_21 for RDB$PROCEDURES unique RDB$PACKAGE_NAME, RDB$PROCEDURE_NAME; - INDEX(21, rel_procedures, idx_unique, 2, ODS_13_0) + // define index RDB$INDEX_21 for RDB$PROCEDURES unique RDB$SCHEMA_NAME, RDB$PACKAGE_NAME, RDB$PROCEDURE_NAME; + INDEX(21, rel_procedures, idx_unique, 3, ODS_14_0) + SEGMENT(f_prc_schema, idx_metadata), // schema name SEGMENT(f_prc_pkg_name, idx_metadata), // package name SEGMENT(f_prc_name, idx_metadata) // procedure name }}, @@ -161,8 +179,9 @@ static const struct ini_idx_t indices[] = INDEX(22, rel_procedures, idx_unique, 1, ODS_13_0) SEGMENT(f_prc_id, idx_numeric) // procedure id }}, - // define index RDB$INDEX_23 for RDB$EXCEPTIONS unique RDB$EXCEPTION_NAME; - INDEX(23, rel_exceptions, idx_unique, 1, ODS_13_0) + // define index RDB$INDEX_23 for RDB$EXCEPTIONS unique RDB$SCHEMA_NAME, RDB$EXCEPTION_NAME; + INDEX(23, rel_exceptions, idx_unique, 2, ODS_14_0) + SEGMENT(f_xcp_schema, idx_metadata), // schema name SEGMENT(f_xcp_name, idx_metadata) // exception name }}, // define index RDB$INDEX_24 for RDB$EXCEPTIONS unique RDB$EXCEPTION_NUMBER; @@ -178,76 +197,91 @@ static const struct ini_idx_t indices[] = SEGMENT(f_coll_id, idx_numeric), // collation id SEGMENT(f_coll_cs_id, idx_numeric) // character set id }}, - // define index RDB$INDEX_27 for RDB$DEPENDENCIES RDB$DEPENDENT_NAME, RDB$DEPENDENT_TYPE; - INDEX(27, rel_dpds, 0, 2, ODS_13_0) + // define index RDB$INDEX_27 for RDB$DEPENDENCIES RDB$DEPENDENT_SCHEMA_NAME, RDB$DEPENDENT_NAME, RDB$DEPENDENT_TYPE; + INDEX(27, rel_dpds, 0, 3, ODS_14_0) + SEGMENT(f_dpd_schema, idx_metadata), // dependent schema name SEGMENT(f_dpd_name, idx_metadata), // dependent name SEGMENT(f_dpd_type, idx_numeric) // dependent type }}, - // define index RDB$INDEX_28 for RDB$DEPENDENCIES RDB$DEPENDED_ON_NAME, RDB$DEPENDED_ON_TYPE, RDB$FIELD_NAME; - INDEX(28, rel_dpds, 0, 3, ODS_13_0) + // define index RDB$INDEX_28 for RDB$DEPENDENCIES RDB$DEPENDED_ON_SCHEMA_NAME, RDB$DEPENDED_ON_NAME, + // RDB$DEPENDED_ON_TYPE, RDB$FIELD_NAME; + INDEX(28, rel_dpds, 0, 4, ODS_14_0) + SEGMENT(f_dpd_o_schema, idx_metadata), // dependent on schema name SEGMENT(f_dpd_o_name, idx_metadata), // dependent on name SEGMENT(f_dpd_o_type, idx_numeric), // dependent on type SEGMENT(f_dpd_f_name, idx_metadata) // field name }}, - // define index RDB$INDEX_29 for RDB$USER_PRIVILEGES RDB$RELATION_NAME; - INDEX(29, rel_priv, 0, 1, ODS_13_0) - SEGMENT(f_prv_rname, idx_metadata) // relation name + // define index RDB$INDEX_29 for RDB$USER_PRIVILEGES RDB$RELATION_SCHEMA_NAME, RDB$RELATION_NAME; + INDEX(29, rel_priv, 0, 2, ODS_14_0) + SEGMENT(f_prv_rel_schema, idx_metadata), // relation schema name + SEGMENT(f_prv_rname, idx_metadata) // relation name }}, - // define index RDB$INDEX_30 for RDB$USER_PRIVILEGES RDB$USER; - INDEX(30, rel_priv, 0, 1, ODS_13_0) - SEGMENT(f_prv_user, idx_metadata) // granted user + // define index RDB$INDEX_30 for RDB$USER_PRIVILEGES RDB$USER_SCHEMA_NAME, RDB$USER; + INDEX(30, rel_priv, 0, 2, ODS_14_0) + SEGMENT(f_prv_user_schema, idx_metadata), // granted user schema name + SEGMENT(f_prv_user, idx_metadata) // granted user }}, - // define index RDB$INDEX_31 for RDB$INDICES RDB$RELATION_NAME; - INDEX(31, rel_indices, 0, 1, ODS_13_0) + // define index RDB$INDEX_31 for RDB$INDICES RDB$SCHEMA_NAME, RDB$RELATION_NAME; + INDEX(31, rel_indices, 0, 2, ODS_14_0) + SEGMENT(f_idx_schema, idx_metadata), // schema name SEGMENT(f_idx_relation, idx_metadata) // indexed relation }}, // define index RDB$INDEX_32 for RDB$TRANSACTIONS unique RDB$TRANSACTION_ID; INDEX(32, rel_trans, idx_unique, 1, ODS_13_0) SEGMENT(f_trn_id, idx_numeric) // transaction id }}, - // define index RDB$INDEX_33 for RDB$VIEW_RELATIONS RDB$VIEW_NAME; - INDEX(33, rel_vrel, 0, 1, ODS_13_0) + // define index RDB$INDEX_33 for RDB$VIEW_RELATIONS RDB$SCHEMA_NAME, RDB$VIEW_NAME; + INDEX(33, rel_vrel, 0, 2, ODS_14_0) + SEGMENT(f_vrl_schema, idx_metadata), // schema name SEGMENT(f_vrl_vname, idx_metadata) // view name }}, - // define index RDB$INDEX_34 for RDB$VIEW_RELATIONS RDB$RELATION_NAME; - INDEX(34, rel_vrel, 0, 1, ODS_13_0) + // define index RDB$INDEX_34 for RDB$VIEW_RELATIONS RDB$RELATION_SCHEMA_NAME, RDB$RELATION_NAME; + INDEX(34, rel_vrel, 0, 2, ODS_14_0) + SEGMENT(f_vrl_rname_schema, idx_metadata), // schema name SEGMENT(f_vrl_rname, idx_metadata) // base relation name }}, - // define index RDB$INDEX_35 for RDB$TRIGGER_MESSAGES RDB$TRIGGER_NAME; - INDEX(35, rel_msgs, 0, 1, ODS_13_0) + // define index RDB$INDEX_35 for RDB$TRIGGER_MESSAGES RDB$SCHEMA_NAME, RDB$TRIGGER_NAME; + INDEX(35, rel_msgs, 0, 2, ODS_14_0) + SEGMENT(f_msg_schema, idx_metadata), // schema name SEGMENT(f_msg_trigger, idx_metadata) // trigger name }}, - // define index RDB$INDEX_36 for RDB$FIELD_DIMENSIONS RDB$FIELD_NAME; - INDEX(36, rel_dims, 0, 1, ODS_13_0) + // define index RDB$INDEX_36 for RDB$FIELD_DIMENSIONS RDB$SCHEMA_NAME, RDB$FIELD_NAME; + INDEX(36, rel_dims, 0, 2, ODS_14_0) + SEGMENT(f_dims_schema, idx_metadata), // schema name SEGMENT(f_dims_fname, idx_metadata) // array name }}, // define index RDB$INDEX_37 for RDB$TYPES RDB$TYPE_NAME; INDEX(37, rel_types, 0, 1, ODS_13_0) SEGMENT(f_typ_name, idx_metadata) // type name }}, - // define index RDB$INDEX_38 for RDB$TRIGGERS RDB$RELATION_NAME; - INDEX(38, rel_triggers, 0, 1, ODS_13_0) + // define index RDB$INDEX_38 for RDB$TRIGGERS RDB$SCHEMA_NAME, RDB$RELATION_NAME; + INDEX(38, rel_triggers, 0, 2, ODS_14_0) + SEGMENT(f_trg_schema, idx_metadata), // schema name SEGMENT(f_trg_rname, idx_metadata) // triggered relation }}, // define index RDB$INDEX_39 for RDB$ROLES unique RDB$ROLE_NAME; INDEX(39, rel_roles, idx_unique, 1, ODS_13_0) SEGMENT(f_rol_name, idx_metadata) // role name }}, - // define index RDB$INDEX_40 for RDB$CHECK_CONSTRAINTS RDB$TRIGGER_NAME; - INDEX(40, rel_ccon, 0, 1, ODS_13_0) + // define index RDB$INDEX_40 for RDB$CHECK_CONSTRAINTS RDB$SCHEMA_NAME, RDB$TRIGGER_NAME; + INDEX(40, rel_ccon, 0, 2, ODS_14_0) + SEGMENT(f_ccon_schema, idx_metadata), // schema name SEGMENT(f_ccon_tname, idx_metadata) // trigger name }}, - // define index RDB$INDEX_41 for RDB$INDICES RDB$FOREIGN_KEY; - INDEX(41, rel_indices, 0, 1, ODS_13_0) - SEGMENT(f_idx_foreign, idx_metadata) // foreign key name + // define index RDB$INDEX_41 for RDB$INDICES RDB$FOREIGN_KEY_SCHEMA_NAME, RDB$FOREIGN_KEY; + INDEX(41, rel_indices, 0, 2, ODS_14_0) + SEGMENT(f_idx_foreign_schema, idx_metadata), // foreign key schema name + SEGMENT(f_idx_foreign, idx_metadata) // foreign key name }}, - // define index RDB$INDEX_42 for RDB$RELATION_CONSTRAINTS RDB$RELATION_NAME, RDB$CONSTRAINT_TYPE; - INDEX(42, rel_rcon, 0, 2, ODS_13_0) + // define index RDB$INDEX_42 for RDB$RELATION_CONSTRAINTS RDB$SCHEMA_NAME, RDB$RELATION_NAME, RDB$CONSTRAINT_TYPE; + INDEX(42, rel_rcon, 0, 3, ODS_14_0) + SEGMENT(f_rcon_schema, idx_metadata), // schema name SEGMENT(f_rcon_rname, idx_metadata), // relation name SEGMENT(f_rcon_ctype, idx_metadata) // constraint type }}, - // define index RDB$INDEX_43 for RDB$RELATION_CONSTRAINTS RDB$INDEX_NAME; - INDEX(43, rel_rcon, 0, 1, ODS_13_0) + // define index RDB$INDEX_43 for RDB$RELATION_CONSTRAINTS RDB$SCHEMA_NAME, RDB$INDEX_NAME; + INDEX(43, rel_rcon, 0, 2, ODS_14_0) + SEGMENT(f_rcon_schema, idx_metadata), // schema name SEGMENT(f_rcon_iname, idx_metadata), // index name }}, // define index RDB$INDEX_44 for RDB$BACKUP_HISTORY RDB$LEVEL, RDB$BACKUP_ID; @@ -263,27 +297,32 @@ static const struct ini_idx_t indices[] = INDEX(46, rel_gens, idx_unique, 1, ODS_13_0) SEGMENT(f_gen_id, idx_numeric) // generator id }}, - // define index RDB$INDEX_47 for RDB$PACKAGES unique RDB$PACKAGE_NAME; - INDEX(47, rel_packages, idx_unique, 1, ODS_13_0) + // define index RDB$INDEX_47 for RDB$PACKAGES unique RDB$SCHEMA_NAME, RDB$PACKAGE_NAME; + INDEX(47, rel_packages, idx_unique, 2, ODS_14_0) + SEGMENT(f_pkg_schema, idx_metadata), // schema name SEGMENT(f_pkg_name, idx_metadata) // package name }}, - // define index RDB$INDEX_48 for RDB$PROCEDURE_PARAMETERS RDB$FIELD_SOURCE; - INDEX(48, rel_prc_prms, 0, 1, ODS_13_0) - SEGMENT(f_prm_sname, idx_metadata) // field source name + // define index RDB$INDEX_48 for RDB$PROCEDURE_PARAMETERS RDB$FIELD_SOURCE_SCHEMA_NAME, RDB$FIELD_SOURCE; + INDEX(48, rel_prc_prms, 0, 2, ODS_14_0) + SEGMENT(f_prm_field_source_schema, idx_metadata), // field source schema name + SEGMENT(f_prm_sname, idx_metadata) // field source name }}, - // define index RDB$INDEX_49 for RDB$FUNCTION_ARGUMENTS RDB$FIELD_SOURCE; - INDEX(49, rel_args, 0, 1, ODS_13_0) - SEGMENT(f_arg_sname, idx_metadata) // field source name + // define index RDB$INDEX_49 for RDB$FUNCTION_ARGUMENTS RDB$FIELD_SOURCE_SCHEMA_NAME, RDB$FIELD_SOURCE; + INDEX(49, rel_args, 0, 2, ODS_14_0) + SEGMENT(f_arg_field_source_schema, idx_metadata), // field source schema name + SEGMENT(f_arg_sname, idx_metadata) // field source name }}, - // define index RDB$INDEX_50 for RDB$PROCEDURE_PARAMETERS RDB$RELATION_NAME, RDB$FIELD_NAME; - INDEX(50, rel_prc_prms, 0, 2, ODS_13_0) - SEGMENT(f_prm_rname, idx_metadata), // relation name - SEGMENT(f_prm_fname, idx_metadata) // field name + // define index RDB$INDEX_50 for RDB$PROCEDURE_PARAMETERS RDB$SCHEMA_NAME, RDB$RELATION_NAME, RDB$FIELD_NAME; + INDEX(50, rel_prc_prms, 0, 3, ODS_14_0) + SEGMENT(f_prm_rel_schema, idx_metadata), // relation schema name + SEGMENT(f_prm_rname, idx_metadata), // relation name + SEGMENT(f_prm_fname, idx_metadata) // field name }}, - // define index RDB$INDEX_51 for RDB$FUNCTION_ARGUMENTS RDB$RELATION_NAME, RDB$FIELD_NAME; - INDEX(51, rel_args, 0, 2, ODS_13_0) - SEGMENT(f_arg_rname, idx_metadata), // relation name - SEGMENT(f_arg_fname, idx_metadata) // field name + // define index RDB$INDEX_51 for RDB$FUNCTION_ARGUMENTS RDB$SCHEMA_NAME, RDB$RELATION_NAME, RDB$FIELD_NAME; + INDEX(51, rel_args, 0, 3, ODS_14_0) + SEGMENT(f_arg_rel_schema, idx_metadata), // relation schema name + SEGMENT(f_arg_rname, idx_metadata), // relation name + SEGMENT(f_arg_fname, idx_metadata) // field name }}, // define index RDB$INDEX_52 for RDB$AUTH_MAPPING RDB$MAP_NAME; INDEX(52, rel_auth_mapping, 0, 1, ODS_13_0) @@ -301,15 +340,21 @@ static const struct ini_idx_t indices[] = INDEX(55, rel_pubs, idx_unique, 1, ODS_13_0) SEGMENT(f_pub_name, idx_string) // publication name }}, - // define index RDB$INDEX_56 for RDB$PUBLICATION_TABLES unique RDB$TABLE_NAME, RDB$PUBLICATION_NAME; - INDEX(56, rel_pub_tables, idx_unique, 2, ODS_13_0) - SEGMENT(f_pubtab_tab_name, idx_string), // table name - SEGMENT(f_pubtab_pub_name, idx_string) // publication name + // define index RDB$INDEX_56 for RDB$PUBLICATION_TABLES unique RDB$TABLE_SCHEMA_NAME, + // RDB$TABLE_NAME, RDB$PUBLICATION_NAME; + INDEX(56, rel_pub_tables, idx_unique, 3, ODS_14_0) + SEGMENT(f_pubtab_tab_schema, idx_metadata), // table schema name + SEGMENT(f_pubtab_tab_name, idx_metadata), // table name + SEGMENT(f_pubtab_pub_name, idx_metadata) // publication name }}, // define index RDB$INDEX_57 for RDB$BACKUP_HISTORY RDB$TIMESTAMP; INDEX(57, rel_backup_history, idx_descending, 1, ODS_13_1) SEGMENT(f_backup_time, idx_timestamp_tz) // backup timestamp }}, + // define index RDB$INDEX_58 for RDB$SCHEMAS unique RDB$SCHEMA_NAME; + INDEX(58, rel_schemas, idx_unique, 1, ODS_14_0) + SEGMENT(f_sch_schema, idx_metadata) // schema name + }}, }; #define SYSTEM_INDEX_COUNT FB_NELEM(indices) diff --git a/src/jrd/idx_proto.h b/src/jrd/idx_proto.h index c45b43d5b0..1931a0e16f 100644 --- a/src/jrd/idx_proto.h +++ b/src/jrd/idx_proto.h @@ -41,7 +41,7 @@ namespace Jrd void IDX_check_access(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::jrd_rel*, Jrd::jrd_rel*); bool IDX_check_master_types (Jrd::thread_db*, Jrd::index_desc&, Jrd::jrd_rel*, int&); -void IDX_create_index(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::index_desc*, const TEXT*, +void IDX_create_index(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::index_desc*, const Jrd::QualifiedName&, USHORT*, Jrd::jrd_tra*, Jrd::SelectivityList&); Jrd::IndexBlock* IDX_create_index_block(Jrd::thread_db*, Jrd::jrd_rel*, USHORT); void IDX_delete_index(Jrd::thread_db*, Jrd::jrd_rel*, USHORT); diff --git a/src/jrd/ini.epp b/src/jrd/ini.epp index 03413fc8d0..1a5c0a2193 100644 --- a/src/jrd/ini.epp +++ b/src/jrd/ini.epp @@ -132,7 +132,7 @@ namespace } void storeGrant(thread_db* tdbb, const char* user, USHORT user_type, - const char* object, USHORT object_type, const char* prvl) + const QualifiedName& object, USHORT object_type, const char* prvl, bool useOwnerGrantor = false) { const auto attachment = tdbb->getAttachment(); const auto transaction = tdbb->getTransaction(); @@ -145,14 +145,30 @@ namespace PRIV IN RDB$USER_PRIVILEGES { PAD(user, PRIV.RDB$USER); - PAD(object, PRIV.RDB$RELATION_NAME); + + if (object.schema.hasData()) + { + PAD(object.schema.c_str(), PRIV.RDB$RELATION_SCHEMA_NAME); + PRIV.RDB$RELATION_SCHEMA_NAME.NULL = FALSE; + } + else + PRIV.RDB$RELATION_SCHEMA_NAME.NULL = TRUE; + + PAD(object.object.c_str(), PRIV.RDB$RELATION_NAME); PRIV.RDB$FIELD_NAME.NULL = TRUE; PRIV.RDB$PRIVILEGE[0] = *prvl++; PRIV.RDB$PRIVILEGE[1] = 0; PRIV.RDB$GRANT_OPTION = 0; PRIV.RDB$USER_TYPE = user_type; PRIV.RDB$OBJECT_TYPE = object_type; - PRIV.RDB$GRANTOR.NULL = TRUE; + + if (useOwnerGrantor) + { + PAD(attachment->getUserName().c_str(), PRIV.RDB$GRANTOR); + PRIV.RDB$GRANTOR.NULL = FALSE; + } + else + PRIV.RDB$GRANTOR.NULL = TRUE; } END_STORE } @@ -193,8 +209,10 @@ namespace UCHAR buffer[FB_MAX_ACL_SIZE]; ULONG length = 0; - private: + protected: const MetaName userName; + + private: AutoRequest& reqAddSC; }; @@ -265,51 +283,32 @@ namespace const auto userName = getOwnerName(); - for (int cnt = 0; cnt < 6; cnt++) + for (auto privilege = ALL_PRIVILEGES; *privilege; ++privilege) { - STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) - PRIV IN RDB$USER_PRIVILEGES + for (int i = 0; i <= (*privilege == 'S' ? 1 : 0); ++i) { - switch (cnt) + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES { - case 0: - strcpy(PRIV.RDB$USER, userName); - PRIV.RDB$PRIVILEGE[0] = 'S'; - PRIV.RDB$GRANT_OPTION = WITH_GRANT_OPTION; - break; - case 1: - strcpy(PRIV.RDB$USER, userName); - PRIV.RDB$PRIVILEGE[0] = 'I'; - PRIV.RDB$GRANT_OPTION = WITH_GRANT_OPTION; - break; - case 2: - strcpy(PRIV.RDB$USER, userName); - PRIV.RDB$PRIVILEGE[0] = 'U'; - PRIV.RDB$GRANT_OPTION = WITH_GRANT_OPTION; - break; - case 3: - strcpy(PRIV.RDB$USER, userName); - PRIV.RDB$PRIVILEGE[0] = 'D'; - PRIV.RDB$GRANT_OPTION = WITH_GRANT_OPTION; - break; - case 4: - strcpy(PRIV.RDB$USER, userName); - PRIV.RDB$PRIVILEGE[0] = 'R'; - PRIV.RDB$GRANT_OPTION = WITH_GRANT_OPTION; - break; - default: - strcpy(PRIV.RDB$USER, "PUBLIC"); - PRIV.RDB$PRIVILEGE[0] = 'S'; - PRIV.RDB$GRANT_OPTION = 0; - break; - } + PRIV.RDB$PRIVILEGE[0] = *privilege; + PRIV.RDB$PRIVILEGE[1] = 0; - PRIV.RDB$PRIVILEGE[1] = 0; - PRIV.RDB$GRANTOR.NULL = TRUE; - strcpy(PRIV.RDB$RELATION_NAME, relName); - PRIV.RDB$FIELD_NAME.NULL = TRUE; - PRIV.RDB$USER_TYPE = obj_user; - PRIV.RDB$OBJECT_TYPE = obj_relation; + strcpy(PRIV.RDB$RELATION_SCHEMA_NAME, SYSTEM_SCHEMA); + strcpy(PRIV.RDB$RELATION_NAME, relName); + PRIV.RDB$USER_TYPE = obj_user; + PRIV.RDB$OBJECT_TYPE = obj_relation; + + if (i == 0) + { + strcpy(PRIV.RDB$USER, userName); + PRIV.RDB$GRANT_OPTION = WITH_GRANT_OPTION; + } + else + { + strcpy(PRIV.RDB$USER, "PUBLIC"); + PRIV.RDB$GRANT_OPTION = 0; + } + } } END_STORE } @@ -417,6 +416,7 @@ namespace PRIV IN RDB$USER_PRIVILEGES { PAD(users[i], PRIV.RDB$USER); + PAD(SYSTEM_SCHEMA, PRIV.RDB$RELATION_SCHEMA_NAME); PAD(objName, PRIV.RDB$RELATION_NAME); PRIV.RDB$PRIVILEGE[0] = *privileges; PRIV.RDB$PRIVILEGE[1] = 0; @@ -532,11 +532,7 @@ namespace const UCHAR DDL_OWNER_ACL[] = {ACL_priv_list, priv_control, priv_alter, priv_drop, ACL_end}; - const UCHAR DDL_PUBLIC_ACL[] = - {ACL_priv_list, ACL_end}; - - fb_assert(sizeof(buffer) >= 8 + ownerNameLength + - sizeof(DDL_OWNER_ACL) + sizeof(DDL_PUBLIC_ACL)); + fb_assert(sizeof(buffer) >= 6 + ownerNameLength + sizeof(DDL_OWNER_ACL)); UCHAR* acl = buffer; *acl++ = ACL_version; @@ -552,11 +548,6 @@ namespace memcpy(acl, DDL_OWNER_ACL, sizeof(DDL_OWNER_ACL)); acl += sizeof(DDL_OWNER_ACL); - *acl++ = ACL_id_list; - *acl++ = ACL_end; - memcpy(acl, DDL_PUBLIC_ACL, sizeof(DDL_PUBLIC_ACL)); - acl += sizeof(DDL_PUBLIC_ACL); - *acl++ = ACL_end; // Extra terminator to avoid scl.epp:walk_acl() missing the end length = acl - buffer; @@ -569,8 +560,30 @@ namespace for (int obj = obj_database + 1; obj < obj_type_MAX; obj++) { - if (isDdlObject(obj)) - addSecurityClass(tdbb, getSecurityClassName(obj)); + if (bool useSchema; isDdlObject(obj, &useSchema)) + { + if (useSchema) + { + if (!attachment->isGbak() || !(attachment->att_flags & ATT_gbak_restore_has_schema)) + { + storeGrant(tdbb, userName.c_str(), obj_user, + QualifiedName(getSecurityClassName(obj), PUBLIC_SCHEMA), + obj, ALL_DDL_PRIVILEGES, true); + + addSecurityClass(tdbb, MetaName(string(getSecurityClassName(obj)) + "$" + PUBLIC_SCHEMA)); + } + + addSecurityClass(tdbb, MetaName(string(getSecurityClassName(obj)) + "$" + SYSTEM_SCHEMA)); + } + else + { + storeGrant(tdbb, userName.c_str(), obj_user, + QualifiedName(getSecurityClassName(obj)), + obj, ALL_DDL_PRIVILEGES, false); + + addSecurityClass(tdbb, getSecurityClassName(obj)); + } + } } MetaName securityClass; @@ -579,6 +592,8 @@ namespace addSecurityClass(tdbb, securityClass); + handle.reset(); + FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) DB IN RDB$DATABASE { @@ -593,7 +608,6 @@ namespace private: AutoRequest handle; }; - }; // namespace static void store_admin_role(thread_db*, const MetaName&, RoleSecurity&); @@ -645,6 +659,9 @@ void INI_format(thread_db* tdbb, const string& charset) // Store RELATIONS and RELATION_FIELDS + dsc schemaDesc; + schemaDesc.makeText(strlen(SYSTEM_SCHEMA), CS_METADATA, (UCHAR*) SYSTEM_SCHEMA); + AutoRequest handle2; for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1) @@ -680,7 +697,7 @@ void INI_format(thread_db* tdbb, const string& charset) { dsc desc; desc.makeText(static_cast(strlen(relName)), CS_METADATA, (UCHAR*) relName); - DFW_post_work(transaction, dfw_update_format, &desc, 0); + DFW_post_work(transaction, dfw_update_format, &desc, &schemaDesc, 0); } } } @@ -699,16 +716,73 @@ void INI_format(thread_db* tdbb, const string& charset) handle.reset(); // Uppercase charset name - MetaName charSetName(charset.hasData() ? charset : DEFAULT_DB_CHARACTER_SET_NAME); + auto charSetName = QualifiedMetaString::parseSchemaObject( + charset.hasData() ? charset.c_str() : DEFAULT_DB_CHARACTER_SET_NAME); + + if (charSetName.schema.isEmpty()) + charSetName.schema = SYSTEM_SCHEMA; STORE(REQUEST_HANDLE handle) X IN RDB$DATABASE { X.RDB$RELATION_ID = (int) USER_DEF_REL_INIT_ID; - PAD(charSetName, X.RDB$CHARACTER_SET_NAME); - X.RDB$CHARACTER_SET_NAME.NULL = FALSE; + PAD(charSetName.object.c_str(), X.RDB$CHARACTER_SET_NAME); + PAD(charSetName.schema.c_str(), X.RDB$CHARACTER_SET_SCHEMA_NAME); } END_STORE + // Store SYSTEM schema + + handle.reset(); + + STORE(REQUEST_HANDLE handle) SCH IN RDB$SCHEMAS + { + PAD(SYSTEM_SCHEMA, SCH.RDB$SCHEMA_NAME); + PAD(ownerName, SCH.RDB$OWNER_NAME); + SCH.RDB$SYSTEM_FLAG = RDB_system; + PAD(SYSTEM_SCHEMA, SCH.RDB$CHARACTER_SET_SCHEMA_NAME); + PAD("UTF8", SCH.RDB$CHARACTER_SET_NAME); + + const auto securityClass = nonRelSec.storeSecurityClass(tdbb); + PAD(securityClass, SCH.RDB$SECURITY_CLASS); + } + END_STORE + + storeGrant(tdbb, attachment->getUserName().c_str(), obj_user, QualifiedName(SYSTEM_SCHEMA), + obj_schema, USAGE_PRIVILEGES, false); + + storeGrant(tdbb, "PUBLIC", obj_user, QualifiedName(SYSTEM_SCHEMA), + obj_schema, USAGE_PRIVILEGES, false); + + GRANT_privileges(tdbb, QualifiedName(SYSTEM_SCHEMA), obj_schema, transaction); + + if (!attachment->isGbak() || !(attachment->att_flags & ATT_gbak_restore_has_schema)) + { + // Store PUBLIC schema + + handle.reset(); + + STORE(REQUEST_HANDLE handle) SCH IN RDB$SCHEMAS + { + PAD(PUBLIC_SCHEMA, SCH.RDB$SCHEMA_NAME); + PAD(ownerName, SCH.RDB$OWNER_NAME); + SCH.RDB$SYSTEM_FLAG = 0; + PAD(charSetName.schema.c_str(), SCH.RDB$CHARACTER_SET_SCHEMA_NAME); + PAD(charSetName.object.c_str(), SCH.RDB$CHARACTER_SET_NAME); + + const auto securityClass = nonRelSec.storeSecurityClass(tdbb); + PAD(securityClass, SCH.RDB$SECURITY_CLASS); + } + END_STORE + + storeGrant(tdbb, attachment->getUserName().c_str(), obj_user, QualifiedName(PUBLIC_SCHEMA), + obj_schema, USAGE_PRIVILEGES, true); + + storeGrant(tdbb, "PUBLIC", obj_user, QualifiedName(PUBLIC_SCHEMA), + obj_schema, USAGE_PRIVILEGES, true); + + GRANT_privileges(tdbb, QualifiedName(PUBLIC_SCHEMA), obj_schema, transaction); + } + // Create indices for system relations store_indices(tdbb); @@ -803,16 +877,19 @@ void INI_format(thread_db* tdbb, const string& charset) MetaName buf; buf.printf("%d", USE_NBACKUP_UTILITY); - storeGrant(tdbb, buf.c_str(), obj_privilege, "RDB$BACKUP_HISTORY", obj_relation, "SIUDR"); - GRANT_privileges(tdbb, "RDB$BACKUP_HISTORY", obj_relation, transaction); + storeGrant(tdbb, buf.c_str(), obj_privilege, QualifiedName("RDB$BACKUP_HISTORY", SYSTEM_SCHEMA), + obj_relation, ALL_PRIVILEGES); + GRANT_privileges(tdbb, QualifiedName("RDB$BACKUP_HISTORY", SYSTEM_SCHEMA), obj_relation, transaction); buf.printf("%d", CREATE_USER_TYPES); - storeGrant(tdbb, buf.c_str(), obj_privilege, "RDB$TYPES", obj_relation, "SIUDR"); - GRANT_privileges(tdbb, "RDB$TYPES", obj_relation, transaction); + storeGrant(tdbb, buf.c_str(), obj_privilege, QualifiedName("RDB$TYPES", SYSTEM_SCHEMA), + obj_relation, ALL_PRIVILEGES); + GRANT_privileges(tdbb, QualifiedName("RDB$TYPES", SYSTEM_SCHEMA), obj_relation, transaction); buf.printf("%d", GRANT_REVOKE_ANY_DDL_RIGHT); - storeGrant(tdbb, buf.c_str(), obj_privilege, "RDB$DB_CREATORS", obj_relation, "SIUDR"); - GRANT_privileges(tdbb, "RDB$DB_CREATORS", obj_relation, transaction); + storeGrant(tdbb, buf.c_str(), obj_privilege, QualifiedName("RDB$DB_CREATORS", SYSTEM_SCHEMA), + obj_relation, ALL_PRIVILEGES); + GRANT_privileges(tdbb, QualifiedName("RDB$DB_CREATORS", SYSTEM_SCHEMA), obj_relation, transaction); DFW_perform_work(tdbb, transaction); @@ -839,7 +916,7 @@ void INI_init(thread_db* tdbb) jrd_rel* relation = MET_relation(tdbb, relfld[RFLD_R_ID]); relation->rel_flags |= REL_system; relation->rel_flags |= MET_get_rel_flags_from_TYPE(relfld[RFLD_R_TYPE]); - relation->rel_name = names[relfld[RFLD_R_NAME]]; + relation->rel_name = QualifiedName(names[relfld[RFLD_R_NAME]], SYSTEM_SCHEMA); HalfStaticArray fieldNames; for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH) @@ -994,7 +1071,7 @@ void INI_init_dsql(thread_db* tdbb, dsql_dbb* database) dsql_rel* relation = FB_NEW_POOL(database->dbb_pool) dsql_rel(database->dbb_pool); relation->rel_id = relfld[RFLD_R_ID]; - relation->rel_name = names[relfld[RFLD_R_NAME]]; + relation->rel_name = QualifiedName(names[relfld[RFLD_R_NAME]], SYSTEM_SCHEMA); relation->rel_owner = DBA_USER_NAME; relation->rel_dbkey_length = 8; @@ -1017,7 +1094,7 @@ void INI_init_dsql(thread_db* tdbb, dsql_dbb* database) const gfld* gfield = &gfields[fld[RFLD_F_ID]]; field->fld_name = names[fld[RFLD_F_NAME]]; - field->fieldSource = names[gfield->gfld_name]; + field->fieldSource = QualifiedName(names[gfield->gfld_name], SYSTEM_SCHEMA); field->length = gfield->gfld_length; field->scale = 0; field->subType = gfield->gfld_sub_type; @@ -1056,7 +1133,8 @@ void INI_init_dsql(thread_db* tdbb, dsql_dbb* database) continue; dsql_intlsym* csSymbol = FB_NEW_POOL(database->dbb_pool) dsql_intlsym(database->dbb_pool); - csSymbol->intlsym_name = csDef->name; + const QualifiedName csName(csDef->name, SYSTEM_SCHEMA); + csSymbol->intlsym_name = csName; csSymbol->intlsym_charset_id = csDef->id; csSymbol->intlsym_collate_id = 0; csSymbol->intlsym_ttype = @@ -1067,9 +1145,9 @@ void INI_init_dsql(thread_db* tdbb, dsql_dbb* database) // if the user has altered its default collation. csSymbol->intlsym_flags = INTLSYM_dropped; - database->dbb_charsets.put(csDef->name, csSymbol); + database->dbb_charsets.put(csName, csSymbol); database->dbb_charsets_by_id.put(csSymbol->intlsym_charset_id, csSymbol); - MET_dsql_cache_use(tdbb, SYM_intlsym_charset, csDef->name); + MET_dsql_cache_use(tdbb, SYM_intlsym_charset, csName); for (const IntlManager::CollationDefinition* colDef = IntlManager::defaultCollations; colDef->name; ++colDef) @@ -1078,7 +1156,8 @@ void INI_init_dsql(thread_db* tdbb, dsql_dbb* database) continue; dsql_intlsym* colSymbol = FB_NEW_POOL(database->dbb_pool) dsql_intlsym(database->dbb_pool); - colSymbol->intlsym_name = colDef->name; + const QualifiedName colName(colDef->name, SYSTEM_SCHEMA); + colSymbol->intlsym_name = colName; colSymbol->intlsym_flags = 0; colSymbol->intlsym_charset_id = csDef->id; colSymbol->intlsym_collate_id = colDef->collationId; @@ -1086,8 +1165,8 @@ void INI_init_dsql(thread_db* tdbb, dsql_dbb* database) INTL_CS_COLL_TO_TTYPE(colSymbol->intlsym_charset_id, colSymbol->intlsym_collate_id); colSymbol->intlsym_bytes_per_char = csDef->maxBytes; - database->dbb_collations.put(colDef->name, colSymbol); - MET_dsql_cache_use(tdbb, SYM_intlsym_collation, colDef->name); + database->dbb_collations.put(colName, colSymbol); + MET_dsql_cache_use(tdbb, SYM_intlsym_collation, colName); } } } @@ -1130,6 +1209,9 @@ void INI_upgrade(thread_db* tdbb) const int* fld; const char* context = nullptr; + dsc schemaDesc; + schemaDesc.makeText(strlen(SYSTEM_SCHEMA), CS_METADATA, (UCHAR*) SYSTEM_SCHEMA); + try { // Disable most of the deferred work processing, @@ -1215,7 +1297,7 @@ void INI_upgrade(thread_db* tdbb) dsc desc; desc.makeText(static_cast(strlen(relName)), CS_METADATA, (UCHAR*) relName); - DFW_post_work(transaction, dfw_update_format, &desc, 0); + DFW_post_work(transaction, dfw_update_format, &desc, &schemaDesc, 0); } } } @@ -1339,7 +1421,7 @@ void INI_upgrade(thread_db* tdbb) // Code below is the same as METD_drop_relation() but without a transaction - const auto relName = names[relfld[RFLD_R_NAME]]; + const QualifiedName relName(names[relfld[RFLD_R_NAME]], SYSTEM_SCHEMA); dsql_rel* relation; if (invalidate && dbb->dbb_relations.get(relName, relation)) @@ -1362,7 +1444,7 @@ static void store_admin_role(thread_db* tdbb, const MetaName& roleName, const auto securityClass = security.storeSecurityClass(tdbb); PreparedStatement::Builder sql; - sql << "insert into rdb$roles(rdb$role_name, rdb$owner_name, rdb$security_class, rdb$system_flag, rdb$system_privileges)" + sql << "insert into system.rdb$roles(rdb$role_name, rdb$owner_name, rdb$security_class, rdb$system_flag, rdb$system_privileges)" << "values (" << roleName << "," << ownerName << "," << securityClass << ", 1," << p << ")"; const auto attachment = tdbb->getAttachment(); @@ -1416,6 +1498,8 @@ static void store_generator(thread_db* tdbb, const gen* generator, STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) X IN RDB$GENERATORS { + PAD(SYSTEM_SCHEMA, X.RDB$SCHEMA_NAME); + PAD(generator->gen_name, X.RDB$GENERATOR_NAME); X.RDB$GENERATOR_ID = generator->gen_id; @@ -1462,6 +1546,8 @@ static void store_global_field(thread_db* tdbb, const gfld* gfield, STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) X IN RDB$FIELDS { + PAD(SYSTEM_SCHEMA, X.RDB$SCHEMA_NAME); + PAD(objName, X.RDB$FIELD_NAME); X.RDB$FIELD_LENGTH = gfield->gfld_length; @@ -1627,14 +1713,17 @@ static void store_indices(thread_db* tdbb, USHORT odsVersion) if (odsVersion && index->ini_idx_ods <= odsVersion) continue; - MetaName indexName; - indexName.printf("RDB$INDEX_%d", index->ini_idx_index_id); + QualifiedName indexName; + indexName.schema = SYSTEM_SCHEMA; + indexName.object.printf("RDB$INDEX_%d", index->ini_idx_index_id); STORE(REQUEST_HANDLE handle1 TRANSACTION_HANDLE transaction) X IN RDB$INDICES { - PAD(relation->rel_name, X.RDB$RELATION_NAME); - PAD(indexName, X.RDB$INDEX_NAME); + PAD(indexName.schema, X.RDB$SCHEMA_NAME); + + PAD(relation->rel_name.object, X.RDB$RELATION_NAME); + PAD(indexName.object, X.RDB$INDEX_NAME); X.RDB$UNIQUE_FLAG = index->ini_idx_flags & idx_unique; X.RDB$SEGMENT_COUNT = index->ini_idx_segment_count; @@ -1664,6 +1753,7 @@ static void store_indices(thread_db* tdbb, USHORT odsVersion) jrd_fld* field = (*relation->rel_fields)[segment->ini_idx_rfld_id]; Y.RDB$FIELD_POSITION = position; + PAD(SYSTEM_SCHEMA, Y.RDB$SCHEMA_NAME); PAD(X.RDB$INDEX_NAME, Y.RDB$INDEX_NAME); PAD(field->fld_name, Y.RDB$FIELD_NAME); tail->idx_field = segment->ini_idx_rfld_id; @@ -1677,7 +1767,7 @@ static void store_indices(thread_db* tdbb, USHORT odsVersion) idx.idx_flags = index->ini_idx_flags; SelectivityList selectivity(*tdbb->getDefaultPool()); - IDX_create_index(tdbb, relation, &idx, indexName.c_str(), NULL, + IDX_create_index(tdbb, relation, &idx, indexName, NULL, transaction, selectivity); X.RDB$INDEX_ID = idx.idx_id + 1; @@ -1689,9 +1779,10 @@ static void store_indices(thread_db* tdbb, USHORT odsVersion) STORE(REQUEST_HANDLE handle3 TRANSACTION_HANDLE transaction) RC IN RDB$RELATION_CONSTRAINTS { - PAD(indexName, RC.RDB$CONSTRAINT_NAME); - PAD(indexName, RC.RDB$INDEX_NAME); - PAD(relation->rel_name, RC.RDB$RELATION_NAME); + PAD(SYSTEM_SCHEMA, RC.RDB$SCHEMA_NAME); + PAD(indexName.object, RC.RDB$CONSTRAINT_NAME); + PAD(indexName.object, RC.RDB$INDEX_NAME); + PAD(relation->rel_name.object, RC.RDB$RELATION_NAME); strcpy(RC.RDB$CONSTRAINT_TYPE, UNIQUE_CNSTRT); strcpy(RC.RDB$DEFERRABLE, "NO"); strcpy(RC.RDB$INITIALLY_DEFERRED, "NO"); @@ -1719,7 +1810,9 @@ static void store_intlnames(thread_db* tdbb, NonRelationSecurity& security) STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) X IN RDB$CHARACTER_SETS USING { + PAD(SYSTEM_SCHEMA, X.RDB$SCHEMA_NAME); PAD(charSet->name, X.RDB$CHARACTER_SET_NAME); + PAD(SYSTEM_SCHEMA, X.RDB$DEFAULT_COLLATE_SCHEMA_NAME); PAD(charSet->name, X.RDB$DEFAULT_COLLATE_NAME); X.RDB$CHARACTER_SET_ID = charSet->id; @@ -1749,6 +1842,7 @@ static void store_intlnames(thread_db* tdbb, NonRelationSecurity& security) STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) X IN RDB$COLLATIONS USING { + PAD(SYSTEM_SCHEMA, X.RDB$SCHEMA_NAME); PAD(collation->name, X.RDB$COLLATION_NAME); if (collation->baseName) @@ -1809,6 +1903,7 @@ static void store_relation(thread_db* tdbb, X IN RDB$RELATIONS { X.RDB$RELATION_ID = relId; + PAD(SYSTEM_SCHEMA, X.RDB$SCHEMA_NAME); PAD(relName, X.RDB$RELATION_NAME); X.RDB$RELATION_TYPE = relType; @@ -1847,8 +1942,10 @@ static void store_relation_field(thread_db* tdbb, STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) X IN RDB$RELATION_FIELDS { + PAD(SYSTEM_SCHEMA, X.RDB$SCHEMA_NAME); PAD(relName, X.RDB$RELATION_NAME); PAD(fieldName, X.RDB$FIELD_NAME); + PAD(SYSTEM_SCHEMA, X.RDB$FIELD_SOURCE_SCHEMA_NAME); PAD(globalName, X.RDB$FIELD_SOURCE); X.RDB$FIELD_POSITION = fieldId; X.RDB$FIELD_ID = fieldId; @@ -1883,6 +1980,7 @@ static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHOR STORE (REQUEST_HANDLE packageHandle TRANSACTION_HANDLE transaction) PKG IN RDB$PACKAGES { + PAD(SYSTEM_SCHEMA, PKG.RDB$SCHEMA_NAME); PAD(systemPackage.name, PKG.RDB$PACKAGE_NAME); PAD(ownerName, PKG.RDB$OWNER_NAME); @@ -1903,6 +2001,7 @@ static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHOR STORE (REQUEST_HANDLE procedureHandle TRANSACTION_HANDLE transaction) PRC IN RDB$PROCEDURES { + PAD(SYSTEM_SCHEMA, PRC.RDB$SCHEMA_NAME); PAD(systemPackage.name, PRC.RDB$PACKAGE_NAME); PAD(procedure.name, PRC.RDB$PROCEDURE_NAME); @@ -1931,6 +2030,7 @@ static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHOR STORE (REQUEST_HANDLE procedureParameterHandle TRANSACTION_HANDLE transaction) PP IN RDB$PROCEDURE_PARAMETERS { + PAD(SYSTEM_SCHEMA, PP.RDB$SCHEMA_NAME); PAD(systemPackage.name, PP.RDB$PACKAGE_NAME); PAD(procedure.name, PP.RDB$PROCEDURE_NAME); PAD(parameter.name, PP.RDB$PARAMETER_NAME); @@ -1942,6 +2042,7 @@ static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHOR PP.RDB$PARAMETER_MECHANISM = (SSHORT) prm_mech_normal; PP.RDB$NULL_FLAG = !parameter.nullable; + PAD(SYSTEM_SCHEMA, PP.RDB$FIELD_SOURCE_SCHEMA_NAME); PAD(names[gfields[parameter.fieldId].gfld_name], PP.RDB$FIELD_SOURCE); fb_assert(parameter.defaultBlr.isEmpty() == !parameter.defaultText); @@ -1977,6 +2078,7 @@ static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHOR STORE (REQUEST_HANDLE functionHandle TRANSACTION_HANDLE transaction) FUN IN RDB$FUNCTIONS { + PAD(SYSTEM_SCHEMA, FUN.RDB$SCHEMA_NAME); PAD(systemPackage.name, FUN.RDB$PACKAGE_NAME); PAD(function.name, FUN.RDB$FUNCTION_NAME); @@ -1997,6 +2099,7 @@ static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHOR STORE (REQUEST_HANDLE functionReturnHandle TRANSACTION_HANDLE transaction) ARG IN RDB$FUNCTION_ARGUMENTS { + PAD(SYSTEM_SCHEMA, ARG.RDB$SCHEMA_NAME); PAD(systemPackage.name, ARG.RDB$PACKAGE_NAME); PAD(function.name, ARG.RDB$FUNCTION_NAME); @@ -2005,6 +2108,7 @@ static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHOR ARG.RDB$ARGUMENT_POSITION = paramNumber; ARG.RDB$NULL_FLAG = !function.returnType.nullable; + PAD(SYSTEM_SCHEMA, ARG.RDB$FIELD_SOURCE_SCHEMA_NAME); PAD(names[gfields[function.returnType.fieldId].gfld_name], ARG.RDB$FIELD_SOURCE); } END_STORE @@ -2016,6 +2120,7 @@ static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHOR STORE (REQUEST_HANDLE functionArgumentHandle TRANSACTION_HANDLE transaction) ARG IN RDB$FUNCTION_ARGUMENTS { + PAD(SYSTEM_SCHEMA, ARG.RDB$SCHEMA_NAME); PAD(systemPackage.name, ARG.RDB$PACKAGE_NAME); PAD(function.name, ARG.RDB$FUNCTION_NAME); PAD(parameter.name, ARG.RDB$ARGUMENT_NAME); @@ -2025,6 +2130,7 @@ static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHOR ARG.RDB$ARGUMENT_POSITION = paramNumber; ARG.RDB$NULL_FLAG = !parameter.nullable; + PAD(SYSTEM_SCHEMA, ARG.RDB$FIELD_SOURCE_SCHEMA_NAME); PAD(names[gfields[parameter.fieldId].gfld_name], ARG.RDB$FIELD_SOURCE); fb_assert(parameter.defaultBlr.isEmpty() == !parameter.defaultText); diff --git a/src/jrd/intl.cpp b/src/jrd/intl.cpp index 463293de4e..78acdde888 100644 --- a/src/jrd/intl.cpp +++ b/src/jrd/intl.cpp @@ -241,7 +241,7 @@ bool CharSetContainer::lookupInternalCharSet(USHORT id, SubtypeInfo* info) { if (id == CS_UTF16) { - info->charsetName = "UTF16"; + info->charsetName = QualifiedName("UTF16"); return true; } @@ -261,8 +261,8 @@ bool CharSetContainer::lookupInternalCharSet(USHORT id, SubtypeInfo* info) { if (colDef->charSetId == id && colDef->collationId == 0) { - info->charsetName = csDef->name; - info->collationName = colDef->name; + info->charsetName = QualifiedName(csDef->name, SYSTEM_SCHEMA); + info->collationName = QualifiedName(colDef->name, SYSTEM_SCHEMA); info->attributes = colDef->attributes; info->ignoreAttributes = false; @@ -310,7 +310,7 @@ CharSetContainer::CharSetContainer(MemoryPool& p, USHORT cs_id, const SubtypeInf charset* csL = FB_NEW_POOL(p) charset; memset(csL, 0, sizeof(charset)); - if (IntlManager::lookupCharSet(info->charsetName.c_str(), csL) && + if (IntlManager::lookupCharSet(info->charsetName, csL) && (csL->charset_flags & CHARSET_ASCII_BASED)) { this->cs = CharSet::createInstance(p, cs_id, csL); @@ -318,7 +318,7 @@ CharSetContainer::CharSetContainer(MemoryPool& p, USHORT cs_id, const SubtypeInf else { delete csL; - ERR_post(Arg::Gds(isc_charset_not_installed) << Arg::Str(info->charsetName)); + ERR_post(Arg::Gds(isc_charset_not_installed) << info->charsetName.toQuotedString()); } } @@ -462,7 +462,7 @@ void CharSetContainer::unloadCollation(thread_db* tdbb, USHORT tt_id) if (charset_collations[id]->useCount != 0) { ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_obj_in_use) << Arg::Str(charset_collations[id]->name)); + Arg::Gds(isc_obj_in_use) << charset_collations[id]->name.toQuotedString()); } fb_assert(charset_collations[id]->existenceLock); @@ -489,7 +489,7 @@ void CharSetContainer::unloadCollation(thread_db* tdbb, USHORT tt_id) static void lookup_texttype(texttype* tt, const SubtypeInfo* info) { - IntlManager::lookupCollation(info->baseCollationName.c_str(), info->charsetName.c_str(), + IntlManager::lookupCollation(info->baseCollationName, info->charsetName, info->attributes, info->specificAttributes.begin(), info->specificAttributes.getCount(), info->ignoreAttributes, tt); } diff --git a/src/jrd/intl.h b/src/jrd/intl.h index ee9e0d5733..8e23fb9e81 100644 --- a/src/jrd/intl.h +++ b/src/jrd/intl.h @@ -41,7 +41,7 @@ #define DEFAULT_CHARACTER_SET_NAME "ISO8859_1" #define NATIONAL_CHARACTER_SET DEFAULT_CHARACTER_SET_NAME -#define DEFAULT_DB_CHARACTER_SET_NAME "NONE" +#define DEFAULT_DB_CHARACTER_SET_NAME "SYSTEM.NONE" // Character Set used for system metadata information diff --git a/src/jrd/irq.h b/src/jrd/irq.h index 2c6d1a9288..d20508be65 100644 --- a/src/jrd/irq.h +++ b/src/jrd/irq.h @@ -149,7 +149,6 @@ enum irq_type_t irq_domain, // DSQL/METD: lookup a domain irq_type, // DSQL/METD: lookup a symbolic name in RDB$TYPES irq_cs_name, // DSQL/METD: lookup a charset name - irq_default_cs, // DSQL/METD: lookup the default charset irq_rel_ids, // DSQL/METD: check relation/field ids irq_comp_circ_dpd, // check computed circular dependencies irq_grant10, // process grant option (packages) diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 2d0fea9563..7b618658ad 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -731,7 +731,7 @@ namespace { PreparedStatement::Builder sql; MetaName missPriv("UNKNOWN"); - sql << "select" << sql("rdb$type_name", missPriv) << "from rdb$types" + sql << "select" << sql("rdb$type_name", missPriv) << "from system.rdb$types" << "where rdb$field_name = 'RDB$SYSTEM_PRIVILEGES'" << " and rdb$type =" << SSHORT(sp); jrd_tra* transaction = attachment->getSysTransaction(); @@ -913,7 +913,7 @@ void Trigger::compile(thread_db* tdbb) *csb->csb_dbg_info); } - PAR_blr(tdbb, relation, blr.begin(), (ULONG) blr.getCount(), NULL, &csb, &statement, + PAR_blr(tdbb, &name.schema, relation, blr.begin(), (ULONG) blr.getCount(), NULL, &csb, &statement, (relation ? true : false), par_flags); trace.finish(statement, ITracePlugin::RESULT_SUCCESS); @@ -1064,6 +1064,7 @@ namespace Jrd SLONG dpb_remote_pid; bool dpb_no_db_triggers; bool dpb_gbak_attach; + bool dpb_gbak_restore_has_schema; bool dpb_utf8_filename; ULONG dpb_ext_call_depth; ULONG dpb_flags; // to OR'd with dbb_flags @@ -1085,7 +1086,7 @@ namespace Jrd AuthReader::AuthBlock dpb_auth_block; string dpb_role_name; string dpb_journal; - string dpb_lc_ctype; + QualifiedMetaString dpb_lc_ctype; PathName dpb_working_directory; string dpb_set_db_charset; string dpb_network_protocol; @@ -1104,6 +1105,8 @@ namespace Jrd string dpb_decfloat_round; string dpb_decfloat_traps; string dpb_owner; + Firebird::ObjectsArray dpb_schema_search_path; + Firebird::ObjectsArray dpb_blr_request_schema_search_path; public: static const ULONG DPB_FLAGS_MASK = DBB_damaged; @@ -1252,6 +1255,25 @@ namespace Jrd decFloatStatus.decExtFlag = traps; } + if (options.dpb_schema_search_path.hasData()) + { + for (const auto& schema : options.dpb_schema_search_path) + schemaSearchPath->push(schema); + } + else + { + schemaSearchPath->push(PUBLIC_SCHEMA); + schemaSearchPath->push(SYSTEM_SCHEMA); + } + + if (options.dpb_blr_request_schema_search_path.hasData()) + { + for (const auto& schema : options.dpb_blr_request_schema_search_path) + blrRequestSchemaSearchPath->push(schema); + } + else + blrRequestSchemaSearchPath = schemaSearchPath; + originalTimeZone = options.dpb_session_tz.isEmpty() ? TimeZoneUtil::getSystemTimeZone() : TimeZoneUtil::parse(options.dpb_session_tz.c_str(), options.dpb_session_tz.length()); @@ -1267,6 +1289,10 @@ namespace Jrd // reset bindings attachment->att_bindings.clear(); + + // reset schema search path + attachment->att_schema_search_path = schemaSearchPath; + attachment->att_blr_request_schema_search_path = blrRequestSchemaSearchPath; } } // namespace Jrd @@ -1283,7 +1309,7 @@ public: int getProcessID() { return m_options->dpb_remote_pid; } const char* getUserName() { return m_id.getUserName().c_str(); } const char* getRoleName() { return m_options->dpb_role_name.c_str(); } - const char* getCharSet() { return m_options->dpb_lc_ctype.c_str(); } + const char* getCharSet() { return m_options->dpb_lc_ctype.object.c_str(); } const char* getRemoteProtocol() { return m_options->dpb_network_protocol.c_str(); } const char* getRemoteAddress() { return m_options->dpb_remote_address.c_str(); } int getRemoteProcessID() { return m_options->dpb_remote_pid; } @@ -1754,7 +1780,12 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch attachment->att_flags |= ATT_mapping; if (options.dpb_gbak_attach) + { attachment->att_utility = Attachment::UTIL_GBAK; + + if (options.dpb_gbak_restore_has_schema) + attachment->att_flags |= ATT_gbak_restore_has_schema; + } else if (options.dpb_gstat_attach) attachment->att_utility = Attachment::UTIL_GSTAT; else if (options.dpb_gfix_attach) @@ -2702,9 +2733,13 @@ JRequest* JAttachment::compileRequest(CheckStatusWrapper* user_status, TraceBlrCompile trace(tdbb, blr_length, blr); try { + const auto attachment = tdbb->getAttachment(); + + AutoSetRestore autoSchemaSearchPath( + &attachment->att_schema_search_path, attachment->att_blr_request_schema_search_path); + stmt = CMP_compile(tdbb, blr, blr_length, false, 0, nullptr); - const auto attachment = tdbb->getAttachment(); const auto rootRequest = stmt->getRequest(tdbb, 0); rootRequest->setAttachment(attachment); attachment->att_requests.add(rootRequest); @@ -2971,8 +3006,13 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch attachment->att_flags |= ATT_mapping; if (options.dpb_gbak_attach) + { attachment->att_utility = Attachment::UTIL_GBAK; + if (options.dpb_gbak_restore_has_schema) + attachment->att_flags |= ATT_gbak_restore_has_schema; + } + if (options.dpb_no_db_triggers) attachment->att_flags |= ATT_no_db_triggers; @@ -6652,8 +6692,8 @@ void JRD_print_procedure_info(thread_db* tdbb, const char* mesg) if (procedure) { fprintf(fptr, "%s , %d, %X, %d, %d\n", - (procedure->getName().toString().hasData() ? - procedure->getName().toString().c_str() : "NULL"), + (procedure->getName().toQuotedString().hasData() ? + procedure->getName().toQuotedString().c_str() : "NULL"), procedure->getId(), procedure->flags, procedure->useCount, 0); // procedure->prc_alter_count } @@ -6839,7 +6879,7 @@ static void find_intl_charset(thread_db* tdbb, Jrd::Attachment* attachment, cons **************************************/ SET_TDBB(tdbb); - if (options->dpb_lc_ctype.isEmpty()) + if (options->dpb_lc_ctype.object.isEmpty()) { // No declaration of character set, act like 3.x Interbase attachment->att_client_charset = attachment->att_charset = DEFAULT_ATTACHMENT_CHARSET; @@ -6847,15 +6887,14 @@ static void find_intl_charset(thread_db* tdbb, Jrd::Attachment* attachment, cons } USHORT id; - const UCHAR* lc_ctype = reinterpret_cast(options->dpb_lc_ctype.c_str()); - if (MET_get_char_coll_subtype(tdbb, &id, lc_ctype, options->dpb_lc_ctype.length()) && + if (MET_get_char_coll_subtype(tdbb, &id, options->dpb_lc_ctype) && INTL_defined_type(tdbb, id & 0xFF)) { if ((id & 0xFF) == CS_BINARY) { ERR_post(Arg::Gds(isc_bad_dpb_content) << - Arg::Gds(isc_invalid_attachment_charset) << Arg::Str(options->dpb_lc_ctype)); + Arg::Gds(isc_invalid_attachment_charset) << options->dpb_lc_ctype.toQuotedString()); } attachment->att_client_charset = attachment->att_charset = id & 0xFF; @@ -6864,7 +6903,7 @@ static void find_intl_charset(thread_db* tdbb, Jrd::Attachment* attachment, cons { // Report an error - we can't do what user has requested ERR_post(Arg::Gds(isc_bad_dpb_content) << - Arg::Gds(isc_charset_not_found) << Arg::Str(options->dpb_lc_ctype)); + Arg::Gds(isc_charset_not_found) << options->dpb_lc_ctype.toQuotedString()); } } @@ -6907,6 +6946,8 @@ void DatabaseOptions::get(const UCHAR* dpb, FB_SIZE_T dpb_length, bool& invalid_ dpb_utf8_filename = rdr.find(isc_dpb_utf8_filename); + string tempStr; + for (rdr.rewind(); !rdr.isEof(); rdr.moveNext()) { switch (rdr.getClumpTag()) @@ -7066,7 +7107,22 @@ void DatabaseOptions::get(const UCHAR* dpb, FB_SIZE_T dpb_length, bool& invalid_ break; case isc_dpb_lc_ctype: - rdr.getString(dpb_lc_ctype); + rdr.getString(tempStr); + + // hack for aliases like utf-8 + if (tempStr.find('-') != string::npos && + tempStr.find('.') == string::npos && + tempStr.find('"') == string::npos) + { + tempStr.upper(); + tempStr = '"' + tempStr + '"'; + } + + dpb_lc_ctype = QualifiedMetaString::parseSchemaObject(tempStr); + + if (dpb_lc_ctype.schema.isEmpty()) + dpb_lc_ctype.schema = SYSTEM_SCHEMA; + break; case isc_dpb_shutdown: @@ -7128,6 +7184,10 @@ void DatabaseOptions::get(const UCHAR* dpb, FB_SIZE_T dpb_length, bool& invalid_ } break; + case isc_dpb_gbak_restore_has_schema: + dpb_gbak_restore_has_schema = true; + break; + case isc_dpb_gstat_attach: dpb_gstat_attach = true; break; @@ -7306,6 +7366,16 @@ void DatabaseOptions::get(const UCHAR* dpb, FB_SIZE_T dpb_length, bool& invalid_ getString(rdr, dpb_owner); break; + case isc_dpb_search_path: + getString(rdr, tempStr); + MetaString::parseList(tempStr, dpb_schema_search_path); + break; + + case isc_dpb_blr_request_search_path: + getString(rdr, tempStr); + MetaString::parseList(tempStr, dpb_blr_request_schema_search_path); + break; + default: break; } @@ -7365,10 +7435,18 @@ static JAttachment* initAttachment(thread_db* tdbb, const PathName& expanded_nam engineStartup.init(); + QualifiedMetaString charSetName; + + if (options.dpb_set_db_charset.hasData()) + charSetName = QualifiedMetaString::parseSchemaObject(options.dpb_set_db_charset); + + if (charSetName.schema.isEmpty()) + charSetName.schema = SYSTEM_SCHEMA; + if (!attach_flag && options.dpb_set_db_charset.hasData() && - !IntlManager::charSetInstalled(options.dpb_set_db_charset)) + !IntlManager::charSetInstalled(charSetName)) { - ERR_post(Arg::Gds(isc_charset_not_installed) << options.dpb_set_db_charset); + ERR_post(Arg::Gds(isc_charset_not_installed) << charSetName.toQuotedString()); } // Check to see if the database is already attached diff --git a/src/jrd/jrd.h b/src/jrd/jrd.h index 9bb03c60e8..49757d5299 100644 --- a/src/jrd/jrd.h +++ b/src/jrd/jrd.h @@ -146,7 +146,7 @@ public: FB_UINT64 type = 0; // Trigger type USHORT flags = 0; // Flags as they are in RDB$TRIGGERS table jrd_rel* relation = nullptr; // Trigger parent relation - MetaName name; // Trigger name + QualifiedName name; // Trigger name MetaName engine; // External engine name MetaName owner; // Owner for SQL SECURITY Firebird::string entryPoint; // External trigger entrypoint @@ -281,9 +281,9 @@ public: bool prm_nullable; prm_mech_t prm_mechanism; MetaName prm_name; - MetaName prm_field_source; + QualifiedName prm_field_source; MetaName prm_type_of_column; - MetaName prm_type_of_table; + QualifiedName prm_type_of_table; std::optional prm_text_type; FUN_T prm_fun_mechanism; diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 8d5efc9f1b..770e00c2fc 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -87,7 +87,6 @@ #include "../jrd/sdw_proto.h" #include "../common/utils_proto.h" -#include "../jrd/PreparedStatement.h" #include "../jrd/RecordSourceNodes.h" #include "../jrd/DebugInterface.h" #include "../common/classes/Hash.h" @@ -115,19 +114,19 @@ static int blocking_ast_relation(void*); static int partners_ast_relation(void*); static int rescan_ast_relation(void*); static ULONG get_rel_flags_from_FLAGS(USHORT); -static void get_trigger(thread_db*, jrd_rel*, bid*, bid*, TrigVector**, const TEXT*, FB_UINT64, bool, +static void get_trigger(thread_db*, jrd_rel*, bid*, bid*, TrigVector**, const QualifiedName&, FB_UINT64, bool, USHORT, const MetaName&, const string&, const bid*, TriState ssDefiner); -static bool get_type(thread_db*, USHORT*, const UCHAR*, const TEXT*); +static bool get_type(thread_db*, USHORT*, const MetaName&, const TEXT*); static void lookup_view_contexts(thread_db*, jrd_rel*); -static void make_relation_scope_name(const TEXT*, const USHORT, string& str); -static ValueExprNode* parse_field_default_blr(thread_db* tdbb, bid* blob_id); -static BoolExprNode* parse_field_validation_blr(thread_db* tdbb, bid* blob_id, const MetaName name); -static bool resolve_charset_and_collation(thread_db*, USHORT*, const UCHAR*, const UCHAR*); +static void make_relation_scope_name(const QualifiedName&, const USHORT, string& str); +static ValueExprNode* parse_field_default_blr(thread_db* tdbb, const MetaName& schema, bid* blob_id); +static BoolExprNode* parse_field_validation_blr(thread_db* tdbb, bid* blob_id, const QualifiedName& name); +static bool resolve_charset_and_collation(thread_db*, USHORT*, const QualifiedName&, const QualifiedName&); static void save_trigger_data(thread_db*, TrigVector**, jrd_rel*, Statement*, blb*, blb*, - const TEXT*, FB_UINT64, bool, USHORT, const MetaName&, const string&, + const QualifiedName*, FB_UINT64, bool, USHORT, const MetaName&, const string&, const bid*, TriState ssDefiner); static void scan_partners(thread_db*, jrd_rel*); -static bool verify_TRG_ignore_perm(thread_db*, const MetaName&); +static bool verify_TRG_ignore_perm(thread_db*, const QualifiedName&); static void inc_int_use_count(Statement* statement) @@ -181,7 +180,7 @@ static void post_used_procedures(TrigVector* vector) } -void MET_get_domain(thread_db* tdbb, MemoryPool& csbPool, const MetaName& name, dsc* desc, +void MET_get_domain(thread_db* tdbb, MemoryPool& csbPool, const QualifiedName& name, dsc* desc, FieldInfo* fieldInfo) { /************************************** @@ -201,7 +200,9 @@ void MET_get_domain(thread_db* tdbb, MemoryPool& csbPool, const MetaName& name, AutoCacheRequest handle(tdbb, irq_l_domain, IRQ_REQUESTS); FOR(REQUEST_HANDLE handle) - FLD IN RDB$FIELDS WITH FLD.RDB$FIELD_NAME EQ name.c_str() + FLD IN RDB$FIELDS + WITH FLD.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + FLD.RDB$FIELD_NAME EQ name.object.c_str() { if (DSC_make_descriptor(desc, FLD.RDB$FIELD_TYPE, @@ -222,7 +223,7 @@ void MET_get_domain(thread_db* tdbb, MemoryPool& csbPool, const MetaName& name, if (FLD.RDB$DEFAULT_VALUE.NULL) fieldInfo->defaultValue = NULL; else - fieldInfo->defaultValue = parse_field_default_blr(tdbb, &FLD.RDB$DEFAULT_VALUE); + fieldInfo->defaultValue = parse_field_default_blr(tdbb, name.schema, &FLD.RDB$DEFAULT_VALUE); if (FLD.RDB$VALIDATION_BLR.NULL) fieldInfo->validationExpr = NULL; @@ -237,13 +238,11 @@ void MET_get_domain(thread_db* tdbb, MemoryPool& csbPool, const MetaName& name, END_FOR if (!found) - { - ERR_post(Arg::Gds(isc_domnotdef) << Arg::Str(name)); - } + ERR_post(Arg::Gds(isc_domnotdef) << name.toQuotedString()); } -MetaName MET_get_relation_field(thread_db* tdbb, MemoryPool& csbPool, const MetaName& relationName, +MetaName MET_get_relation_field(thread_db* tdbb, MemoryPool& csbPool, const QualifiedName& relationName, const MetaName& fieldName, dsc* desc, FieldInfo* fieldInfo) { /************************************** @@ -267,8 +266,10 @@ MetaName MET_get_relation_field(thread_db* tdbb, MemoryPool& csbPool, const Meta FOR(REQUEST_HANDLE handle) RFL IN RDB$RELATION_FIELDS CROSS FLD IN RDB$FIELDS WITH - RFL.RDB$RELATION_NAME EQ relationName.c_str() AND + RFL.RDB$SCHEMA_NAME EQ relationName.schema.c_str() AND + RFL.RDB$RELATION_NAME EQ relationName.object.c_str() AND RFL.RDB$FIELD_NAME EQ fieldName.c_str() AND + FLD.RDB$SCHEMA_NAME EQUIV RFL.RDB$FIELD_SOURCE_SCHEMA_NAME AND FLD.RDB$FIELD_NAME EQ RFL.RDB$FIELD_SOURCE { if (DSC_make_descriptor(desc, @@ -296,7 +297,7 @@ MetaName MET_get_relation_field(thread_db* tdbb, MemoryPool& csbPool, const Meta defaultId = &FLD.RDB$DEFAULT_VALUE; if (defaultId) - fieldInfo->defaultValue = parse_field_default_blr(tdbb, defaultId); + fieldInfo->defaultValue = parse_field_default_blr(tdbb, relationName.schema, defaultId); else fieldInfo->defaultValue = NULL; @@ -305,7 +306,7 @@ MetaName MET_get_relation_field(thread_db* tdbb, MemoryPool& csbPool, const Meta else { fieldInfo->validationExpr = parse_field_validation_blr(tdbb, - &FLD.RDB$VALIDATION_BLR, RFL.RDB$FIELD_SOURCE); + &FLD.RDB$VALIDATION_BLR, QualifiedName(RFL.RDB$FIELD_SOURCE, RFL.RDB$FIELD_SOURCE_SCHEMA_NAME)); } } } @@ -314,8 +315,9 @@ MetaName MET_get_relation_field(thread_db* tdbb, MemoryPool& csbPool, const Meta if (!found) { - ERR_post(Arg::Gds(isc_dyn_column_does_not_exist) << Arg::Str(fieldName) << - Arg::Str(relationName)); + ERR_post(Arg::Gds(isc_dyn_column_does_not_exist) << + Arg::Str(fieldName) << + relationName.toQuotedString()); } return sourceName; @@ -483,7 +485,7 @@ void MET_verify_cache(thread_db* tdbb) { char buffer[1024], *buf = buffer; buf += sprintf(buf, "Procedure %d:%s is not properly counted (use count=%d, prc use=%d). Used by: \n", - routine->getId(), routine->getName().toString().c_str(), + routine->getId(), routine->getName().toQuotedString().c_str(), routine->useCount, routine->intUseCount); for (jrd_prc** iter2 = att->att_procedures.begin(); iter2 != att->att_procedures.end(); ++iter2) @@ -508,7 +510,7 @@ void MET_verify_cache(thread_db* tdbb) // Do not enable this code in production builds unless // the possible B.O. is fixed here. buf += sprintf(buf, "%d:%s\n", routine2->getId(), - routine2->getName().toString().c_str()); + routine2->getName().toQuotedString().c_str()); } } } @@ -536,7 +538,7 @@ void MET_verify_cache(thread_db* tdbb) // Do not enable this code in production builds unless // the possible B.O. is fixed here. buf += sprintf(buf, "%d:%s\n", routine2->getId(), - routine2->getName().toString().c_str()); + routine2->getName().toQuotedString().c_str()); } } } @@ -558,7 +560,7 @@ void MET_verify_cache(thread_db* tdbb) { char buffer[1024], *buf = buffer; buf += sprintf(buf, "Function %d:%s is not properly counted (use count=%d, func use=%d). Used by: \n", - routine->getId(), routine->getName().toString().c_str(), + routine->getId(), routine->getName().toQuotedString().c_str(), routine->useCount, routine->intUseCount); for (jrd_prc** iter2 = att->att_procedures.begin(); iter2 != att->att_procedures.end(); ++iter2) @@ -583,7 +585,7 @@ void MET_verify_cache(thread_db* tdbb) // Do not enable this code in production builds unless // the possible B.O. is fixed here. buf += sprintf(buf, "%d:%s\n", routine2->getId(), - routine2->getName().toString().c_str()); + routine2->getName().toQuotedString().c_str()); } } } @@ -611,7 +613,7 @@ void MET_verify_cache(thread_db* tdbb) // Do not enable this code in production builds unless // the possible B.O. is fixed here. buf += sprintf(buf, "%d:%s\n", routine2->getId(), - routine2->getName().toString().c_str()); + routine2->getName().toQuotedString().c_str()); } } } @@ -961,7 +963,7 @@ ULONG MET_align(const dsc* desc, ULONG value) } -DeferredWork* MET_change_fields(thread_db* tdbb, jrd_tra* transaction, const dsc* field_source) +DeferredWork* MET_change_fields(thread_db* tdbb, jrd_tra* transaction, const dsc* schemaName, const dsc* field_source) { /************************************** * @@ -979,88 +981,99 @@ DeferredWork* MET_change_fields(thread_db* tdbb, jrd_tra* transaction, const dsc SET_TDBB(tdbb); Attachment* attachment = tdbb->getAttachment(); - dsc relation_name; + dsc schemaNameDsc; + dsc nameDesc; DeferredWork* dw = NULL; AutoCacheRequest request(tdbb, irq_m_fields, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - X IN RDB$RELATION_FIELDS WITH - X.RDB$FIELD_SOURCE EQ field_source->dsc_address + X IN RDB$RELATION_FIELDS + WITH X.RDB$SCHEMA_NAME EQ schemaName->dsc_address AND + X.RDB$FIELD_SOURCE EQ field_source->dsc_address { - relation_name.makeText(sizeof(X.RDB$RELATION_NAME) - 1, CS_METADATA, - (UCHAR*) X.RDB$RELATION_NAME); - SCL_check_relation(tdbb, &relation_name, SCL_alter); - dw = DFW_post_work(transaction, dfw_update_format, &relation_name, 0); + SCL_check_relation(tdbb, QualifiedName(X.RDB$RELATION_NAME, X.RDB$SCHEMA_NAME), SCL_alter); + schemaNameDsc.makeText(sizeof(X.RDB$SCHEMA_NAME) - 1, CS_METADATA, (UCHAR*) X.RDB$SCHEMA_NAME); + nameDesc.makeText(sizeof(X.RDB$RELATION_NAME) - 1, CS_METADATA, (UCHAR*) X.RDB$RELATION_NAME); + dw = DFW_post_work(transaction, dfw_update_format, &nameDesc, &schemaNameDsc, 0); AutoCacheRequest request2(tdbb, irq_m_fields4, IRQ_REQUESTS); FOR(REQUEST_HANDLE request2) - DEP IN RDB$DEPENDENCIES CROSS - PRC IN RDB$PROCEDURES - WITH DEP.RDB$DEPENDED_ON_NAME EQ X.RDB$RELATION_NAME AND - DEP.RDB$FIELD_NAME EQ X.RDB$FIELD_NAME AND - DEP.RDB$DEPENDED_ON_TYPE EQ obj_relation AND - DEP.RDB$DEPENDENT_TYPE EQ obj_procedure AND - DEP.RDB$DEPENDENT_NAME EQ PRC.RDB$PROCEDURE_NAME AND - PRC.RDB$PACKAGE_NAME MISSING + DEP IN RDB$DEPENDENCIES + CROSS PRC IN RDB$PROCEDURES + WITH DEP.RDB$DEPENDED_ON_SCHEMA_NAME EQ X.RDB$SCHEMA_NAME AND + DEP.RDB$DEPENDED_ON_NAME EQ X.RDB$RELATION_NAME AND + DEP.RDB$FIELD_NAME EQ X.RDB$FIELD_NAME AND + DEP.RDB$DEPENDED_ON_TYPE EQ obj_relation AND + DEP.RDB$DEPENDENT_TYPE EQ obj_procedure AND + DEP.RDB$DEPENDENT_SCHEMA_NAME EQ PRC.RDB$SCHEMA_NAME AND + DEP.RDB$DEPENDENT_NAME EQ PRC.RDB$PROCEDURE_NAME AND + PRC.RDB$PACKAGE_NAME MISSING { - MetaName proc_name(PRC.RDB$PROCEDURE_NAME); + QualifiedName procName(PRC.RDB$PROCEDURE_NAME, PRC.RDB$SCHEMA_NAME); - dsc desc; - desc.makeText(proc_name.length(), CS_METADATA, (UCHAR*) proc_name.c_str()); + dsc schemaDesc, nameDesc; + schemaDesc.makeText(procName.schema.length(), CS_METADATA, (UCHAR*) procName.schema.c_str()); + nameDesc.makeText(procName.object.length(), CS_METADATA, (UCHAR*) procName.object.c_str()); DeferredWork* dw2 = - DFW_post_work(transaction, dfw_modify_procedure, &desc, PRC.RDB$PROCEDURE_ID); - DFW_post_work_arg(transaction, dw2, NULL, 0, dfw_arg_check_blr); + DFW_post_work(transaction, dfw_modify_procedure, &nameDesc, &schemaDesc, PRC.RDB$PROCEDURE_ID); + DFW_post_work_arg(transaction, dw2, nullptr, nullptr, 0, dfw_arg_check_blr); } END_FOR request2.reset(tdbb, irq_m_fields5, IRQ_REQUESTS); FOR(REQUEST_HANDLE request2) - DEP IN RDB$DEPENDENCIES CROSS - TRG IN RDB$TRIGGERS - WITH DEP.RDB$DEPENDED_ON_NAME EQ X.RDB$RELATION_NAME AND - DEP.RDB$FIELD_NAME EQ X.RDB$FIELD_NAME AND - DEP.RDB$DEPENDED_ON_TYPE EQ obj_relation AND - DEP.RDB$DEPENDENT_TYPE EQ obj_trigger AND - DEP.RDB$DEPENDENT_NAME EQ TRG.RDB$TRIGGER_NAME + DEP IN RDB$DEPENDENCIES + CROSS TRG IN RDB$TRIGGERS + WITH DEP.RDB$DEPENDED_ON_SCHEMA_NAME EQ X.RDB$SCHEMA_NAME AND + DEP.RDB$DEPENDED_ON_NAME EQ X.RDB$RELATION_NAME AND + DEP.RDB$FIELD_NAME EQ X.RDB$FIELD_NAME AND + DEP.RDB$DEPENDED_ON_TYPE EQ obj_relation AND + DEP.RDB$DEPENDENT_TYPE EQ obj_trigger AND + DEP.RDB$DEPENDENT_SCHEMA_NAME EQ TRG.RDB$SCHEMA_NAME AND + DEP.RDB$DEPENDENT_NAME EQ TRG.RDB$TRIGGER_NAME { - MetaName trigger_name(TRG.RDB$TRIGGER_NAME); - MetaName trigger_relation_name(TRG.RDB$RELATION_NAME); + QualifiedName triggerName(TRG.RDB$TRIGGER_NAME, TRG.RDB$SCHEMA_NAME); + MetaName triggerRelationName(TRG.RDB$RELATION_NAME); - dsc desc; - desc.makeText(trigger_name.length(), CS_METADATA, (UCHAR*) trigger_name.c_str()); + dsc schemaDesc, nameDesc; + schemaDesc.makeText(triggerName.schema.length(), CS_METADATA, (UCHAR*) triggerName.schema.c_str()); + nameDesc.makeText(triggerName.object.length(), CS_METADATA, (UCHAR*) triggerName.object.c_str()); - DeferredWork* dw2 = DFW_post_work(transaction, dfw_modify_trigger, &desc, 0); - DFW_post_work_arg(transaction, dw2, NULL, TRG.RDB$TRIGGER_TYPE, dfw_arg_trg_type); + DeferredWork* dw2 = DFW_post_work(transaction, dfw_modify_trigger, &nameDesc, &schemaDesc, 0); + DFW_post_work_arg(transaction, dw2, nullptr, nullptr, TRG.RDB$TRIGGER_TYPE, dfw_arg_trg_type); - desc.dsc_length = trigger_relation_name.length(); - desc.dsc_address = (UCHAR*) trigger_relation_name.c_str(); - DFW_post_work_arg(transaction, dw2, &desc, 0, dfw_arg_check_blr); + nameDesc.dsc_length = triggerRelationName.length(); + nameDesc.dsc_address = (UCHAR*) triggerRelationName.c_str(); + DFW_post_work_arg(transaction, dw2, &nameDesc, &schemaDesc, 0, dfw_arg_check_blr); } END_FOR request2.reset(tdbb, irq_m_fields8, IRQ_REQUESTS); FOR(REQUEST_HANDLE request2) - DEP IN RDB$DEPENDENCIES CROSS - FUN IN RDB$FUNCTIONS - WITH DEP.RDB$DEPENDED_ON_NAME EQ X.RDB$RELATION_NAME AND - DEP.RDB$FIELD_NAME EQ X.RDB$FIELD_NAME AND - DEP.RDB$DEPENDED_ON_TYPE EQ obj_relation AND - DEP.RDB$DEPENDENT_TYPE EQ obj_udf AND - DEP.RDB$DEPENDENT_NAME EQ FUN.RDB$FUNCTION_NAME AND - FUN.RDB$PACKAGE_NAME MISSING + DEP IN RDB$DEPENDENCIES + CROSS FUN IN RDB$FUNCTIONS + WITH DEP.RDB$DEPENDED_ON_SCHEMA_NAME EQ X.RDB$SCHEMA_NAME AND + DEP.RDB$DEPENDED_ON_NAME EQ X.RDB$RELATION_NAME AND + DEP.RDB$FIELD_NAME EQ X.RDB$FIELD_NAME AND + DEP.RDB$DEPENDED_ON_TYPE EQ obj_relation AND + DEP.RDB$DEPENDENT_TYPE EQ obj_udf AND + DEP.RDB$DEPENDENT_SCHEMA_NAME EQ FUN.RDB$SCHEMA_NAME AND + DEP.RDB$DEPENDENT_NAME EQ FUN.RDB$FUNCTION_NAME AND + FUN.RDB$PACKAGE_NAME MISSING { - MetaName name(FUN.RDB$FUNCTION_NAME); + QualifiedName funcName(FUN.RDB$FUNCTION_NAME, FUN.RDB$SCHEMA_NAME); - dsc desc; - desc.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str()); + dsc schemaDesc, nameDesc; + schemaDesc.makeText(funcName.schema.length(), CS_METADATA, (UCHAR*) funcName.schema.c_str()); + nameDesc.makeText(funcName.object.length(), CS_METADATA, (UCHAR*) funcName.object.c_str()); DeferredWork* dw2 = - DFW_post_work(transaction, dfw_modify_function, &desc, FUN.RDB$FUNCTION_ID); - DFW_post_work_arg(transaction, dw2, NULL, 0, dfw_arg_check_blr); + DFW_post_work(transaction, dfw_modify_function, &nameDesc, &schemaDesc, FUN.RDB$FUNCTION_ID); + DFW_post_work_arg(transaction, dw2, nullptr, nullptr, 0, dfw_arg_check_blr); } END_FOR } @@ -1069,44 +1082,49 @@ DeferredWork* MET_change_fields(thread_db* tdbb, jrd_tra* transaction, const dsc request.reset(tdbb, irq_m_fields2, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - DEP IN RDB$DEPENDENCIES CROSS - PRC IN RDB$PROCEDURES - WITH DEP.RDB$DEPENDED_ON_NAME EQ field_source->dsc_address AND - DEP.RDB$DEPENDED_ON_TYPE EQ obj_field AND - DEP.RDB$DEPENDENT_TYPE EQ obj_procedure AND - DEP.RDB$DEPENDENT_NAME EQ PRC.RDB$PROCEDURE_NAME AND - PRC.RDB$PACKAGE_NAME MISSING + DEP IN RDB$DEPENDENCIES + CROSS PRC IN RDB$PROCEDURES + WITH DEP.RDB$DEPENDED_ON_SCHEMA_NAME EQ schemaName->dsc_address AND + DEP.RDB$DEPENDED_ON_NAME EQ field_source->dsc_address AND + DEP.RDB$DEPENDED_ON_TYPE EQ obj_field AND + DEP.RDB$DEPENDENT_TYPE EQ obj_procedure AND + DEP.RDB$DEPENDENT_SCHEMA_NAME EQ PRC.RDB$SCHEMA_NAME AND + DEP.RDB$DEPENDENT_NAME EQ PRC.RDB$PROCEDURE_NAME AND + PRC.RDB$PACKAGE_NAME MISSING { - MetaName proc_name(PRC.RDB$PROCEDURE_NAME); + QualifiedName procName(PRC.RDB$PROCEDURE_NAME, PRC.RDB$SCHEMA_NAME); - dsc desc; - desc.makeText(proc_name.length(), CS_METADATA, (UCHAR*) proc_name.c_str()); + dsc schemaDesc, nameDesc; + schemaDesc.makeText(procName.schema.length(), CS_METADATA, (UCHAR*) procName.schema.c_str()); + nameDesc.makeText(procName.object.length(), CS_METADATA, (UCHAR*) procName.object.c_str()); DeferredWork* dw2 = - DFW_post_work(transaction, dfw_modify_procedure, &desc, PRC.RDB$PROCEDURE_ID); - DFW_post_work_arg(transaction, dw2, NULL, 0, dfw_arg_check_blr); + DFW_post_work(transaction, dfw_modify_procedure, &nameDesc, &schemaDesc, PRC.RDB$PROCEDURE_ID); + DFW_post_work_arg(transaction, dw2, nullptr, nullptr, 0, dfw_arg_check_blr); } END_FOR request.reset(tdbb, irq_m_fields6, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - DEP IN RDB$DEPENDENCIES CROSS - PRC IN RDB$PROCEDURES - WITH DEP.RDB$DEPENDED_ON_NAME EQ field_source->dsc_address AND - DEP.RDB$DEPENDED_ON_TYPE EQ obj_field AND - (DEP.RDB$DEPENDENT_TYPE EQ obj_package_header OR - DEP.RDB$DEPENDENT_TYPE EQ obj_package_body) AND - DEP.RDB$DEPENDENT_NAME EQ PRC.RDB$PACKAGE_NAME + DEP IN RDB$DEPENDENCIES + CROSS PRC IN RDB$PROCEDURES + WITH DEP.RDB$DEPENDED_ON_SCHEMA_NAME EQ schemaName->dsc_address AND + DEP.RDB$DEPENDED_ON_NAME EQ field_source->dsc_address AND + DEP.RDB$DEPENDED_ON_TYPE EQ obj_field AND + (DEP.RDB$DEPENDENT_TYPE EQ obj_package_header OR + DEP.RDB$DEPENDENT_TYPE EQ obj_package_body) AND + DEP.RDB$DEPENDENT_NAME EQ PRC.RDB$PACKAGE_NAME { - MetaName proc_name(PRC.RDB$PROCEDURE_NAME); + QualifiedName procName(PRC.RDB$PROCEDURE_NAME, PRC.RDB$SCHEMA_NAME); - dsc desc; - desc.makeText(proc_name.length(), CS_METADATA, (UCHAR*) proc_name.c_str()); + dsc schemaDesc, nameDesc; + schemaDesc.makeText(procName.schema.length(), CS_METADATA, (UCHAR*) procName.schema.c_str()); + nameDesc.makeText(procName.object.length(), CS_METADATA, (UCHAR*) procName.object.c_str()); - DeferredWork* dw2 = DFW_post_work(transaction, dfw_modify_procedure, &desc, + DeferredWork* dw2 = DFW_post_work(transaction, dfw_modify_procedure, &nameDesc, &schemaDesc, PRC.RDB$PROCEDURE_ID, PRC.RDB$PACKAGE_NAME); - DFW_post_work_arg(transaction, dw2, NULL, 0, dfw_arg_check_blr); + DFW_post_work_arg(transaction, dw2, nullptr, nullptr, 0, dfw_arg_check_blr); } END_FOR @@ -1115,23 +1133,25 @@ DeferredWork* MET_change_fields(thread_db* tdbb, jrd_tra* transaction, const dsc FOR(REQUEST_HANDLE request) DEP IN RDB$DEPENDENCIES CROSS TRG IN RDB$TRIGGERS - WITH DEP.RDB$DEPENDED_ON_NAME EQ field_source->dsc_address AND - DEP.RDB$DEPENDED_ON_TYPE EQ obj_field AND - DEP.RDB$DEPENDENT_TYPE EQ obj_trigger AND - DEP.RDB$DEPENDENT_NAME EQ TRG.RDB$TRIGGER_NAME + WITH DEP.RDB$DEPENDED_ON_SCHEMA_NAME EQ schemaName->dsc_address AND + DEP.RDB$DEPENDED_ON_NAME EQ field_source->dsc_address AND + DEP.RDB$DEPENDED_ON_TYPE EQ obj_field AND + DEP.RDB$DEPENDENT_TYPE EQ obj_trigger AND + DEP.RDB$DEPENDENT_NAME EQ TRG.RDB$TRIGGER_NAME { - MetaName trigger_name(TRG.RDB$TRIGGER_NAME); - MetaName trigger_relation_name(TRG.RDB$RELATION_NAME); + QualifiedName triggerName(TRG.RDB$TRIGGER_NAME, TRG.RDB$SCHEMA_NAME); + MetaName triggerRelationName(TRG.RDB$RELATION_NAME); - dsc desc; - desc.makeText(trigger_name.length(), CS_METADATA, (UCHAR*) trigger_name.c_str()); + dsc schemaDesc, nameDesc; + schemaDesc.makeText(triggerName.schema.length(), CS_METADATA, (UCHAR*) triggerName.schema.c_str()); + nameDesc.makeText(triggerName.object.length(), CS_METADATA, (UCHAR*) triggerName.object.c_str()); - DeferredWork* dw2 = DFW_post_work(transaction, dfw_modify_trigger, &desc, 0); - DFW_post_work_arg(transaction, dw2, NULL, TRG.RDB$TRIGGER_TYPE, dfw_arg_trg_type); + DeferredWork* dw2 = DFW_post_work(transaction, dfw_modify_trigger, &nameDesc, &schemaDesc, 0); + DFW_post_work_arg(transaction, dw2, nullptr, nullptr, TRG.RDB$TRIGGER_TYPE, dfw_arg_trg_type); - desc.dsc_length = trigger_relation_name.length(); - desc.dsc_address = (UCHAR*) trigger_relation_name.c_str(); - DFW_post_work_arg(transaction, dw2, &desc, 0, dfw_arg_check_blr); + nameDesc.dsc_length = triggerRelationName.length(); + nameDesc.dsc_address = (UCHAR*) triggerRelationName.c_str(); + DFW_post_work_arg(transaction, dw2, &nameDesc, &schemaDesc, 0, dfw_arg_check_blr); } END_FOR @@ -1140,20 +1160,22 @@ DeferredWork* MET_change_fields(thread_db* tdbb, jrd_tra* transaction, const dsc FOR(REQUEST_HANDLE request) DEP IN RDB$DEPENDENCIES CROSS FUN IN RDB$FUNCTIONS - WITH DEP.RDB$DEPENDED_ON_NAME EQ field_source->dsc_address AND - DEP.RDB$DEPENDED_ON_TYPE EQ obj_field AND - DEP.RDB$DEPENDENT_TYPE EQ obj_udf AND - DEP.RDB$DEPENDENT_NAME EQ FUN.RDB$FUNCTION_NAME AND - FUN.RDB$PACKAGE_NAME MISSING + WITH DEP.RDB$DEPENDED_ON_SCHEMA_NAME EQ schemaName->dsc_address AND + DEP.RDB$DEPENDED_ON_NAME EQ field_source->dsc_address AND + DEP.RDB$DEPENDED_ON_TYPE EQ obj_field AND + DEP.RDB$DEPENDENT_TYPE EQ obj_udf AND + DEP.RDB$DEPENDENT_NAME EQ FUN.RDB$FUNCTION_NAME AND + FUN.RDB$PACKAGE_NAME MISSING { - MetaName name(FUN.RDB$FUNCTION_NAME); + QualifiedName funcName(FUN.RDB$FUNCTION_NAME, FUN.RDB$SCHEMA_NAME); - dsc desc; - desc.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str()); + dsc schemaDesc, nameDesc; + schemaDesc.makeText(funcName.schema.length(), CS_METADATA, (UCHAR*) funcName.schema.c_str()); + nameDesc.makeText(funcName.object.length(), CS_METADATA, (UCHAR*) funcName.object.c_str()); DeferredWork* dw2 = - DFW_post_work(transaction, dfw_modify_function, &desc, FUN.RDB$FUNCTION_ID); - DFW_post_work_arg(transaction, dw2, NULL, 0, dfw_arg_check_blr); + DFW_post_work(transaction, dfw_modify_function, &nameDesc, &schemaDesc, FUN.RDB$FUNCTION_ID); + DFW_post_work_arg(transaction, dw2, nullptr, nullptr, 0, dfw_arg_check_blr); } END_FOR @@ -1162,20 +1184,22 @@ DeferredWork* MET_change_fields(thread_db* tdbb, jrd_tra* transaction, const dsc FOR(REQUEST_HANDLE request) DEP IN RDB$DEPENDENCIES CROSS FUN IN RDB$FUNCTIONS - WITH DEP.RDB$DEPENDED_ON_NAME EQ field_source->dsc_address AND - DEP.RDB$DEPENDED_ON_TYPE EQ obj_field AND - (DEP.RDB$DEPENDENT_TYPE EQ obj_package_header OR - DEP.RDB$DEPENDENT_TYPE EQ obj_package_body) AND - DEP.RDB$DEPENDENT_NAME EQ FUN.RDB$PACKAGE_NAME + WITH DEP.RDB$DEPENDED_ON_SCHEMA_NAME EQ schemaName->dsc_address AND + DEP.RDB$DEPENDED_ON_NAME EQ field_source->dsc_address AND + DEP.RDB$DEPENDED_ON_TYPE EQ obj_field AND + (DEP.RDB$DEPENDENT_TYPE EQ obj_package_header OR + DEP.RDB$DEPENDENT_TYPE EQ obj_package_body) AND + DEP.RDB$DEPENDENT_NAME EQ FUN.RDB$PACKAGE_NAME { - MetaName name(FUN.RDB$FUNCTION_NAME); + QualifiedName funcName(FUN.RDB$FUNCTION_NAME, FUN.RDB$SCHEMA_NAME); - dsc desc; - desc.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str()); + dsc schemaDesc, nameDesc; + schemaDesc.makeText(funcName.schema.length(), CS_METADATA, (UCHAR*) funcName.schema.c_str()); + nameDesc.makeText(funcName.object.length(), CS_METADATA, (UCHAR*) funcName.object.c_str()); - DeferredWork* dw2 = DFW_post_work(transaction, dfw_modify_function, &desc, + DeferredWork* dw2 = DFW_post_work(transaction, dfw_modify_function, &nameDesc, &schemaDesc, FUN.RDB$FUNCTION_ID, FUN.RDB$PACKAGE_NAME); - DFW_post_work_arg(transaction, dw2, NULL, 0, dfw_arg_check_blr); + DFW_post_work_arg(transaction, dw2, nullptr, nullptr, 0, dfw_arg_check_blr); } END_FOR @@ -1238,7 +1262,7 @@ Format* MET_current(thread_db* tdbb, jrd_rel* relation) void MET_delete_dependencies(thread_db* tdbb, - const MetaName& object_name, + const QualifiedName& object_name, int dependency_type, jrd_tra* transaction) { @@ -1255,15 +1279,13 @@ void MET_delete_dependencies(thread_db* tdbb, **************************************/ SET_TDBB(tdbb); -// if (!object_name) -// return; -// AutoCacheRequest request(tdbb, irq_d_deps, IRQ_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) DEP IN RDB$DEPENDENCIES - WITH DEP.RDB$DEPENDENT_NAME = object_name.c_str() - AND DEP.RDB$DEPENDENT_TYPE = dependency_type + WITH DEP.RDB$DEPENDENT_SCHEMA_NAME EQUIV NULLIF(object_name.schema.c_str(), '') AND + DEP.RDB$DEPENDENT_NAME = object_name.object.c_str() AND + DEP.RDB$DEPENDENT_TYPE = dependency_type { ERASE DEP; } @@ -1309,13 +1331,12 @@ void MET_delete_shadow(thread_db* tdbb, USHORT shadow_number) } -bool MET_dsql_cache_use(thread_db* tdbb, sym_type type, const MetaName& name, const MetaName& package) +bool MET_dsql_cache_use(thread_db* tdbb, sym_type type, const QualifiedName& name) { - const QualifiedName qualifiedName(name, package); - DSqlCacheItem* item = get_dsql_cache_item(tdbb, type, qualifiedName); + DSqlCacheItem* item = get_dsql_cache_item(tdbb, type, name); bool obsolete = false; - item->obsoleteMap.get(qualifiedName, obsolete); + item->obsoleteMap.get(name, obsolete); if (!item->locked) { @@ -1324,16 +1345,15 @@ bool MET_dsql_cache_use(thread_db* tdbb, sym_type type, const MetaName& name, co item->locked = true; } - item->obsoleteMap.put(qualifiedName, false); + item->obsoleteMap.put(name, false); return obsolete; } -void MET_dsql_cache_release(thread_db* tdbb, sym_type type, const MetaName& name, const MetaName& package) +void MET_dsql_cache_release(thread_db* tdbb, sym_type type, const QualifiedName& name) { - const QualifiedName qualifiedName(name, package); - DSqlCacheItem* item = get_dsql_cache_item(tdbb, type, qualifiedName); + DSqlCacheItem* item = get_dsql_cache_item(tdbb, type, name); // release the shared lock LCK_release(tdbb, item->lock); @@ -1348,9 +1368,9 @@ void MET_dsql_cache_release(thread_db* tdbb, sym_type type, const MetaName& name item->locked = false; - GenericMap > >::Accessor accessor(&item->obsoleteMap); + LeftPooledMap::Accessor accessor(&item->obsoleteMap); for (bool found = accessor.getFirst(); found; found = accessor.getNext()) - accessor.current()->second = accessor.current()->first != qualifiedName; + accessor.current()->second = accessor.current()->first != name; } @@ -1475,67 +1495,22 @@ Format* MET_format(thread_db* tdbb, jrd_rel* relation, USHORT number) } -bool MET_get_char_coll_subtype(thread_db* tdbb, USHORT* id, const UCHAR* name, USHORT length) +// Return: +// true if no errors (and *id is set). +// false if the name could not be resolved. +bool MET_get_char_coll_subtype(thread_db* tdbb, USHORT* id, const QualifiedName& name) { -/************************************** - * - * M E T _ g e t _ c h a r _ c o l l _ s u b t y p e - * - ************************************** - * - * Functional description - * Character types can be specified as either: - * a) A POSIX style locale name "." - * or - * b) A simple name (using default collation) - * c) A simple name (use charset for collation) - * - * Given an ASCII7 string which could be any of the above, try to - * resolve the name in the order a, b, c - * a) is only tried iff the name contains a period. - * (in which case b) and c) are not tried). - * - * Return: - * 1 if no errors (and *id is set). - * 0 if the name could not be resolved. - * - **************************************/ SET_TDBB(tdbb); - fb_assert(id != NULL); - fb_assert(name != NULL); + fb_assert(id); - const UCHAR* const end_name = name + length; - - // Force key to uppercase, following C locale rules for uppercasing - // At the same time, search for the first period in the string (if any) - UCHAR buffer[MAX_SQL_IDENTIFIER_SIZE]; // BASED ON RDB$COLLATION_NAME - UCHAR* p = buffer; - UCHAR* period = NULL; - for (; name < end_name && p < buffer + sizeof(buffer) - 1; p++, name++) - { - *p = UPPER7(*name); - if ((*p == '.') && !period) { - period = p; - } - } - *p = 0; - - // Is there a period, separating collation name from character set? - if (period) - { - *period = 0; - return resolve_charset_and_collation(tdbb, id, period + 1, buffer); - } - - // Is it a character set name (implying charset default collation sequence) - - bool res = resolve_charset_and_collation(tdbb, id, buffer, NULL); + bool res = resolve_charset_and_collation(tdbb, id, name, {}); if (!res) { // Is it a collation name (implying implementation-default character set) - res = resolve_charset_and_collation(tdbb, id, NULL, buffer); + res = resolve_charset_and_collation(tdbb, id, {}, name); } + return res; } @@ -1573,13 +1548,16 @@ bool MET_get_char_coll_subtype_info(thread_db* tdbb, USHORT id, SubtypeInfo* inf { found = true; - info->charsetName = CS.RDB$CHARACTER_SET_NAME; - info->collationName = CL.RDB$COLLATION_NAME; + info->charsetName = QualifiedName(CS.RDB$CHARACTER_SET_NAME, CS.RDB$SCHEMA_NAME); + info->collationName = QualifiedName(CL.RDB$COLLATION_NAME, CL.RDB$SCHEMA_NAME); if (CL.RDB$BASE_COLLATION_NAME.NULL) - info->baseCollationName = info->collationName; + info->baseCollationName = info->collationName.object.c_str(); else + { info->baseCollationName = CL.RDB$BASE_COLLATION_NAME; + info->baseCollationName.rtrim(); + } if (CL.RDB$SPECIFIC_ATTRIBUTES.NULL) info->specificAttributes.clear(); @@ -1610,11 +1588,11 @@ DmlNode* MET_get_dependencies(thread_db* tdbb, bid* blob_id, Statement** statementPtr, CompilerScratch** csb_ptr, - const MetaName& object_name, + const QualifiedName& object_name, int type, USHORT flags, jrd_tra* transaction, - const MetaName& domain_validation) + const QualifiedName& domain_validation) { /************************************** * @@ -1630,7 +1608,7 @@ DmlNode* MET_get_dependencies(thread_db* tdbb, SET_TDBB(tdbb); Attachment* attachment = tdbb->getAttachment(); - fb_assert(domain_validation.isEmpty() || object_name == domain_validation); // for now + fb_assert(domain_validation.object.isEmpty() || object_name == domain_validation); // for now MemoryPool& pool = *tdbb->getDefaultPool(); AutoPtr auto_csb(FB_NEW_POOL(pool) CompilerScratch(pool)); @@ -1643,32 +1621,37 @@ DmlNode* MET_get_dependencies(thread_db* tdbb, if (blob) { - node = PAR_blr(tdbb, relation, blob, blob_length, view_csb, &csb, statementPtr, + node = PAR_blr(tdbb, &object_name.schema, relation, blob, blob_length, view_csb, &csb, statementPtr, (type == obj_trigger && relation != NULL), 0); } else { - node = MET_parse_blob(tdbb, relation, blob_id, &csb, statementPtr, + node = MET_parse_blob(tdbb, &object_name.schema, relation, blob_id, &csb, statementPtr, (type == obj_trigger && relation != NULL), type == obj_validation); } if (type == obj_computed) { - MetaName domainName; + QualifiedName domainName; - AutoRequest handle; + static const CachedRequestId cachedHandleId; + AutoCacheRequest handle(tdbb, cachedHandleId); FOR(REQUEST_HANDLE handle) - RLF IN RDB$RELATION_FIELDS CROSS - FLD IN RDB$FIELDS WITH - RLF.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND - RLF.RDB$RELATION_NAME EQ relation->rel_name.c_str() AND - RLF.RDB$FIELD_NAME EQ object_name.c_str() + RFL IN RDB$RELATION_FIELDS CROSS + FLD IN RDB$FIELDS + WITH RFL.RDB$SCHEMA_NAME EQ relation->rel_name.schema.c_str() AND + RFL.RDB$RELATION_NAME EQ relation->rel_name.object.c_str() AND + RFL.RDB$FIELD_NAME EQ object_name.object.c_str() AND + FLD.RDB$SCHEMA_NAME EQ RFL.RDB$FIELD_SOURCE_SCHEMA_NAME AND + FLD.RDB$FIELD_NAME EQ RFL.RDB$FIELD_SOURCE { - domainName = FLD.RDB$FIELD_NAME; + domainName = QualifiedName(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME); } END_FOR + fb_assert(domainName.object.hasData()); + if (type != obj_package_body) MET_delete_dependencies(tdbb, domainName, type, transaction); @@ -1711,7 +1694,7 @@ jrd_fld* MET_get_field(const jrd_rel* relation, USHORT id) } -bool MET_get_repl_state(Jrd::thread_db* tdbb, const MetaName& name) +bool MET_get_repl_state(Jrd::thread_db* tdbb, const QualifiedName& name) { /************************************** * @@ -1730,11 +1713,12 @@ bool MET_get_repl_state(Jrd::thread_db* tdbb, const MetaName& name) AutoRequest handle; bool state = false; - if (name.hasData()) + if (name.object.hasData()) { FOR(REQUEST_HANDLE handle) PTAB IN RDB$PUBLICATION_TABLES - WITH PTAB.RDB$TABLE_NAME EQ name.c_str() + WITH PTAB.RDB$TABLE_SCHEMA_NAME EQ name.schema.c_str() AND + PTAB.RDB$TABLE_NAME EQ name.object.c_str() { state = true; break; @@ -1860,7 +1844,8 @@ void MET_load_db_triggers(thread_db* tdbb, int type) TRG.RDB$TRIGGER_INACTIVE EQ 0 SORTED BY TRG.RDB$TRIGGER_SEQUENCE { - MET_load_trigger(tdbb, NULL, TRG.RDB$TRIGGER_NAME, &attachment->att_triggers[type]); + MET_load_trigger(tdbb, nullptr, QualifiedName(TRG.RDB$TRIGGER_NAME, TRG.RDB$SCHEMA_NAME), + &attachment->att_triggers[type]); } END_FOR } @@ -1894,7 +1879,7 @@ void MET_load_ddl_triggers(thread_db* tdbb) { if ((TRG.RDB$TRIGGER_TYPE & TRIGGER_TYPE_MASK) == TRIGGER_TYPE_DDL) { - MET_load_trigger(tdbb, NULL, TRG.RDB$TRIGGER_NAME, + MET_load_trigger(tdbb, nullptr, QualifiedName(TRG.RDB$TRIGGER_NAME, TRG.RDB$SCHEMA_NAME), &attachment->att_ddl_triggers); } } @@ -1904,7 +1889,7 @@ void MET_load_ddl_triggers(thread_db* tdbb) void MET_load_trigger(thread_db* tdbb, jrd_rel* relation, - const MetaName& trigger_name, + const QualifiedName& trigger_name, TrigVector** triggers) { /************************************** @@ -1941,7 +1926,8 @@ void MET_load_trigger(thread_db* tdbb, FOR(REQUEST_HANDLE request) TRG IN RDB$TRIGGERS - WITH TRG.RDB$TRIGGER_NAME EQ trigger_name.c_str() AND + WITH TRG.RDB$SCHEMA_NAME EQ trigger_name.schema.c_str() AND + TRG.RDB$TRIGGER_NAME EQ trigger_name.object.c_str() AND (TRG.RDB$TRIGGER_INACTIVE MISSING OR TRG.RDB$TRIGGER_INACTIVE EQ 0) { // check if the trigger is to be fired without any permissions @@ -1952,7 +1938,7 @@ void MET_load_trigger(thread_db* tdbb, if ((TRG.RDB$FLAGS & TRG_ignore_perm) && !verify_TRG_ignore_perm(tdbb, trigger_name)) { fb_msg_format(NULL, FB_IMPL_MSG_FACILITY_JRD_BUGCHK, 304, sizeof(errmsg), - errmsg, MsgFormat::SafeArg() << trigger_name.c_str()); + errmsg, MsgFormat::SafeArg() << trigger_name.toQuotedString().c_str()); ERR_log(FB_IMPL_MSG_FACILITY_JRD_BUGCHK, 304, errmsg); trig_flags &= ~TRG_ignore_perm; @@ -2000,7 +1986,7 @@ void MET_load_trigger(thread_db* tdbb, &TRG.RDB$TRIGGER_BLR, &debug_blob_id, triggers, - TRG.RDB$TRIGGER_NAME, + trigger_name, TRG.RDB$TRIGGER_TYPE, (bool) TRG.RDB$SYSTEM_FLAG, trig_flags, @@ -2021,7 +2007,7 @@ void MET_load_trigger(thread_db* tdbb, &TRG.RDB$TRIGGER_BLR, &debug_blob_id, triggers + trigger_action, - TRG.RDB$TRIGGER_NAME, + trigger_name, (UCHAR) trigger_action, (bool) TRG.RDB$SYSTEM_FLAG, trig_flags, @@ -2039,7 +2025,7 @@ void MET_load_trigger(thread_db* tdbb, void MET_lookup_cnstrt_for_index(thread_db* tdbb, MetaName& constraint_name, - const MetaName& index_name) + const QualifiedName& index_name) { /************************************** * @@ -2059,7 +2045,9 @@ void MET_lookup_cnstrt_for_index(thread_db* tdbb, AutoCacheRequest request(tdbb, irq_l_cnstrt, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - X IN RDB$RELATION_CONSTRAINTS WITH X.RDB$INDEX_NAME EQ index_name.c_str() + X IN RDB$RELATION_CONSTRAINTS + WITH X.RDB$SCHEMA_NAME EQ index_name.schema.c_str() AND + X.RDB$INDEX_NAME EQ index_name.object.c_str() { constraint_name = X.RDB$CONSTRAINT_NAME; } @@ -2069,8 +2057,8 @@ void MET_lookup_cnstrt_for_index(thread_db* tdbb, void MET_lookup_cnstrt_for_trigger(thread_db* tdbb, MetaName& constraint_name, - MetaName& relation_name, - const MetaName& trigger_name) + QualifiedName& relation_name, + const QualifiedName& trigger_name) { /************************************** * @@ -2087,7 +2075,8 @@ void MET_lookup_cnstrt_for_trigger(thread_db* tdbb, Attachment* attachment = tdbb->getAttachment(); constraint_name = ""; - relation_name = ""; + relation_name.clear(); + AutoCacheRequest request(tdbb, irq_l_check, IRQ_REQUESTS); AutoCacheRequest request2(tdbb, irq_l_check2, IRQ_REQUESTS); @@ -2097,18 +2086,20 @@ void MET_lookup_cnstrt_for_trigger(thread_db* tdbb, // have a check constraint defined for that trigger FOR(REQUEST_HANDLE request) - Y IN RDB$TRIGGERS WITH - Y.RDB$TRIGGER_NAME EQ trigger_name.c_str() + Y IN RDB$TRIGGERS + WITH Y.RDB$SCHEMA_NAME EQ trigger_name.schema.c_str() AND + Y.RDB$TRIGGER_NAME EQ trigger_name.object.c_str() { FOR(REQUEST_HANDLE request2) - X IN RDB$CHECK_CONSTRAINTS WITH - X.RDB$TRIGGER_NAME EQ Y.RDB$TRIGGER_NAME + X IN RDB$CHECK_CONSTRAINTS + WITH X.RDB$SCHEMA_NAME EQ Y.RDB$SCHEMA_NAME AND + X.RDB$TRIGGER_NAME EQ Y.RDB$TRIGGER_NAME { constraint_name = X.RDB$CONSTRAINT_NAME; } END_FOR - relation_name = Y.RDB$RELATION_NAME; + relation_name = QualifiedName(Y.RDB$RELATION_NAME, Y.RDB$SCHEMA_NAME); } END_FOR } @@ -2116,7 +2107,7 @@ void MET_lookup_cnstrt_for_trigger(thread_db* tdbb, void MET_lookup_exception(thread_db* tdbb, SLONG number, - MetaName& name, + QualifiedName& name, string* message) { /************************************** @@ -2136,15 +2127,15 @@ void MET_lookup_exception(thread_db* tdbb, AutoCacheRequest request(tdbb, irq_l_exception, IRQ_REQUESTS); - name = ""; + name.clear(); if (message) - *message = ""; + message->clear(); FOR(REQUEST_HANDLE request) X IN RDB$EXCEPTIONS WITH X.RDB$EXCEPTION_NUMBER = number { if (!X.RDB$EXCEPTION_NAME.NULL) - name = X.RDB$EXCEPTION_NAME; + name = QualifiedName(X.RDB$EXCEPTION_NAME, X.RDB$SCHEMA_NAME); if (!X.RDB$MESSAGE.NULL && message) *message = X.RDB$MESSAGE; @@ -2173,12 +2164,15 @@ bool MET_load_exception(thread_db* tdbb, ExceptionItem& item) AutoCacheRequest request(tdbb, irq_l_except_no, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - X IN RDB$EXCEPTIONS WITH X.RDB$EXCEPTION_NAME = item.name.c_str() + XCP IN RDB$EXCEPTIONS + CROSS SCH IN RDB$SCHEMAS + WITH XCP.RDB$SCHEMA_NAME = item.name.schema.c_str() AND + XCP.RDB$EXCEPTION_NAME = item.name.object.c_str() AND + SCH.RDB$SCHEMA_NAME = XCP.RDB$SCHEMA_NAME { item.type = ExceptionItem::XCP_CODE; - item.code = X.RDB$EXCEPTION_NUMBER; - item.secName = X.RDB$SECURITY_CLASS; - + item.code = XCP.RDB$EXCEPTION_NUMBER; + item.secName = QualifiedName(XCP.RDB$SECURITY_CLASS, SCH.RDB$SECURITY_CLASS); return true; } END_FOR @@ -2236,10 +2230,11 @@ int MET_lookup_field(thread_db* tdbb, jrd_rel* relation, const MetaName& name) AutoCacheRequest request(tdbb, irq_l_field, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - X IN RDB$RELATION_FIELDS WITH - X.RDB$RELATION_NAME EQ relation->rel_name.c_str() AND - X.RDB$FIELD_ID NOT MISSING AND - X.RDB$FIELD_NAME EQ name.c_str() + X IN RDB$RELATION_FIELDS + WITH X.RDB$SCHEMA_NAME EQ relation->rel_name.schema.c_str() AND + X.RDB$RELATION_NAME EQ relation->rel_name.object.c_str() AND + X.RDB$FIELD_ID NOT MISSING AND + X.RDB$FIELD_NAME EQ name.c_str() { id = X.RDB$FIELD_ID; } @@ -2307,7 +2302,7 @@ bool MET_load_generator(thread_db* tdbb, GeneratorItem& item, bool* sysGen, SLON SET_TDBB(tdbb); Attachment* attachment = tdbb->getAttachment(); - if (item.name == MASTER_GENERATOR) + if (item.name == QualifiedName(MASTER_GENERATOR, SYSTEM_SCHEMA)) { item.id = 0; if (sysGen) @@ -2320,14 +2315,20 @@ bool MET_load_generator(thread_db* tdbb, GeneratorItem& item, bool* sysGen, SLON AutoCacheRequest request(tdbb, irq_r_gen_id, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - X IN RDB$GENERATORS WITH X.RDB$GENERATOR_NAME EQ item.name.c_str() + GEN IN RDB$GENERATORS + CROSS SCH IN RDB$SCHEMAS + WITH GEN.RDB$SCHEMA_NAME EQ item.name.schema.c_str() AND + GEN.RDB$GENERATOR_NAME EQ item.name.object.c_str() AND + SCH.RDB$SCHEMA_NAME = GEN.RDB$SCHEMA_NAME { - item.id = X.RDB$GENERATOR_ID; - item.secName = X.RDB$SECURITY_CLASS; + item.id = GEN.RDB$GENERATOR_ID; + item.secName = QualifiedName(GEN.RDB$SECURITY_CLASS, SCH.RDB$SECURITY_CLASS); + if (sysGen) - *sysGen = (X.RDB$SYSTEM_FLAG == fb_sysflag_system); + *sysGen = (GEN.RDB$SYSTEM_FLAG == fb_sysflag_system); + if (step) - *step = X.RDB$GENERATOR_INCREMENT; + *step = GEN.RDB$GENERATOR_INCREMENT; return true; } @@ -2336,7 +2337,7 @@ bool MET_load_generator(thread_db* tdbb, GeneratorItem& item, bool* sysGen, SLON return false; } -SLONG MET_lookup_generator(thread_db* tdbb, const MetaName& name, bool* sysGen, SLONG* step) +SLONG MET_lookup_generator(thread_db* tdbb, const QualifiedName& name, bool* sysGen, SLONG* step) { /************************************** * @@ -2351,7 +2352,7 @@ SLONG MET_lookup_generator(thread_db* tdbb, const MetaName& name, bool* sysGen, SET_TDBB(tdbb); Attachment* attachment = tdbb->getAttachment(); - if (name == MASTER_GENERATOR) + if (name == QualifiedName(MASTER_GENERATOR, SYSTEM_SCHEMA)) { if (sysGen) *sysGen = true; @@ -2363,7 +2364,9 @@ SLONG MET_lookup_generator(thread_db* tdbb, const MetaName& name, bool* sysGen, AutoCacheRequest request(tdbb, irq_l_gen_id, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - X IN RDB$GENERATORS WITH X.RDB$GENERATOR_NAME EQ name.c_str() + X IN RDB$GENERATORS + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$GENERATOR_NAME EQ name.object.c_str() { if (sysGen) *sysGen = (X.RDB$SYSTEM_FLAG == fb_sysflag_system); @@ -2377,7 +2380,7 @@ SLONG MET_lookup_generator(thread_db* tdbb, const MetaName& name, bool* sysGen, return -1; } -bool MET_lookup_generator_id(thread_db* tdbb, SLONG gen_id, MetaName& name, bool* sysGen) +bool MET_lookup_generator_id(thread_db* tdbb, SLONG gen_id, QualifiedName& name, bool* sysGen) { /************************************** * @@ -2395,7 +2398,7 @@ bool MET_lookup_generator_id(thread_db* tdbb, SLONG gen_id, MetaName& name, bool fb_assert(gen_id != 0); - name = ""; + name.clear(); AutoCacheRequest request(tdbb, irq_r_gen_id_num, IRQ_REQUESTS); @@ -2405,11 +2408,11 @@ bool MET_lookup_generator_id(thread_db* tdbb, SLONG gen_id, MetaName& name, bool if (sysGen) *sysGen = (X.RDB$SYSTEM_FLAG == fb_sysflag_system); - name = X.RDB$GENERATOR_NAME; + name = QualifiedName(X.RDB$GENERATOR_NAME, X.RDB$SCHEMA_NAME); } END_FOR - return name.hasData(); + return name.object.hasData(); } void MET_update_generator_increment(thread_db* tdbb, SLONG gen_id, SLONG step) @@ -2445,8 +2448,8 @@ void MET_update_generator_increment(thread_db* tdbb, SLONG gen_id, SLONG step) void MET_lookup_index(thread_db* tdbb, - MetaName& index_name, - const MetaName& relation_name, + QualifiedName& index_name, + const QualifiedName& relation_name, USHORT number) { /************************************** @@ -2463,22 +2466,24 @@ void MET_lookup_index(thread_db* tdbb, SET_TDBB(tdbb); Attachment* attachment = tdbb->getAttachment(); - index_name = ""; + index_name.clear(); AutoCacheRequest request(tdbb, irq_l_index, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - X IN RDB$INDICES WITH X.RDB$RELATION_NAME EQ relation_name.c_str() - AND X.RDB$INDEX_ID EQ number + X IN RDB$INDICES + WITH X.RDB$SCHEMA_NAME EQ relation_name.schema.c_str() AND + X.RDB$RELATION_NAME EQ relation_name.object.c_str() AND + X.RDB$INDEX_ID EQ number { - index_name = X.RDB$INDEX_NAME; + index_name = QualifiedName(X.RDB$INDEX_NAME, X.RDB$SCHEMA_NAME); } END_FOR } SLONG MET_lookup_index_name(thread_db* tdbb, - const MetaName& index_name, + const QualifiedName& index_name, SLONG* relation_id, IndexStatus* status) { /************************************** @@ -2501,8 +2506,9 @@ SLONG MET_lookup_index_name(thread_db* tdbb, *status = MET_object_unknown; FOR(REQUEST_HANDLE request) - X IN RDB$INDICES WITH - X.RDB$INDEX_NAME EQ index_name.c_str() + X IN RDB$INDICES + WITH X.RDB$SCHEMA_NAME EQ index_name.schema.c_str() AND + X.RDB$INDEX_NAME EQ index_name.object.c_str() { if (X.RDB$INDEX_INACTIVE == 0) *status = MET_object_active; @@ -2512,7 +2518,7 @@ SLONG MET_lookup_index_name(thread_db* tdbb, *status = MET_object_inactive; id = X.RDB$INDEX_ID - 1; - const jrd_rel* relation = MET_lookup_relation(tdbb, X.RDB$RELATION_NAME); + const jrd_rel* relation = MET_lookup_relation(tdbb, QualifiedName(X.RDB$RELATION_NAME, X.RDB$SCHEMA_NAME)); *relation_id = relation->rel_id; } END_FOR @@ -2564,9 +2570,10 @@ void MET_lookup_index_condition(thread_db* tdbb, jrd_rel* relation, index_desc* AutoCacheRequest request(tdbb, irq_l_cond_index, 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->idx_id + 1 + IDX IN RDB$INDICES + WITH IDX.RDB$SCHEMA_NAME EQ relation->rel_name.schema.c_str() AND + IDX.RDB$RELATION_NAME EQ relation->rel_name.object.c_str() AND + IDX.RDB$INDEX_ID EQ idx->idx_id + 1 { if (idx->idx_condition_statement) { @@ -2581,7 +2588,8 @@ void MET_lookup_index_condition(thread_db* tdbb, jrd_rel* relation, index_desc* { // scope Jrd::ContextPoolHolder context(tdbb, attachment->createPool()); - MET_parse_blob(tdbb, relation, &IDX.RDB$CONDITION_BLR, &csb, nullptr, false, false); + MET_parse_blob(tdbb, &relation->rel_name.schema, relation, &IDX.RDB$CONDITION_BLR, &csb, + nullptr, false, false); idx->idx_condition_statement = Statement::makeBoolExpression(tdbb, idx->idx_condition, csb, false); @@ -2655,9 +2663,10 @@ void MET_lookup_index_expression(thread_db* tdbb, jrd_rel* relation, index_desc* AutoCacheRequest request(tdbb, irq_l_exp_index, 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->idx_id + 1 + IDX IN RDB$INDICES + WITH IDX.RDB$SCHEMA_NAME EQ relation->rel_name.schema.c_str() AND + IDX.RDB$RELATION_NAME EQ relation->rel_name.object.c_str() AND + IDX.RDB$INDEX_ID EQ idx->idx_id + 1 { if (idx->idx_expression_statement) { @@ -2672,7 +2681,8 @@ void MET_lookup_index_expression(thread_db* tdbb, jrd_rel* relation, index_desc* { // scope Jrd::ContextPoolHolder context(tdbb, attachment->createPool()); - MET_parse_blob(tdbb, relation, &IDX.RDB$EXPRESSION_BLR, &csb, nullptr, false, false); + MET_parse_blob(tdbb, &relation->rel_name.schema, relation, &IDX.RDB$EXPRESSION_BLR, &csb, + nullptr, false, false); idx->idx_expression_statement = Statement::makeValueExpression(tdbb, idx->idx_expression, idx->idx_expression_desc, csb, false); @@ -2706,7 +2716,8 @@ void MET_lookup_index_expression(thread_db* tdbb, jrd_rel* relation, index_desc* } -bool MET_lookup_index_expr_cond_blr(thread_db* tdbb, const MetaName& index_name, bid& expr_blob_id, bid& cond_blob_id) +bool MET_lookup_index_expr_cond_blr(thread_db* tdbb, const QualifiedName& index_name, + bid& expr_blob_id, bid& cond_blob_id) { /************************************** * @@ -2728,8 +2739,9 @@ bool MET_lookup_index_expr_cond_blr(thread_db* tdbb, const MetaName& index_name, AutoCacheRequest request(tdbb, irq_l_exp_index_blr, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - IDX IN RDB$INDICES WITH - IDX.RDB$INDEX_NAME EQ index_name.c_str() + IDX IN RDB$INDICES + WITH IDX.RDB$SCHEMA_NAME EQ index_name.schema.c_str() AND + IDX.RDB$INDEX_NAME EQ index_name.object.c_str() { found = !IDX.RDB$EXPRESSION_BLR.NULL || !IDX.RDB$CONDITION_BLR.NULL; expr_blob_id = IDX.RDB$EXPRESSION_BLR; @@ -2741,7 +2753,7 @@ bool MET_lookup_index_expr_cond_blr(thread_db* tdbb, const MetaName& index_name, } -bool MET_lookup_partner(thread_db* tdbb, jrd_rel* relation, index_desc* idx, const TEXT* index_name) +bool MET_lookup_partner(thread_db* tdbb, jrd_rel* relation, index_desc* idx, const QualifiedName& index_name) { /************************************** * @@ -2756,6 +2768,9 @@ bool MET_lookup_partner(thread_db* tdbb, jrd_rel* relation, index_desc* idx, con **************************************/ SET_TDBB(tdbb); + + fb_assert(index_name.object.isEmpty() || index_name.schema == relation->rel_name.schema); + Attachment* attachment = tdbb->getAttachment(); if (relation->rel_flags & REL_check_partners) @@ -2763,7 +2778,7 @@ bool MET_lookup_partner(thread_db* tdbb, jrd_rel* relation, index_desc* idx, con if (idx->idx_flags & idx_foreign) { - if (index_name) + if (index_name.object.hasData()) { // Since primary key index names aren't being cached, do a long // hard lookup. This is only called during index create for foreign keys. @@ -2774,15 +2789,19 @@ bool MET_lookup_partner(thread_db* tdbb, jrd_rel* relation, index_desc* idx, con FOR(REQUEST_HANDLE request) IDX IN RDB$INDICES CROSS IND IN RDB$INDICES WITH - IDX.RDB$RELATION_NAME EQ relation->rel_name.c_str() AND + IDX.RDB$SCHEMA_NAME EQ relation->rel_name.schema.c_str() AND + IDX.RDB$RELATION_NAME EQ relation->rel_name.object.c_str() AND (IDX.RDB$INDEX_ID EQ idx->idx_id + 1 OR - IDX.RDB$INDEX_NAME EQ index_name) AND + IDX.RDB$INDEX_NAME EQ index_name.object.c_str()) AND + IND.RDB$SCHEMA_NAME EQ IDX.RDB$FOREIGN_KEY_SCHEMA_NAME AND IND.RDB$INDEX_NAME EQ IDX.RDB$FOREIGN_KEY AND IND.RDB$UNIQUE_FLAG = 1 { + const QualifiedName partnerRelationName(IND.RDB$RELATION_NAME, IND.RDB$SCHEMA_NAME); + //// ASF: Hack fix for CORE-4304, until nasty interactions between dfw and met are not resolved. - const jrd_rel* partner_relation = relation->rel_name == IND.RDB$RELATION_NAME ? - relation : MET_lookup_relation(tdbb, IND.RDB$RELATION_NAME); + const jrd_rel* partner_relation = relation->rel_name == partnerRelationName ? + relation : MET_lookup_relation(tdbb, partnerRelationName); if (partner_relation && !IDX.RDB$INDEX_INACTIVE && !IND.RDB$INDEX_INACTIVE) { @@ -2857,9 +2876,9 @@ jrd_prc* MET_lookup_procedure(thread_db* tdbb, const QualifiedName& name, bool n jrd_prc* check_procedure = NULL; // See if we already know the procedure by name - for (jrd_prc** iter = attachment->att_procedures.begin(); iter != attachment->att_procedures.end(); ++iter) + for (auto iter = attachment->att_procedures.begin(); iter != attachment->att_procedures.end(); ++iter) { - jrd_prc* procedure = *iter; + const auto procedure = *iter; if (procedure && !(procedure->flags & Routine::FLAG_OBSOLETE) && !(procedure->flags & Routine::FLAG_CLEARED) && @@ -2889,7 +2908,8 @@ jrd_prc* MET_lookup_procedure(thread_db* tdbb, const QualifiedName& name, bool n FOR(REQUEST_HANDLE request) P IN RDB$PROCEDURES - WITH P.RDB$PROCEDURE_NAME EQ name.identifier.c_str() AND + WITH P.RDB$SCHEMA_NAME EQUIV NULLIF(name.schema.c_str(), '') AND + P.RDB$PROCEDURE_NAME EQ name.object.c_str() AND P.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') { procedure = MET_procedure(tdbb, P.RDB$PROCEDURE_ID, noscan, 0); @@ -2974,7 +2994,7 @@ jrd_prc* MET_lookup_procedure_id(thread_db* tdbb, USHORT id, } -jrd_rel* MET_lookup_relation(thread_db* tdbb, const MetaName& name) +jrd_rel* MET_lookup_relation(thread_db* tdbb, const QualifiedName& name) { /************************************** * @@ -3038,10 +3058,12 @@ jrd_rel* MET_lookup_relation(thread_db* tdbb, const MetaName& name) AutoCacheRequest request(tdbb, irq_l_relation, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - X IN RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ name.c_str() + X IN RDB$RELATIONS + WITH X.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + X.RDB$RELATION_NAME EQ name.object.c_str() { relation = MET_relation(tdbb, X.RDB$RELATION_ID); - if (relation->rel_name.length() == 0) { + if (relation->rel_name.object.isEmpty()) { relation->rel_name = name; } @@ -3125,12 +3147,12 @@ jrd_rel* MET_lookup_relation_id(thread_db* tdbb, SLONG id, bool return_deleted) AutoCacheRequest request(tdbb, irq_l_rel_id, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - X IN RDB$RELATIONS WITH X.RDB$RELATION_ID EQ id + X IN RDB$RELATIONS + WITH X.RDB$RELATION_ID EQ id { relation = MET_relation(tdbb, X.RDB$RELATION_ID); - if (relation->rel_name.length() == 0) { - relation->rel_name = X.RDB$RELATION_NAME; - } + if (relation->rel_name.object.isEmpty()) + relation->rel_name = QualifiedName(X.RDB$RELATION_NAME, X.RDB$SCHEMA_NAME); relation->rel_flags |= get_rel_flags_from_FLAGS(X.RDB$FLAGS); @@ -3163,6 +3185,7 @@ jrd_rel* MET_lookup_relation_id(thread_db* tdbb, SLONG id, bool return_deleted) DmlNode* MET_parse_blob(thread_db* tdbb, + const MetaName* schema, jrd_rel* relation, bid* blob_id, CompilerScratch** csb_ptr, @@ -3200,10 +3223,10 @@ DmlNode* MET_parse_blob(thread_db* tdbb, { // The set of MET parse functions needs a rework. // For now, our caller chain is not interested in the returned node. - PAR_validation_blr(tdbb, relation, temp, length, NULL, csb_ptr, 0); + PAR_validation_blr(tdbb, schema, relation, temp, length, NULL, csb_ptr, 0); } else - node = PAR_blr(tdbb, relation, temp, length, NULL, csb_ptr, statementPtr, trigger, 0); + node = PAR_blr(tdbb, schema, relation, temp, length, NULL, csb_ptr, statementPtr, trigger, 0); return node; } @@ -3228,7 +3251,7 @@ void MET_post_existence(thread_db* tdbb, jrd_rel* relation) if (!MET_lookup_relation_id(tdbb, relation->rel_id, false)) { relation->rel_use_count--; - ERR_post(Arg::Gds(isc_relnotdef) << Arg::Str(relation->rel_name)); + ERR_post(Arg::Gds(isc_relnotdef) << relation->rel_name.toQuotedString()); } } @@ -3346,11 +3369,15 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags) AutoCacheRequest request(tdbb, irq_r_procedure, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - P IN RDB$PROCEDURES WITH P.RDB$PROCEDURE_ID EQ procedure->getId() + P IN RDB$PROCEDURES + CROSS SCH IN RDB$SCHEMAS + WITH P.RDB$PROCEDURE_ID EQ procedure->getId() AND + SCH.RDB$SCHEMA_NAME EQ P.RDB$SCHEMA_NAME { - if (procedure->getName().toString().length() == 0) + if (procedure->getName().toQuotedString().length() == 0) { procedure->setName(QualifiedName(P.RDB$PROCEDURE_NAME, + (P.RDB$SCHEMA_NAME.NULL ? "" : P.RDB$SCHEMA_NAME), (P.RDB$PACKAGE_NAME.NULL ? "" : P.RDB$PACKAGE_NAME))); } @@ -3358,17 +3385,18 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags) TriState ssDefiner; if (!P.RDB$SECURITY_CLASS.NULL) - procedure->setSecurityName(P.RDB$SECURITY_CLASS); + procedure->setSecurityName(QualifiedName(P.RDB$SECURITY_CLASS, SCH.RDB$SECURITY_CLASS)); else if (!P.RDB$PACKAGE_NAME.NULL) { AutoCacheRequest requestHandle(tdbb, irq_l_procedure_pkg_class, IRQ_REQUESTS); FOR (REQUEST_HANDLE requestHandle) PKG IN RDB$PACKAGES - WITH PKG.RDB$PACKAGE_NAME EQ P.RDB$PACKAGE_NAME + WITH PKG.RDB$SCHEMA_NAME EQ SCH.RDB$SCHEMA_NAME AND + PKG.RDB$PACKAGE_NAME EQ P.RDB$PACKAGE_NAME { if (!PKG.RDB$SECURITY_CLASS.NULL) - procedure->setSecurityName(PKG.RDB$SECURITY_CLASS); + procedure->setSecurityName(QualifiedName(PKG.RDB$SECURITY_CLASS, SCH.RDB$SECURITY_CLASS)); if (!PKG.RDB$SQL_SECURITY.NULL) ssDefiner = (bool) PKG.RDB$SQL_SECURITY; @@ -3402,9 +3430,12 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags) FOR (REQUEST_HANDLE request2) PA IN RDB$PROCEDURE_PARAMETERS CROSS F IN RDB$FIELDS - WITH F.RDB$FIELD_NAME = PA.RDB$FIELD_SOURCE AND + WITH PA.RDB$SCHEMA_NAME EQUIV P.RDB$SCHEMA_NAME AND + PA.RDB$PACKAGE_NAME EQUIV NULLIF(packageName.c_str(), '') AND PA.RDB$PROCEDURE_NAME = P.RDB$PROCEDURE_NAME AND - PA.RDB$PACKAGE_NAME EQUIV NULLIF(packageName.c_str(), '') + F.RDB$SCHEMA_NAME EQUIV PA.RDB$FIELD_SOURCE_SCHEMA_NAME AND + F.RDB$FIELD_NAME = PA.RDB$FIELD_SOURCE + { const SSHORT pa_collation_id_null = PA.RDB$COLLATION_ID.NULL; const SSHORT pa_collation_id = PA.RDB$COLLATION_ID; @@ -3424,7 +3455,7 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags) prm_mech_normal : (prm_mech_t) PA.RDB$PARAMETER_MECHANISM; if (!PA.RDB$FIELD_SOURCE.NULL) - parameter->prm_field_source = PA.RDB$FIELD_SOURCE; + parameter->prm_field_source = QualifiedName(PA.RDB$FIELD_SOURCE, PA.RDB$FIELD_SOURCE_SCHEMA_NAME); DSC_make_descriptor(¶meter->prm_desc, F.RDB$FIELD_TYPE, F.RDB$FIELD_SCALE, F.RDB$FIELD_LENGTH, @@ -3438,7 +3469,7 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags) } if (!PA.RDB$RELATION_NAME.NULL) - parameter->prm_type_of_table = PA.RDB$RELATION_NAME; + parameter->prm_type_of_table = QualifiedName(PA.RDB$RELATION_NAME, PA.RDB$RELATION_SCHEMA_NAME); if (!PA.RDB$FIELD_NAME.NULL) parameter->prm_type_of_column = PA.RDB$FIELD_NAME; @@ -3454,7 +3485,8 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags) try { parameter->prm_default_value = static_cast( - MET_parse_blob(tdbb, NULL, &pa_default_value, NULL, NULL, false, false)); + MET_parse_blob(tdbb, &procedure->getName().schema, NULL, &pa_default_value, + NULL, NULL, false, false)); } catch (const Exception&) { @@ -3470,7 +3502,7 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags) const bool external = !P.RDB$ENGINE_NAME.NULL; // ODS_12_0 - Array >& paramArray = procedure->getOutputFields(); + auto& paramArray = procedure->getOutputFields(); if (paramArray.hasData() && paramArray[0]) { @@ -3533,7 +3565,7 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags) } else { - const string name = procedure->getName().toString(); + const string name = procedure->getName().toQuotedString(); try { @@ -3548,8 +3580,8 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags) { StaticStatusVector temp_status; ex.stuffException(temp_status); - (Arg::Gds(isc_bad_proc_BLR) << Arg::Str(name) - << Arg::StatusVector(temp_status.begin())).raise(); + (Arg::Gds(isc_bad_proc_BLR) << name << + Arg::StatusVector(temp_status.begin())).raise(); } } } @@ -3635,7 +3667,8 @@ bool jrd_prc::reload(thread_db* tdbb) AutoCacheRequest request(tdbb, irq_r_proc_blr, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - P IN RDB$PROCEDURES WITH P.RDB$PROCEDURE_ID EQ this->getId() + P IN RDB$PROCEDURES + WITH P.RDB$PROCEDURE_ID EQ this->getId() { MemoryPool* const csb_pool = attachment->createPool(); Jrd::ContextPoolHolder context(tdbb, csb_pool); @@ -3657,8 +3690,7 @@ bool jrd_prc::reload(thread_db* tdbb) StaticStatusVector temp_status; ex.stuffException(temp_status); - const string name = this->getName().toString(); - (Arg::Gds(isc_bad_proc_BLR) << Arg::Str(name) + (Arg::Gds(isc_bad_proc_BLR) << this->getName().toQuotedString() << Arg::StatusVector(temp_status.begin())).raise(); } } @@ -3768,8 +3800,8 @@ void MET_release_existence(thread_db* tdbb, jrd_rel* relation) } -void MET_revoke(thread_db* tdbb, jrd_tra* transaction, const MetaName& relation, - const MetaName& revokee, const string& privilege) +void MET_revoke(thread_db* tdbb, jrd_tra* transaction, const QualifiedName& relation, + const QualifiedName& revokee, const string& privilege) { /************************************** * @@ -3791,10 +3823,12 @@ void MET_revoke(thread_db* tdbb, jrd_tra* transaction, const MetaName& relation, AutoCacheRequest request(tdbb, irq_revoke1, IRQ_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - FIRST 1 P IN RDB$USER_PRIVILEGES WITH - P.RDB$RELATION_NAME EQ relation.c_str() AND - P.RDB$PRIVILEGE EQ privilege.c_str() AND - P.RDB$USER EQ revokee.c_str() + FIRST 1 P IN RDB$USER_PRIVILEGES + WITH P.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(relation.schema.c_str(), '') AND + P.RDB$RELATION_NAME EQ relation.object.c_str() AND + P.RDB$PRIVILEGE EQ privilege.c_str() AND + P.RDB$USER_SCHEMA_NAME EQUIV NULLIF(revokee.schema.c_str(), '') AND + P.RDB$USER EQ revokee.object.c_str() { ++count; } @@ -3808,10 +3842,11 @@ void MET_revoke(thread_db* tdbb, jrd_tra* transaction, const MetaName& relation, // User lost privilege. Take it away from anybody he/she gave it to. FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - P IN RDB$USER_PRIVILEGES WITH - P.RDB$RELATION_NAME EQ relation.c_str() AND - P.RDB$PRIVILEGE EQ privilege.c_str() AND - P.RDB$GRANTOR EQ revokee.c_str() + P IN RDB$USER_PRIVILEGES + WITH P.RDB$RELATION_SCHEMA_NAME EQUIV NULLIF(relation.schema.c_str(), '') AND + P.RDB$RELATION_NAME EQ relation.object.c_str() AND + P.RDB$PRIVILEGE EQ privilege.c_str() AND + P.RDB$GRANTOR EQ revokee.object.c_str() { ERASE P; } @@ -3886,16 +3921,19 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) CompilerScratch* csb = NULL; FOR(REQUEST_HANDLE request) - REL IN RDB$RELATIONS WITH REL.RDB$RELATION_ID EQ relation->rel_id + REL IN RDB$RELATIONS + CROSS SCH IN RDB$SCHEMAS + WITH REL.RDB$RELATION_ID EQ relation->rel_id AND + SCH.RDB$SCHEMA_NAME EQ REL.RDB$SCHEMA_NAME { // Pick up relation level stuff relation->rel_current_fmt = REL.RDB$FORMAT; vec* vector = relation->rel_fields = vec::newVector(*relation->rel_pool, relation->rel_fields, REL.RDB$FIELD_ID + 1); if (!REL.RDB$SECURITY_CLASS.NULL) - relation->rel_security_name = REL.RDB$SECURITY_CLASS; + relation->rel_security_name = QualifiedName(REL.RDB$SECURITY_CLASS, SCH.RDB$SECURITY_CLASS); - relation->rel_name = REL.RDB$RELATION_NAME; + relation->rel_name = QualifiedName(REL.RDB$RELATION_NAME, REL.RDB$SCHEMA_NAME); relation->rel_owner_name = REL.RDB$OWNER_NAME; if (!REL.RDB$SQL_SECURITY.NULL) @@ -3911,12 +3949,15 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) if (dependencies) { - const MetaName depName(REL.RDB$RELATION_NAME); + const QualifiedName depName(REL.RDB$RELATION_NAME, REL.RDB$SCHEMA_NAME); rseNode = MET_get_dependencies(tdbb, relation, NULL, 0, NULL, &REL.RDB$VIEW_BLR, NULL, &csb, depName, obj_view, 0, depTrans); } else - rseNode = MET_parse_blob(tdbb, relation, &REL.RDB$VIEW_BLR, &csb, NULL, false, false); + { + rseNode = MET_parse_blob(tdbb, &relation->rel_name.schema, relation, &REL.RDB$VIEW_BLR, &csb, + NULL, false, false); + } if (rseNode) { @@ -3999,10 +4040,8 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) switch ((rsr_t) buffer[0]) { case RSR_field_id: - if (field && field->fld_security_name.length() == 0 && !REL.RDB$DEFAULT_CLASS.NULL) - { + if (field && field->fld_security_name.isEmpty() && !REL.RDB$DEFAULT_CLASS.NULL) field->fld_security_name = REL.RDB$DEFAULT_CLASS; - } field_id = n; field = (*vector)[field_id]; @@ -4013,7 +4052,7 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) field->fld_default_value = NULL; field->fld_validation = NULL; field->fld_not_null = NULL; - field->fld_generator_name = NULL; + field->fld_generator_name.clear(); } array = NULL; @@ -4040,10 +4079,8 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) // CVC: Be paranoid and allow the possible trigger(s) to have a // not null security class to work on, even if we only take it // from the relation itself. - if (field->fld_security_name.length() == 0 && !REL.RDB$DEFAULT_CLASS.NULL) - { + if (field->fld_security_name.isEmpty() && !REL.RDB$DEFAULT_CLASS.NULL) field->fld_security_name = REL.RDB$DEFAULT_CLASS; - } break; @@ -4056,7 +4093,7 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) { csb->csb_g_flags |= csb_get_dependencies; field->fld_source = PAR_make_field(tdbb, csb, view_context, (TEXT*) p); - const MetaName depName(REL.RDB$RELATION_NAME); + const QualifiedName depName(REL.RDB$RELATION_NAME, REL.RDB$SCHEMA_NAME); MET_store_dependencies(tdbb, csb->csb_dependencies, 0, depName, obj_view, depTrans); } else @@ -4069,7 +4106,7 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) if (ctx.find(view_context, pos) && (ctx[pos]->vcx_type == VCT_TABLE || ctx[pos]->vcx_type == VCT_VIEW)) { - field->fld_source_rel_field = MetaNamePair(ctx[pos]->vcx_relation_name, (TEXT*) p); + field->fld_source_rel_field = QualifiedNameMetaNamePair(ctx[pos]->vcx_relation_name, (TEXT*) p); } } @@ -4081,8 +4118,10 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) DmlNode* nod = dependencies ? MET_get_dependencies(tdbb, relation, p, length, csb, NULL, NULL, NULL, - field->fld_name, obj_computed, csb_computed_field, depTrans) : - PAR_blr(tdbb, relation, p, length, csb, NULL, NULL, false, csb_computed_field); + QualifiedName(field->fld_name, relation->rel_name.schema), + obj_computed, csb_computed_field, depTrans) : + PAR_blr(tdbb, &relation->rel_name.schema, relation, p, length, csb, NULL, NULL, false, + csb_computed_field); field->fld_computation = static_cast(nod); } @@ -4090,12 +4129,12 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) case RSR_missing_value: field->fld_missing_value = static_cast( - PAR_blr(tdbb, relation, p, length, csb, NULL, NULL, false, 0)); + PAR_blr(tdbb, &relation->rel_name.schema, relation, p, length, csb, NULL, NULL, false, 0)); break; case RSR_default_value: field->fld_default_value = static_cast( - PAR_blr(tdbb, relation, p, length, csb, NULL, NULL, false, 0)); + PAR_blr(tdbb, &relation->rel_name.schema, relation, p, length, csb, NULL, NULL, false, 0)); break; case RSR_validation_blr: @@ -4107,14 +4146,14 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) // Because a VIEW can't have a validation section i ignored the whole call. if (!csb) { - field->fld_validation = PAR_validation_blr(tdbb, relation, p, length, csb, - NULL, csb_validation); + field->fld_validation = PAR_validation_blr(tdbb, &relation->rel_name.schema, relation, p, length, + csb, NULL, csb_validation); } break; case RSR_field_not_null: - field->fld_not_null = PAR_validation_blr(tdbb, relation, p, length, csb, - NULL, csb_validation); + field->fld_not_null = PAR_validation_blr(tdbb, &relation->rel_name.schema, relation, p, length, + csb, NULL, csb_validation); break; case RSR_security_class: @@ -4122,7 +4161,7 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) break; case RSR_trigger_name: - MET_load_trigger(tdbb, relation, (const TEXT*) p, triggers); + MET_load_trigger(tdbb, relation, QualifiedName((const TEXT*) p, REL.RDB$SCHEMA_NAME), triggers); break; case RSR_dimensions: @@ -4136,7 +4175,7 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) break; case RSR_field_generator_name: - field->fld_generator_name = (const TEXT*) p; + field->fld_generator_name = QualifiedName((const TEXT*) p, REL.RDB$SCHEMA_NAME); if (!field->fld_identity_type.has_value()) field->fld_identity_type = IDENT_TYPE_BY_DEFAULT; break; @@ -4152,10 +4191,8 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) blob->BLB_close(tdbb); blob = 0; - if (field && field->fld_security_name.length() == 0 && !REL.RDB$DEFAULT_CLASS.NULL) - { + if (field && field->fld_security_name.isEmpty() && !REL.RDB$DEFAULT_CLASS.NULL) field->fld_security_name = REL.RDB$DEFAULT_CLASS; - } } END_FOR @@ -4185,8 +4222,7 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) } -void MET_trigger_msg(thread_db* tdbb, string& msg, const MetaName& name, - USHORT number) +void MET_trigger_msg(thread_db* tdbb, string& msg, const QualifiedName& name, USHORT number) { /************************************** * @@ -4204,9 +4240,10 @@ void MET_trigger_msg(thread_db* tdbb, string& msg, const MetaName& name, AutoCacheRequest request(tdbb, irq_s_msgs, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - MSG IN RDB$TRIGGER_MESSAGES WITH - MSG.RDB$TRIGGER_NAME EQ name.c_str() AND - MSG.RDB$MESSAGE_NUMBER EQ number + MSG IN RDB$TRIGGER_MESSAGES + WITH MSG.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + MSG.RDB$TRIGGER_NAME EQ name.object.c_str() AND + MSG.RDB$MESSAGE_NUMBER EQ number { msg = MSG.RDB$MESSAGE; } @@ -4302,7 +4339,7 @@ static int blocking_ast_dsql_cache(void* ast_object) AsyncContextHolder tdbb(dbb, FB_FUNCTION, item->lock); - GenericMap > >::Accessor accessor(&item->obsoleteMap); + LeftPooledMap::Accessor accessor(&item->obsoleteMap); for (bool found = accessor.getFirst(); found; found = accessor.getNext()) accessor.current()->second = true; @@ -4327,14 +4364,18 @@ static DSqlCacheItem* get_dsql_cache_item(thread_db* tdbb, sym_type type, const string key("0"); // name (not hash) key.append((char*) &ucharType, 1); - USHORT len = (USHORT) name.identifier.length(); + USHORT len = (USHORT) name.object.length(); key.append((char*) &len, sizeof(len)); - key.append(name.identifier.c_str(), len); + key.append(name.object.c_str(), len); len = (USHORT) name.package.length(); key.append((char*) &len, sizeof(len)); key.append(name.package.c_str(), len); + len = (USHORT) name.schema.length(); + key.append((char*) &len, sizeof(len)); + key.append(name.schema.c_str(), len); + if (key.length() > MAX_UCHAR) { FB_SIZE_T hash = DefaultHash::hash(key.c_str(), key.length(), sizeof(FB_SIZE_T)); @@ -4545,7 +4586,7 @@ ULONG MET_get_rel_flags_from_TYPE(USHORT type) static void get_trigger(thread_db* tdbb, jrd_rel* relation, bid* blob_id, bid* debug_blob_id, TrigVector** ptr, - const TEXT* name, FB_UINT64 type, + const QualifiedName& name, FB_UINT64 type, bool sys_trigger, USHORT flags, const MetaName& engine, const string& entryPoint, const bid* body, TriState ssDefiner) @@ -4576,11 +4617,11 @@ static void get_trigger(thread_db* tdbb, jrd_rel* relation, debugInfoBlob = blb::open(tdbb, attachment->getSysTransaction(), debug_blob_id); save_trigger_data(tdbb, ptr, relation, NULL, blrBlob, debugInfoBlob, - name, type, sys_trigger, flags, engine, entryPoint, body, ssDefiner); + &name, type, sys_trigger, flags, engine, entryPoint, body, ssDefiner); } -static bool get_type(thread_db* tdbb, USHORT* id, const UCHAR* name, const TEXT* field) +static bool get_type(thread_db* tdbb, USHORT* id, const MetaName& name, const TEXT* field) { /************************************** * @@ -4596,24 +4637,11 @@ static bool get_type(thread_db* tdbb, USHORT* id, const UCHAR* name, const TEXT* * Return (1) if found, (0) otherwise. * **************************************/ - UCHAR buffer[MAX_SQL_IDENTIFIER_SIZE]; // BASED ON RDB$TYPE_NAME - SET_TDBB(tdbb); Attachment* attachment = tdbb->getAttachment(); - fb_assert(id != NULL); - fb_assert(name != NULL); - fb_assert(field != NULL); - - // Force key to uppercase, following C locale rules for uppercase - UCHAR* p; - for (p = buffer; *name && p < buffer + sizeof(buffer) - 1; p++, name++) - { - *p = UPPER7(*name); - } - *p = 0; - - // Try for exact name match + fb_assert(id); + fb_assert(field); bool found = false; @@ -4622,7 +4650,7 @@ static bool get_type(thread_db* tdbb, USHORT* id, const UCHAR* name, const TEXT* FOR(REQUEST_HANDLE handle) FIRST 1 T IN RDB$TYPES WITH T.RDB$FIELD_NAME EQ field AND - T.RDB$TYPE_NAME EQ buffer + T.RDB$TYPE_NAME EQ name.c_str() { found = true; *id = T.RDB$TYPE; @@ -4652,16 +4680,19 @@ static void lookup_view_contexts( thread_db* tdbb, jrd_rel* view) AutoCacheRequest request(tdbb, irq_view_context, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) - V IN RDB$VIEW_RELATIONS WITH - V.RDB$VIEW_NAME EQ view->rel_name.c_str() - SORTED BY V.RDB$VIEW_CONTEXT + V IN RDB$VIEW_RELATIONS + WITH V.RDB$SCHEMA_NAME EQ view->rel_name.schema.c_str() AND + V.RDB$VIEW_NAME EQ view->rel_name.object.c_str() + SORTED BY V.RDB$VIEW_CONTEXT { // trim trailing spaces fb_utils::exact_name_limit(V.RDB$CONTEXT_NAME, sizeof(V.RDB$CONTEXT_NAME)); ViewContext* view_context = FB_NEW_POOL(*view->rel_pool) ViewContext(*view->rel_pool, - V.RDB$CONTEXT_NAME, V.RDB$RELATION_NAME, V.RDB$VIEW_CONTEXT, + V.RDB$CONTEXT_NAME, + QualifiedName(V.RDB$RELATION_NAME, V.RDB$RELATION_SCHEMA_NAME), + V.RDB$VIEW_CONTEXT, (V.RDB$CONTEXT_TYPE.NULL ? VCT_TABLE : ViewContextType(V.RDB$CONTEXT_TYPE))); view->rel_view_contexts.add(view_context); @@ -4670,7 +4701,7 @@ static void lookup_view_contexts( thread_db* tdbb, jrd_rel* view) } -static void make_relation_scope_name(const TEXT* rel_name, const USHORT rel_flags, +static void make_relation_scope_name(const QualifiedName& rel_name, const USHORT rel_flags, string& str) { /************************************** @@ -4692,12 +4723,12 @@ static void make_relation_scope_name(const TEXT* rel_name, const USHORT rel_flag else scope = REL_SCOPE_PERSISTENT; - str.printf(scope, rel_name); + str.printf(scope, rel_name.toQuotedString().c_str()); } // Parses default BLR for a field. -static ValueExprNode* parse_field_default_blr(thread_db* tdbb, bid* blob_id) +static ValueExprNode* parse_field_default_blr(thread_db* tdbb, const MetaName& schema, bid* blob_id) { SET_TDBB(tdbb); Attachment* attachment = tdbb->getAttachment(); @@ -4712,13 +4743,13 @@ static ValueExprNode* parse_field_default_blr(thread_db* tdbb, bid* blob_id) length = blob->BLB_get_data(tdbb, temp.getBuffer(length), length); - DmlNode* const node = PAR_blr(tdbb, NULL, temp.begin(), length, NULL, &csb, NULL, false, 0); + DmlNode* const node = PAR_blr(tdbb, &schema, NULL, temp.begin(), length, NULL, &csb, NULL, false, 0); return static_cast(node); } // Parses validation BLR for a field. -static BoolExprNode* parse_field_validation_blr(thread_db* tdbb, bid* blob_id, const MetaName name) +static BoolExprNode* parse_field_validation_blr(thread_db* tdbb, bid* blob_id, const QualifiedName& name) { SET_TDBB(tdbb); Attachment* attachment = tdbb->getAttachment(); @@ -4735,11 +4766,11 @@ static BoolExprNode* parse_field_validation_blr(thread_db* tdbb, bid* blob_id, c length = blob->BLB_get_data(tdbb, temp.getBuffer(length), length); - return PAR_validation_blr(tdbb, NULL, temp.begin(), length, NULL, &csb, 0); + return PAR_validation_blr(tdbb, &name.schema, NULL, temp.begin(), length, NULL, &csb, 0); } -void MET_release_trigger(thread_db* tdbb, TrigVector** vector_ptr, const MetaName& name) +void MET_release_trigger(thread_db* tdbb, TrigVector** vector_ptr, const QualifiedName& name) { /*********************************************** * @@ -4814,8 +4845,8 @@ void MET_release_triggers(thread_db* tdbb, TrigVector** vector_ptr, bool destroy static bool resolve_charset_and_collation(thread_db* tdbb, USHORT* id, - const UCHAR* charset, - const UCHAR* collation) + const QualifiedName& charset, + const QualifiedName& collation) { /************************************** * @@ -4855,23 +4886,26 @@ static bool resolve_charset_and_collation(thread_db* tdbb, SET_TDBB(tdbb); Attachment* attachment = tdbb->getAttachment(); + auto charSetName = charset; + auto collationName = collation; - fb_assert(id != NULL); + fb_assert(id); AutoRequest handle; - if (!collation) + if (collationName.object.isEmpty()) { - if (charset == NULL) - charset = (const UCHAR*) DEFAULT_CHARACTER_SET_NAME; + if (charSetName.object.isEmpty()) + charSetName = QualifiedName(DEFAULT_CHARACTER_SET_NAME, SYSTEM_SCHEMA); - if (attachment->att_charset_ids.get((const TEXT*) charset, *id)) + if (attachment->att_charset_ids.get(charSetName, *id)) return true; USHORT charset_id = 0; - if (get_type(tdbb, &charset_id, charset, "RDB$CHARACTER_SET_NAME")) + if (charSetName.schema == SYSTEM_SCHEMA && + get_type(tdbb, &charset_id, charSetName.object, "RDB$CHARACTER_SET_NAME")) { - attachment->att_charset_ids.put((const TEXT*) charset, charset_id); + attachment->att_charset_ids.put(charSetName, charset_id); *id = charset_id; return true; } @@ -4881,10 +4915,11 @@ static bool resolve_charset_and_collation(thread_db* tdbb, FOR(REQUEST_HANDLE handle) FIRST 1 CS IN RDB$CHARACTER_SETS - WITH CS.RDB$CHARACTER_SET_NAME EQ charset + WITH CS.RDB$SCHEMA_NAME EQ charSetName.schema.c_str() AND + CS.RDB$CHARACTER_SET_NAME EQ charSetName.object.c_str() { - found = true; - attachment->att_charset_ids.put((const TEXT*) charset, CS.RDB$CHARACTER_SET_ID); + found = true; + attachment->att_charset_ids.put(charSetName, CS.RDB$CHARACTER_SET_ID); *id = CS.RDB$CHARACTER_SET_ID; } END_FOR @@ -4892,11 +4927,12 @@ static bool resolve_charset_and_collation(thread_db* tdbb, return found; } - if (!charset) + if (charSetName.object.isEmpty()) { FOR(REQUEST_HANDLE handle) FIRST 1 COL IN RDB$COLLATIONS - WITH COL.RDB$COLLATION_NAME EQ collation + WITH COL.RDB$SCHEMA_NAME EQ collationName.schema.c_str() AND + COL.RDB$COLLATION_NAME EQ collationName.object.c_str() { found = true; *id = COL.RDB$CHARACTER_SET_ID | (COL.RDB$COLLATION_ID << 8); @@ -4906,20 +4942,24 @@ static bool resolve_charset_and_collation(thread_db* tdbb, return found; } - FOR(REQUEST_HANDLE handle) - FIRST 1 CS IN RDB$CHARACTER_SETS CROSS - COL IN RDB$COLLATIONS OVER RDB$CHARACTER_SET_ID CROSS - AL1 IN RDB$TYPES - WITH AL1.RDB$FIELD_NAME EQ "RDB$CHARACTER_SET_NAME" - AND AL1.RDB$TYPE_NAME EQ charset - AND COL.RDB$COLLATION_NAME EQ collation - AND AL1.RDB$TYPE EQ CS.RDB$CHARACTER_SET_ID + if (charSetName.schema == SYSTEM_SCHEMA && collationName.schema == SYSTEM_SCHEMA) { - found = true; - attachment->att_charset_ids.put((const TEXT*) charset, CS.RDB$CHARACTER_SET_ID); - *id = CS.RDB$CHARACTER_SET_ID | (COL.RDB$COLLATION_ID << 8); + FOR(REQUEST_HANDLE handle) + FIRST 1 + CS IN RDB$CHARACTER_SETS + CROSS COL IN RDB$COLLATIONS OVER RDB$CHARACTER_SET_ID + CROSS T IN RDB$TYPES + WITH COL.RDB$COLLATION_NAME EQ collationName.object.c_str() AND + T.RDB$TYPE_NAME EQ charSetName.object.c_str() AND + T.RDB$FIELD_NAME EQ "RDB$CHARACTER_SET_NAME" AND + T.RDB$TYPE EQ CS.RDB$CHARACTER_SET_ID + { + found = true; + attachment->att_charset_ids.put(charSetName, CS.RDB$CHARACTER_SET_ID); + *id = CS.RDB$CHARACTER_SET_ID | (COL.RDB$COLLATION_ID << 8); + } + END_FOR } - END_FOR return found; } @@ -4927,7 +4967,7 @@ static bool resolve_charset_and_collation(thread_db* tdbb, static void save_trigger_data(thread_db* tdbb, TrigVector** ptr, jrd_rel* relation, Statement* statement, blb* blrBlob, blb* debugInfoBlob, - const TEXT* name, FB_UINT64 type, + const QualifiedName* name, FB_UINT64 type, bool sys_trigger, USHORT flags, const MetaName& engine, const string& entryPoint, const bid* body, TriState ssDefiner) @@ -4970,7 +5010,7 @@ static void save_trigger_data(thread_db* tdbb, TrigVector** ptr, jrd_rel* relati } if (name) - t.name = name; + t.name = *name; if (body) { @@ -4995,13 +5035,13 @@ static void save_trigger_data(thread_db* tdbb, TrigVector** ptr, jrd_rel* relati } -const Trigger* findTrigger(TrigVector* triggers, const MetaName& trig_name) +const Trigger* findTrigger(TrigVector* triggers, const QualifiedName& trig_name) { if (triggers) { for (TrigVector::iterator t = triggers->begin(); t != triggers->end(); ++t) { - if (t->name.compare(trig_name) == 0) + if (t->name == trig_name) return &(*t); } } @@ -5056,18 +5096,22 @@ void scan_partners(thread_db* tdbb, jrd_rel* relation) FOR(REQUEST_HANDLE request) IDX IN RDB$INDICES CROSS RC IN RDB$RELATION_CONSTRAINTS - OVER RDB$INDEX_NAME CROSS + OVER RDB$SCHEMA_NAME, RDB$INDEX_NAME CROSS IND IN RDB$INDICES WITH RC.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY AND - IDX.RDB$RELATION_NAME EQ relation->rel_name.c_str() AND + IDX.RDB$SCHEMA_NAME EQ relation->rel_name.schema.c_str() AND + IDX.RDB$RELATION_NAME EQ relation->rel_name.object.c_str() AND + IND.RDB$SCHEMA_NAME EQ IDX.RDB$FOREIGN_KEY_SCHEMA_NAME AND IND.RDB$INDEX_NAME EQ IDX.RDB$FOREIGN_KEY AND IDX.RDB$INDEX_ID > 0 AND IND.RDB$INDEX_ID > 0 AND IND.RDB$UNIQUE_FLAG = 1 { + const QualifiedName partnerRelationName(IND.RDB$RELATION_NAME, IND.RDB$SCHEMA_NAME); + //// ASF: Hack fix for CORE-4304, until nasty interactions between dfw and met are not resolved. - const jrd_rel* partner_relation = relation->rel_name == IND.RDB$RELATION_NAME ? - relation : MET_lookup_relation(tdbb, IND.RDB$RELATION_NAME); + const jrd_rel* partner_relation = relation->rel_name == partnerRelationName ? + relation : MET_lookup_relation(tdbb, partnerRelationName); if (partner_relation && !IDX.RDB$INDEX_INACTIVE && !IND.RDB$INDEX_INACTIVE) { @@ -5123,12 +5167,16 @@ void scan_partners(thread_db* tdbb, jrd_rel* relation) IDX.RDB$UNIQUE_FLAG = 1 AND IDX.RDB$INDEX_ID > 0 AND IND.RDB$INDEX_ID > 0 AND - IDX.RDB$RELATION_NAME EQ relation->rel_name.c_str() AND + IDX.RDB$SCHEMA_NAME EQ relation->rel_name.schema.c_str() AND + IDX.RDB$RELATION_NAME EQ relation->rel_name.object.c_str() AND + IND.RDB$FOREIGN_KEY_SCHEMA_NAME EQ IDX.RDB$SCHEMA_NAME AND IND.RDB$FOREIGN_KEY EQ IDX.RDB$INDEX_NAME { + const QualifiedName partnerRelationName(IND.RDB$RELATION_NAME, IND.RDB$SCHEMA_NAME); + //// ASF: Hack fix for CORE-4304, until nasty interactions between dfw and met are not resolved. - const jrd_rel* partner_relation = relation->rel_name == IND.RDB$RELATION_NAME ? - relation : MET_lookup_relation(tdbb, IND.RDB$RELATION_NAME); + const jrd_rel* partner_relation = relation->rel_name == partnerRelationName ? + relation : MET_lookup_relation(tdbb, partnerRelationName); if (partner_relation && !IDX.RDB$INDEX_INACTIVE && !IND.RDB$INDEX_INACTIVE) { @@ -5161,7 +5209,7 @@ void scan_partners(thread_db* tdbb, jrd_rel* relation) void MET_store_dependencies(thread_db* tdbb, Array& dependencies, const jrd_rel* dep_rel, - const MetaName& object_name, + const QualifiedName& object_name, int dependency_type, jrd_tra* transaction) { @@ -5177,7 +5225,7 @@ void MET_store_dependencies(thread_db* tdbb, * compilation of blr for a trigger, view, etc. * **************************************/ - MetaName name; + QualifiedName name; SET_TDBB(tdbb); @@ -5207,8 +5255,7 @@ void MET_store_dependencies(thread_db* tdbb, int dpdo_type = dependency.objType; jrd_rel* relation = NULL; const jrd_prc* procedure = NULL; - const MetaName* dpdo_name = NULL; - MetaName packageName; + const QualifiedName* dpdo_name = NULL; SubtypeInfo info; switch (dpdo_type) @@ -5231,10 +5278,8 @@ void MET_store_dependencies(thread_db* tdbb, { string sMaster, sChild; - make_relation_scope_name(relation->rel_name.c_str(), - relation->rel_flags, sMaster); - make_relation_scope_name(dep_rel->rel_name.c_str(), - dep_rel->rel_flags, sChild); + make_relation_scope_name(relation->rel_name, relation->rel_flags, sMaster); + make_relation_scope_name(dep_rel->rel_name, dep_rel->rel_flags, sChild); ERR_post(Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_met_wrong_gtt_scope) << Arg::Str(sChild) << @@ -5249,8 +5294,7 @@ void MET_store_dependencies(thread_db* tdbb, break; case obj_procedure: procedure = dependency.procedure; - dpdo_name = &procedure->getName().identifier; - packageName = procedure->getName().package; + dpdo_name = &procedure->getName(); break; case obj_collation: { @@ -5281,11 +5325,7 @@ void MET_store_dependencies(thread_db* tdbb, } break; case obj_udf: - { - const Function* const udf = dependency.function; - dpdo_name = &udf->getName().identifier; - packageName = udf->getName().package; - } + dpdo_name = &dependency.function->getName(); break; case obj_index: name = *dependency.name; @@ -5326,12 +5366,15 @@ void MET_store_dependencies(thread_db* tdbb, bool found = false; fb_assert(dpdo_name); - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$DEPENDENCIES WITH - X.RDB$DEPENDENT_NAME = object_name.c_str() AND - X.RDB$DEPENDED_ON_NAME = dpdo_name->c_str() AND - X.RDB$DEPENDED_ON_TYPE = dpdo_type AND - X.RDB$FIELD_NAME = field_name.c_str() AND - X.RDB$DEPENDENT_TYPE = dependency_type + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + X IN RDB$DEPENDENCIES + WITH X.RDB$DEPENDENT_SCHEMA_NAME = NULLIF(object_name.schema.c_str(), '') AND + X.RDB$DEPENDENT_NAME = object_name.object.c_str() AND + X.RDB$DEPENDED_ON_SCHEMA_NAME = NULLIF(dpdo_name->schema.c_str(), '') AND + X.RDB$DEPENDED_ON_NAME = dpdo_name->object.c_str() AND + X.RDB$DEPENDED_ON_TYPE = dpdo_type AND + X.RDB$FIELD_NAME = field_name.c_str() AND + X.RDB$DEPENDENT_TYPE = dependency_type { found = true; } @@ -5345,13 +5388,16 @@ void MET_store_dependencies(thread_db* tdbb, AutoCacheRequest request(tdbb, irq_c_deps, IRQ_REQUESTS); bool found = false; - FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) X IN RDB$DEPENDENCIES WITH - X.RDB$DEPENDENT_NAME = object_name.c_str() AND - X.RDB$DEPENDED_ON_NAME = dpdo_name->c_str() AND - X.RDB$DEPENDED_ON_TYPE = dpdo_type AND - X.RDB$FIELD_NAME MISSING AND - X.RDB$DEPENDENT_TYPE = dependency_type AND - X.RDB$PACKAGE_NAME EQUIV NULLIF(packageName.c_str(), '') + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + X IN RDB$DEPENDENCIES + WITH X.RDB$DEPENDENT_SCHEMA_NAME = NULLIF(object_name.schema.c_str(), '') AND + X.RDB$DEPENDENT_NAME = object_name.object.c_str() AND + X.RDB$DEPENDED_ON_SCHEMA_NAME = NULLIF(dpdo_name->schema.c_str(), '') AND + X.RDB$DEPENDED_ON_NAME = dpdo_name->object.c_str() AND + X.RDB$DEPENDED_ON_TYPE = dpdo_type AND + X.RDB$FIELD_NAME MISSING AND + X.RDB$DEPENDENT_TYPE = dependency_type AND + X.RDB$PACKAGE_NAME EQUIV NULLIF(dpdo_name->package.c_str(), '') { found = true; } @@ -5367,9 +5413,27 @@ void MET_store_dependencies(thread_db* tdbb, STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) DEP IN RDB$DEPENDENCIES { - strcpy(DEP.RDB$DEPENDENT_NAME, object_name.c_str()); + if (object_name.schema.hasData()) + { + DEP.RDB$DEPENDENT_SCHEMA_NAME.NULL = FALSE; + strcpy(DEP.RDB$DEPENDENT_SCHEMA_NAME, object_name.schema.c_str()); + } + else + DEP.RDB$DEPENDENT_SCHEMA_NAME.NULL = TRUE; + + strcpy(DEP.RDB$DEPENDENT_NAME, object_name.object.c_str()); + DEP.RDB$DEPENDED_ON_TYPE = dpdo_type; - strcpy(DEP.RDB$DEPENDED_ON_NAME, dpdo_name->c_str()); + + if (dpdo_name->schema.hasData()) + { + DEP.RDB$DEPENDED_ON_SCHEMA_NAME.NULL = FALSE; + strcpy(DEP.RDB$DEPENDED_ON_SCHEMA_NAME, dpdo_name->schema.c_str()); + } + else + DEP.RDB$DEPENDED_ON_SCHEMA_NAME.NULL = TRUE; + + strcpy(DEP.RDB$DEPENDED_ON_NAME, dpdo_name->object.c_str()); if (field_name.hasData()) { @@ -5379,10 +5443,10 @@ void MET_store_dependencies(thread_db* tdbb, else DEP.RDB$FIELD_NAME.NULL = TRUE; - if (packageName.hasData()) + if (dpdo_name->package.hasData()) { DEP.RDB$PACKAGE_NAME.NULL = FALSE; - strcpy(DEP.RDB$PACKAGE_NAME, packageName.c_str()); + strcpy(DEP.RDB$PACKAGE_NAME, dpdo_name->package.c_str()); } else DEP.RDB$PACKAGE_NAME.NULL = TRUE; @@ -5394,7 +5458,7 @@ void MET_store_dependencies(thread_db* tdbb, } -static bool verify_TRG_ignore_perm(thread_db* tdbb, const MetaName& trig_name) +static bool verify_TRG_ignore_perm(thread_db* tdbb, const QualifiedName& trig_name) { /***************************************************** * @@ -5421,7 +5485,9 @@ static bool verify_TRG_ignore_perm(thread_db* tdbb, const MetaName& trig_name) FOR(REQUEST_HANDLE request) CHK IN RDB$CHECK_CONSTRAINTS CROSS REF IN RDB$REF_CONSTRAINTS WITH - CHK.RDB$TRIGGER_NAME EQ trig_name.c_str() AND + CHK.RDB$SCHEMA_NAME EQ trig_name.schema.c_str() AND + CHK.RDB$TRIGGER_NAME EQ trig_name.object.c_str() AND + REF.RDB$SCHEMA_NAME = CHK.RDB$SCHEMA_NAME AND REF.RDB$CONSTRAINT_NAME = CHK.RDB$CONSTRAINT_NAME { fb_utils::exact_name_limit(REF.RDB$UPDATE_RULE, sizeof(REF.RDB$UPDATE_RULE)); @@ -5501,3 +5567,282 @@ TriState MET_get_ss_definer(Jrd::thread_db* tdbb) return r; } + +bool MET_qualify_existing_name(thread_db* tdbb, QualifiedName& name, ObjectType objType, + ObjectsArray* schemaSearchPath) +{ + fb_assert(name.object.hasData() && name.schema.isEmpty()); + + const auto attachment = tdbb->getAttachment(); + AutoCacheRequest handle; + + if (!schemaSearchPath) + schemaSearchPath = attachment->att_schema_search_path; + + for (const auto& searchSchema : *schemaSearchPath) + { + bool found = false; + + switch (objType) + { + case obj_charset: + { + if (searchSchema == SYSTEM_SCHEMA) + { + USHORT charSetId = 0; + if (get_type(tdbb, &charSetId, name.object, "RDB$CHARACTER_SET_NAME")) + { + found = true; + break; + } + } + + static const CachedRequestId charSetHandleId; + handle.reset(tdbb, charSetHandleId); + + FOR (REQUEST_HANDLE handle) + CS IN RDB$CHARACTER_SETS + WITH CS.RDB$SCHEMA_NAME EQ searchSchema.c_str() AND + CS.RDB$CHARACTER_SET_NAME EQ name.object.c_str() + { + found = true; + break; + } + END_FOR + + break; + } + + case obj_collation: + { + static const CachedRequestId collationHandleId; + handle.reset(tdbb, collationHandleId); + + FOR (REQUEST_HANDLE handle) + COLL IN RDB$COLLATIONS + WITH COLL.RDB$SCHEMA_NAME EQ searchSchema.c_str() AND + COLL.RDB$COLLATION_NAME EQ name.object.c_str() + { + found = true; + break; + } + END_FOR + + break; + } + + case obj_exception: + { + static const CachedRequestId exceptionHandleId; + handle.reset(tdbb, exceptionHandleId); + + FOR (REQUEST_HANDLE handle) + XCP IN RDB$EXCEPTIONS + WITH XCP.RDB$SCHEMA_NAME EQ searchSchema.c_str() AND + XCP.RDB$EXCEPTION_NAME EQ name.object.c_str() + { + found = true; + break; + } + END_FOR + + break; + } + + case obj_field: + { + static const CachedRequestId fieldHandleId; + handle.reset(tdbb, fieldHandleId); + + FOR (REQUEST_HANDLE handle) + FLD IN RDB$FIELDS + WITH FLD.RDB$SCHEMA_NAME EQ searchSchema.c_str() AND + FLD.RDB$FIELD_NAME EQ name.object.c_str() + { + found = true; + break; + } + END_FOR + + break; + } + + case obj_generator: + { + static const CachedRequestId generatorHandleId; + handle.reset(tdbb, generatorHandleId); + + FOR (REQUEST_HANDLE handle) + GEN IN RDB$GENERATORS + WITH GEN.RDB$SCHEMA_NAME EQ searchSchema.c_str() AND + GEN.RDB$GENERATOR_NAME EQ name.object.c_str() + { + found = true; + break; + } + END_FOR + + break; + } + + case obj_index: + { + static const CachedRequestId indexHandleId; + handle.reset(tdbb, indexHandleId); + + FOR (REQUEST_HANDLE handle) + IDX IN RDB$INDICES + WITH IDX.RDB$SCHEMA_NAME EQ searchSchema.c_str() AND + IDX.RDB$INDEX_NAME EQ name.object.c_str() + { + found = true; + break; + } + END_FOR + + break; + } + + case obj_package_header: + { + static const CachedRequestId packageHandleId; + handle.reset(tdbb, packageHandleId); + + FOR (REQUEST_HANDLE handle) + PKG IN RDB$PACKAGES + WITH PKG.RDB$SCHEMA_NAME EQ searchSchema.c_str() AND + PKG.RDB$PACKAGE_NAME EQ name.object.c_str() + { + found = true; + break; + } + END_FOR + + break; + } + + case obj_procedure: + case obj_relation: + case obj_view: + { + static const CachedRequestId procedureHandleId; + handle.reset(tdbb, procedureHandleId); + + FOR (REQUEST_HANDLE handle) + PRC IN RDB$PROCEDURES + WITH PRC.RDB$SCHEMA_NAME EQ searchSchema.c_str() AND + PRC.RDB$PROCEDURE_NAME EQ name.object.c_str() AND + PRC.RDB$PACKAGE_NAME MISSING + { + found = true; + break; + } + END_FOR + + static const CachedRequestId relationHandleId; + handle.reset(tdbb, relationHandleId); + + FOR (REQUEST_HANDLE handle) + REL IN RDB$RELATIONS + WITH REL.RDB$SCHEMA_NAME EQ searchSchema.c_str() AND + REL.RDB$RELATION_NAME EQ name.object.c_str() + { + found = true; + break; + } + END_FOR + + break; + } + + case obj_trigger: + { + static const CachedRequestId triggerHandleId; + handle.reset(tdbb, triggerHandleId); + + FOR (REQUEST_HANDLE handle) + TRG IN RDB$TRIGGERS + WITH TRG.RDB$SCHEMA_NAME EQ searchSchema.c_str() AND + TRG.RDB$TRIGGER_NAME EQ name.object.c_str() + { + found = true; + break; + } + END_FOR + + break; + } + + case obj_udf: + { + static const CachedRequestId udfHandleId; + handle.reset(tdbb, udfHandleId); + + FOR (REQUEST_HANDLE handle) + FUN IN RDB$FUNCTIONS + WITH FUN.RDB$SCHEMA_NAME EQ searchSchema.c_str() AND + FUN.RDB$FUNCTION_NAME EQ name.object.c_str() AND + FUN.RDB$PACKAGE_NAME MISSING + { + found = true; + break; + } + END_FOR + + break; + } + + default: + fb_assert(false); + } + + if (found) + { + name.schema = searchSchema; + return true; + } + } + + return false; +} + +bool MET_check_package_exists(thread_db* tdbb, const QualifiedName& name) +{ + fb_assert(name.package.isEmpty()); + + const auto attachment = tdbb->getAttachment(); + + static const CachedRequestId cachedHandleId; + AutoCacheRequest handle(tdbb, cachedHandleId); + + FOR (REQUEST_HANDLE handle) + PKG IN RDB$PACKAGES + WITH PKG.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + PKG.RDB$PACKAGE_NAME EQ name.object.c_str() + { + return true; + } + END_FOR + + return false; +} + +bool MET_check_schema_exists(thread_db* tdbb, const MetaName& name) +{ + const auto attachment = tdbb->getAttachment(); + + // FIXME: cache in memory + + static const CachedRequestId cachedHandleId; + AutoCacheRequest handle(tdbb, cachedHandleId); + + FOR (REQUEST_HANDLE handle) + PKG IN RDB$SCHEMAS + WITH PKG.RDB$SCHEMA_NAME EQ name.c_str() + { + return true; + } + END_FOR + + return false; +} diff --git a/src/jrd/met_proto.h b/src/jrd/met_proto.h index 1182c81449..86a40f8fb5 100644 --- a/src/jrd/met_proto.h +++ b/src/jrd/met_proto.h @@ -25,6 +25,8 @@ #define JRD_MET_PROTO_H #include "../jrd/MetaName.h" +#include "../jrd/QualifiedName.h" +#include "../jrd/obj.h" struct dsc; @@ -65,9 +67,9 @@ struct SubtypeInfo { } - Jrd::MetaName charsetName; - Jrd::MetaName collationName; - Jrd::MetaName baseCollationName; + Jrd::QualifiedName charsetName; + Jrd::QualifiedName collationName; + Firebird::string baseCollationName; USHORT attributes; bool ignoreAttributes; Firebird::UCharBuffer specificAttributes; @@ -75,78 +77,82 @@ struct SubtypeInfo void MET_activate_shadow(Jrd::thread_db*); ULONG MET_align(const dsc*, ULONG); -Jrd::DeferredWork* MET_change_fields(Jrd::thread_db*, Jrd::jrd_tra*, const dsc*); +Jrd::DeferredWork* MET_change_fields(Jrd::thread_db*, Jrd::jrd_tra*, const dsc*, const dsc*); Jrd::Format* MET_current(Jrd::thread_db*, Jrd::jrd_rel*); -void MET_delete_dependencies(Jrd::thread_db*, const Jrd::MetaName&, int, Jrd::jrd_tra*); +void MET_delete_dependencies(Jrd::thread_db*, const Jrd::QualifiedName&, int, Jrd::jrd_tra*); void MET_delete_shadow(Jrd::thread_db*, USHORT); -bool MET_dsql_cache_use(Jrd::thread_db* tdbb, Jrd::sym_type type, const Jrd::MetaName& name, const Jrd::MetaName& package = ""); -void MET_dsql_cache_release(Jrd::thread_db* tdbb, Jrd::sym_type type, const Jrd::MetaName& name, const Jrd::MetaName& package = ""); +bool MET_dsql_cache_use(Jrd::thread_db* tdbb, Jrd::sym_type type, const Jrd::QualifiedName& name); +void MET_dsql_cache_release(Jrd::thread_db* tdbb, Jrd::sym_type type, const Jrd::QualifiedName& name); void MET_error(const TEXT*, ...); Jrd::Format* MET_format(Jrd::thread_db*, Jrd::jrd_rel*, USHORT); -bool MET_get_char_coll_subtype(Jrd::thread_db*, USHORT*, const UCHAR*, USHORT); +bool MET_get_char_coll_subtype(Jrd::thread_db*, USHORT*, const Jrd::QualifiedName&); bool MET_get_char_coll_subtype_info(Jrd::thread_db*, USHORT, SubtypeInfo* info); Jrd::DmlNode* MET_get_dependencies(Jrd::thread_db*, Jrd::jrd_rel*, const UCHAR*, const ULONG, Jrd::CompilerScratch*, Jrd::bid*, Jrd::Statement**, - Jrd::CompilerScratch**, const Jrd::MetaName&, int, USHORT, - Jrd::jrd_tra*, const Jrd::MetaName& = Jrd::MetaName()); + Jrd::CompilerScratch**, const Jrd::QualifiedName&, int, USHORT, + Jrd::jrd_tra*, const Jrd::QualifiedName& = {}); Jrd::jrd_fld* MET_get_field(const Jrd::jrd_rel*, USHORT); ULONG MET_get_rel_flags_from_TYPE(USHORT); -bool MET_get_repl_state(Jrd::thread_db*, const Jrd::MetaName&); +bool MET_get_repl_state(Jrd::thread_db*, const Jrd::QualifiedName&); void MET_get_shadow_files(Jrd::thread_db*, bool); void MET_load_db_triggers(Jrd::thread_db*, int); void MET_load_ddl_triggers(Jrd::thread_db* tdbb); bool MET_load_exception(Jrd::thread_db*, Jrd::ExceptionItem&); -void MET_load_trigger(Jrd::thread_db*, Jrd::jrd_rel*, const Jrd::MetaName&, Jrd::TrigVector**); -void MET_lookup_cnstrt_for_index(Jrd::thread_db*, Jrd::MetaName& constraint, const Jrd::MetaName& index_name); -void MET_lookup_cnstrt_for_trigger(Jrd::thread_db*, Jrd::MetaName&, Jrd::MetaName&, const Jrd::MetaName&); -void MET_lookup_exception(Jrd::thread_db*, SLONG, /* OUT */ Jrd::MetaName&, /* OUT */ Firebird::string*); +void MET_load_trigger(Jrd::thread_db*, Jrd::jrd_rel*, const Jrd::QualifiedName&, Jrd::TrigVector**); +void MET_lookup_cnstrt_for_index(Jrd::thread_db*, Jrd::MetaName& constraint, const Jrd::QualifiedName& index_name); +void MET_lookup_cnstrt_for_trigger(Jrd::thread_db*, Jrd::MetaName&, Jrd::QualifiedName&, const Jrd::QualifiedName&); +void MET_lookup_exception(Jrd::thread_db*, SLONG, /* OUT */ Jrd::QualifiedName&, /* OUT */ Firebird::string*); int MET_lookup_field(Jrd::thread_db*, Jrd::jrd_rel*, const Jrd::MetaName&); Jrd::BlobFilter* MET_lookup_filter(Jrd::thread_db*, SSHORT, SSHORT); bool MET_load_generator(Jrd::thread_db*, Jrd::GeneratorItem&, bool* sysGen = 0, SLONG* step = 0); -SLONG MET_lookup_generator(Jrd::thread_db*, const Jrd::MetaName&, bool* sysGen = 0, SLONG* step = 0); -bool MET_lookup_generator_id(Jrd::thread_db*, SLONG, Jrd::MetaName&, bool* sysGen = 0); +SLONG MET_lookup_generator(Jrd::thread_db*, const Jrd::QualifiedName&, bool* sysGen = 0, SLONG* step = 0); +bool MET_lookup_generator_id(Jrd::thread_db*, SLONG, Jrd::QualifiedName&, bool* sysGen = 0); void MET_update_generator_increment(Jrd::thread_db* tdbb, SLONG gen_id, SLONG step); -void MET_lookup_index(Jrd::thread_db*, Jrd::MetaName&, const Jrd::MetaName&, USHORT); +void MET_lookup_index(Jrd::thread_db*, Jrd::QualifiedName&, const Jrd::QualifiedName&, USHORT); void MET_lookup_index_condition(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::index_desc*); void MET_lookup_index_expression(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::index_desc*); -bool MET_lookup_index_expr_cond_blr(Jrd::thread_db* tdbb, const Jrd::MetaName& index_name, Jrd::bid& expr_blob_id, Jrd::bid& cond_blob_id); -SLONG MET_lookup_index_name(Jrd::thread_db*, const Jrd::MetaName&, SLONG*, Jrd::IndexStatus* status); -bool MET_lookup_partner(Jrd::thread_db*, Jrd::jrd_rel*, struct Jrd::index_desc*, const TEXT*); +bool MET_lookup_index_expr_cond_blr(Jrd::thread_db* tdbb, const Jrd::QualifiedName& index_name, + Jrd::bid& expr_blob_id, Jrd::bid& cond_blob_id); +SLONG MET_lookup_index_name(Jrd::thread_db*, const Jrd::QualifiedName&, SLONG*, Jrd::IndexStatus* status); +bool MET_lookup_partner(Jrd::thread_db*, Jrd::jrd_rel*, struct Jrd::index_desc*, const Jrd::QualifiedName&); Jrd::jrd_prc* MET_lookup_procedure(Jrd::thread_db*, const Jrd::QualifiedName&, bool); Jrd::jrd_prc* MET_lookup_procedure_id(Jrd::thread_db*, USHORT, bool, bool, USHORT); -Jrd::jrd_rel* MET_lookup_relation(Jrd::thread_db*, const Jrd::MetaName&); +Jrd::jrd_rel* MET_lookup_relation(Jrd::thread_db*, const Jrd::QualifiedName&); Jrd::jrd_rel* MET_lookup_relation_id(Jrd::thread_db*, SLONG, bool); -Jrd::DmlNode* MET_parse_blob(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::bid*, Jrd::CompilerScratch**, - Jrd::Statement**, bool, bool); +Jrd::DmlNode* MET_parse_blob(Jrd::thread_db*, const Jrd::MetaName* schema, Jrd::jrd_rel*, Jrd::bid*, + Jrd::CompilerScratch**, Jrd::Statement**, bool, bool); void MET_post_existence(Jrd::thread_db*, Jrd::jrd_rel*); void MET_prepare(Jrd::thread_db*, Jrd::jrd_tra*, USHORT, const UCHAR*); Jrd::jrd_prc* MET_procedure(Jrd::thread_db*, USHORT, bool, USHORT); Jrd::jrd_rel* MET_relation(Jrd::thread_db*, USHORT); void MET_release_existence(Jrd::thread_db*, Jrd::jrd_rel*); -void MET_release_trigger(Jrd::thread_db*, Jrd::TrigVector**, const Jrd::MetaName&); +void MET_release_trigger(Jrd::thread_db*, Jrd::TrigVector**, const Jrd::QualifiedName&); void MET_release_triggers(Jrd::thread_db*, Jrd::TrigVector**, bool); #ifdef DEV_BUILD void MET_verify_cache(Jrd::thread_db*); #endif void MET_clear_cache(Jrd::thread_db*); bool MET_routine_in_use(Jrd::thread_db*, Jrd::Routine*); -void MET_revoke(Jrd::thread_db*, Jrd::jrd_tra*, const Jrd::MetaName&, - const Jrd::MetaName&, const Firebird::string&); +void MET_revoke(Jrd::thread_db*, Jrd::jrd_tra*, const Jrd::QualifiedName&, + const Jrd::QualifiedName&, const Firebird::string&); void MET_scan_partners(Jrd::thread_db*, Jrd::jrd_rel*); void MET_scan_relation(Jrd::thread_db*, Jrd::jrd_rel*); -void MET_trigger_msg(Jrd::thread_db*, Firebird::string&, const Jrd::MetaName&, USHORT); +void MET_trigger_msg(Jrd::thread_db*, Firebird::string&, const Jrd::QualifiedName&, USHORT); void MET_update_shadow(Jrd::thread_db*, Jrd::Shadow*, USHORT); void MET_update_transaction(Jrd::thread_db*, Jrd::jrd_tra*, const bool); -void MET_get_domain(Jrd::thread_db*, MemoryPool& csbPool, const Jrd::MetaName&, dsc*, - Jrd::FieldInfo*); +void MET_get_domain(Jrd::thread_db*, MemoryPool& csbPool, const Jrd::QualifiedName&, dsc*, Jrd::FieldInfo*); Jrd::MetaName MET_get_relation_field(Jrd::thread_db*, MemoryPool& csbPool, - const Jrd::MetaName&, const Jrd::MetaName&, dsc*, Jrd::FieldInfo*); + const Jrd::QualifiedName&, const Jrd::MetaName&, dsc*, Jrd::FieldInfo*); void MET_update_partners(Jrd::thread_db*); void MET_store_dependencies(Jrd::thread_db*, Firebird::Array& dependencies, - const Jrd::jrd_rel*, const Jrd::MetaName&, int, Jrd::jrd_tra*); + const Jrd::jrd_rel*, const Jrd::QualifiedName&, int, Jrd::jrd_tra*); int MET_get_linger(Jrd::thread_db*); Firebird::TriState MET_get_ss_definer(Jrd::thread_db*); +bool MET_qualify_existing_name(Jrd::thread_db* tdbb, Jrd::QualifiedName& name, ObjectType objType, + Firebird::ObjectsArray* schemaSearchPath = nullptr); +bool MET_check_package_exists(Jrd::thread_db* tdbb, const Jrd::QualifiedName& name); +bool MET_check_schema_exists(Jrd::thread_db* tdbb, const Jrd::MetaName& name); #endif // JRD_MET_PROTO_H diff --git a/src/jrd/names.h b/src/jrd/names.h index be65d34855..661c7974b7 100644 --- a/src/jrd/names.h +++ b/src/jrd/names.h @@ -474,3 +474,19 @@ NAME("RDB$VARBINARY_MAX", nam_varbinary_max) NAME("RDB$INTEGER", nam_integer) NAME("MON$PARALLEL_WORKERS", nam_par_workers) + +NAME("RDB$SCHEMA_NAME", nam_sch_name) +NAME("RDB$CHARACTER_SET_SCHEMA_NAME", nam_charset_sch_name) +NAME("RDB$DEFAULT_COLLATE_SCHEMA_NAME", nam_def_coll_sch_name) +NAME("RDB$RELATION_SCHEMA_NAME", nam_rel_sch_name) +NAME("RDB$DEPENDENT_SCHEMA_NAME", nam_dpd_sch_name) +NAME("RDB$DEPENDED_ON_SCHEMA_NAME", nam_dpd_o_sch_name) +NAME("MON$SCHEMA_NAME", nam_mon_sch_name) +NAME("RDB$SCHEMAS", nam_schemas) +NAME("RDB$FOREIGN_KEY_SCHEMA_NAME", nam_foreign_sch_name) +NAME("RDB$FIELD_SOURCE_SCHEMA_NAME", nam_field_source_sch_name) +NAME("RDB$USER_SCHEMA_NAME", nam_user_sch_name) +NAME("RDB$TABLE_SCHEMA_NAME", nam_tab_sch_name) +NAME("RDB$CONST_SCHEMA_NAME_UQ", nam_con_sch_name_uq) +NAME("MON$SEARCH_PATH", nam_mon_search_path) +NAME("RDB$TEXT_MAX", nam_text_max) diff --git a/src/jrd/obj.h b/src/jrd/obj.h index 77e8faa7cb..79c9c6c74e 100644 --- a/src/jrd/obj.h +++ b/src/jrd/obj.h @@ -76,10 +76,13 @@ const ObjectType obj_tablespace = 35; const ObjectType obj_tablespaces = 36; const ObjectType obj_index_condition = 37; -const ObjectType obj_type_MAX = 38; +const ObjectType obj_schema = 38; +const ObjectType obj_schemas = 39; -// not used in metadata / no relation with obj_type_MAX (should be greater) -const ObjectType obj_user_or_role= 100; +const ObjectType obj_type_MAX = 40; + +// used in the parser only / no relation with obj_type_MAX (should be greater) +const ObjectType obj_user_or_role = 100; const ObjectType obj_parameter = 101; const ObjectType obj_column = 102; const ObjectType obj_publication = 103; @@ -87,26 +90,35 @@ const ObjectType obj_publication = 103; const ObjectType obj_any = 255; -inline bool isDdlObject(ObjectType object_type) +inline bool isDdlObject(ObjectType objectType, bool* useSchema = nullptr) { - switch (object_type) + if (useSchema) + *useSchema = false; + + switch (objectType) { - case obj_database: case obj_relations: case obj_views: case obj_procedures: case obj_functions: case obj_packages: case obj_generators: - case obj_filters: case obj_domains: case obj_exceptions: - case obj_roles: case obj_charsets: case obj_collations: + if (useSchema) + *useSchema = true; + [[fallthrough]]; + + case obj_database: + case obj_filters: + case obj_roles: case obj_jobs: case obj_tablespaces: + case obj_schemas: return true; + default: return false; } @@ -143,10 +155,12 @@ inline const char* getSecurityClassName(ObjectType object_type) return "SQL$CHARSETS"; case obj_collations: return "SQL$COLLATIONS"; - case obj_tablespaces: - return "SQL$TABLESPACES"; case obj_jobs: return "SQL$JOBS"; + case obj_tablespaces: + return "SQL$TABLESPACES"; + case obj_schemas: + return "SQL$SCHEMAS"; default: return ""; } @@ -185,10 +199,51 @@ inline const char* getDdlObjectName(ObjectType object_type) return "ROLE"; case obj_filters: return "FILTER"; - case obj_tablespaces: - return "TABLESPACE"; case obj_jobs: return "JOB"; + case obj_tablespaces: + return "TABLESPACE"; + case obj_schemas: + return "SCHEMA"; + default: + fb_assert(false); + return ""; + } +} + + +inline const char* getObjectName(ObjectType objType) +{ + switch (objType) + { + case obj_relation: + return "TABLE"; + case obj_package_header: + return "PACKAGE"; + case obj_procedure: + return "PROCEDURE"; + case obj_udf: + return "FUNCTION"; + case obj_column: + return "COLUMN"; + case obj_charset: + return "CHARACTER SET"; + case obj_collation: + return "COLLATION"; + case obj_field: + return "DOMAIN"; + case obj_exception: + return "EXCEPTION"; + case obj_generator: + return "GENERATOR"; + case obj_view: + return "VIEW"; + case obj_sql_role: + return "ROLE"; + case obj_blob_filter: + return "FILTER"; + case obj_schema: + return "SCHEMA"; default: fb_assert(false); return ""; diff --git a/src/jrd/optimizer/Optimizer.cpp b/src/jrd/optimizer/Optimizer.cpp index 9d74042351..0f2e0f5d85 100644 --- a/src/jrd/optimizer/Optimizer.cpp +++ b/src/jrd/optimizer/Optimizer.cpp @@ -431,7 +431,7 @@ namespace if (relationId != arg.relationId) { // index %s cannot be used in the specified plan - ERR_post(Arg::Gds(isc_index_unused) << arg.indexName); + ERR_post(Arg::Gds(isc_index_unused) << arg.indexName.toQuotedString()); } if (idx.idx_id == arg.indexId) @@ -1068,8 +1068,12 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack) fb_assert(tail->csb_relation); - CMP_post_access(tdbb, csb, tail->csb_relation->rel_security_name, - tail->csb_view ? tail->csb_view->rel_id : 0, + const SLONG ssRelationId = tail->csb_view ? tail->csb_view->rel_id : 0; + + CMP_post_access(tdbb, csb, tail->csb_relation->rel_security_name.schema, ssRelationId, + SCL_usage, obj_schemas, QualifiedName(tail->csb_relation->rel_name.schema)); + + CMP_post_access(tdbb, csb, tail->csb_relation->rel_security_name.object, ssRelationId, SCL_update, obj_relations, tail->csb_relation->rel_name); } @@ -1679,9 +1683,9 @@ void Optimizer::checkIndices() { // index %s cannot be used in the specified plan if (isGbak) - ERR_post_warning(Arg::Warning(isc_index_unused) << plan->accessType->items[0].indexName); + ERR_post_warning(Arg::Warning(isc_index_unused) << plan->accessType->items[0].indexName.toQuotedString()); else - ERR_post(Arg::Gds(isc_index_unused) << plan->accessType->items[0].indexName); + ERR_post(Arg::Gds(isc_index_unused) << plan->accessType->items[0].indexName.toQuotedString()); } if (!tail->csb_idx) @@ -1689,7 +1693,7 @@ void Optimizer::checkIndices() // Check to make sure that all indices are either used or marked not to be used, // and that there are no unused navigational indices - MetaName index_name; + QualifiedName index_name; for (const auto& idx : *tail->csb_idx) { @@ -1699,13 +1703,13 @@ void Optimizer::checkIndices() if (relation) MET_lookup_index(tdbb, index_name, relation->rel_name, (USHORT) (idx.idx_id + 1)); else - index_name = ""; + index_name.clear(); // index %s cannot be used in the specified plan if (isGbak) - ERR_post_warning(Arg::Warning(isc_index_unused) << Arg::Str(index_name)); + ERR_post_warning(Arg::Warning(isc_index_unused) << index_name.toQuotedString()); else - ERR_post(Arg::Gds(isc_index_unused) << Arg::Str(index_name)); + ERR_post(Arg::Gds(isc_index_unused) << index_name.toQuotedString()); } } } @@ -2890,9 +2894,9 @@ string Optimizer::getStreamName(StreamType stream) string name; if (relation) - name = relation->rel_name.c_str(); + name = relation->rel_name.toQuotedString(); else if (procedure) - name = procedure->getName().toString(); + name = procedure->getName().toQuotedString(); if (alias && alias->hasData()) { @@ -2925,7 +2929,7 @@ string Optimizer::makeAlias(StreamType stream) if (csb_tail->csb_alias) alias_list.push(*csb_tail->csb_alias); else if (csb_tail->csb_relation) - alias_list.push(csb_tail->csb_relation->rel_name.c_str()); + alias_list.push(csb_tail->csb_relation->rel_name.object.c_str()); if (!csb_tail->csb_view) break; @@ -2942,9 +2946,9 @@ string Optimizer::makeAlias(StreamType stream) } } else if (csb_tail->csb_relation) - alias = csb_tail->csb_relation->rel_name.c_str(); + alias = csb_tail->csb_relation->rel_name.object.c_str(); else if (csb_tail->csb_procedure) - alias = csb_tail->csb_procedure->getName().toString(); + alias = csb_tail->csb_procedure->getName().object.c_str(); //// TODO: LocalTableSourceNode else fb_assert(false); diff --git a/src/jrd/optimizer/Retrieval.cpp b/src/jrd/optimizer/Retrieval.cpp index 22e3889306..eebf15622f 100644 --- a/src/jrd/optimizer/Retrieval.cpp +++ b/src/jrd/optimizer/Retrieval.cpp @@ -1219,7 +1219,7 @@ InversionNode* Retrieval::makeIndexScanNode(IndexScratch* indexScratch) const } // For external requests, determine index name (to be reported in plans) - MetaName indexName; + QualifiedName indexName; if (!(csb->csb_g_flags & csb_internal)) MET_lookup_index(tdbb, indexName, relation->rel_name, idx->idx_id + 1); diff --git a/src/jrd/par.cpp b/src/jrd/par.cpp index 3d7442d49d..b7775b7bf3 100644 --- a/src/jrd/par.cpp +++ b/src/jrd/par.cpp @@ -79,7 +79,7 @@ static NodeParseFunc blr_parsers[256] = {NULL}; static void par_error(BlrReader& blrReader, const Arg::StatusVector& v, bool isSyntaxError = true); static PlanNode* par_plan(thread_db*, CompilerScratch*); -static void getBlrVersion(CompilerScratch* csb); +static void getBlrVersionAndFlags(CompilerScratch* csb); static void parseSubRoutines(thread_db* tdbb, CompilerScratch* csb); static void setNodeLineColumn(CompilerScratch* csb, DmlNode* node, ULONG blrOffset); @@ -168,7 +168,7 @@ namespace // Parse blr, returning a compiler scratch block with the results. // Caller must do pool handling. -DmlNode* PAR_blr(thread_db* tdbb, jrd_rel* relation, const UCHAR* blr, ULONG blr_length, +DmlNode* PAR_blr(thread_db* tdbb, const MetaName* schema, jrd_rel* relation, const UCHAR* blr, ULONG blr_length, CompilerScratch* view_csb, CompilerScratch** csb_ptr, Statement** statementPtr, const bool trigger, USHORT flags) { @@ -180,9 +180,12 @@ DmlNode* PAR_blr(thread_db* tdbb, jrd_rel* relation, const UCHAR* blr, ULONG blr BlrParseWrapper csb(*tdbb->getDefaultPool(), relation, view_csb, csb_ptr, trigger, flags); + if (schema) + csb->csb_schema = *schema; + csb->csb_blr_reader = BlrReader(blr, blr_length); - getBlrVersion(csb); + getBlrVersionAndFlags(csb); csb->csb_node = PAR_parse_node(tdbb, csb); @@ -204,6 +207,7 @@ void PAR_preparsed_node(thread_db* tdbb, jrd_rel* relation, DmlNode* node, CompilerScratch* view_csb, CompilerScratch** csb_ptr, Statement** statementPtr, const bool trigger, USHORT flags) { + fb_assert(csb_ptr && *csb_ptr); BlrParseWrapper csb(*tdbb->getDefaultPool(), relation, view_csb, csb_ptr, trigger, flags); csb->blrVersion = 5; // blr_version5 @@ -216,7 +220,7 @@ void PAR_preparsed_node(thread_db* tdbb, jrd_rel* relation, DmlNode* node, // PAR_blr equivalent for validation expressions. // Validation expressions are boolean expressions, but may be prefixed with a blr_stmt_expr. -BoolExprNode* PAR_validation_blr(thread_db* tdbb, jrd_rel* relation, const UCHAR* blr, ULONG blr_length, +BoolExprNode* PAR_validation_blr(thread_db* tdbb, const MetaName* schema, jrd_rel* relation, const UCHAR* blr, ULONG blr_length, CompilerScratch* view_csb, CompilerScratch** csb_ptr, USHORT flags) { SET_TDBB(tdbb); @@ -229,9 +233,12 @@ BoolExprNode* PAR_validation_blr(thread_db* tdbb, jrd_rel* relation, const UCHAR BlrParseWrapper csb(*tdbb->getDefaultPool(), relation, view_csb, csb_ptr, false, flags); + if (schema) + csb->csb_schema = *schema; + csb->csb_blr_reader = BlrReader(blr, blr_length); - getBlrVersion(csb); + getBlrVersionAndFlags(csb); if (csb->csb_blr_reader.peekByte() == blr_stmt_expr) { @@ -411,6 +418,7 @@ USHORT PAR_desc(thread_db* tdbb, CompilerScratch* csb, dsc* desc, ItemInfo* item desc->clear(); + bool explicitCollation = false; const USHORT dtype = csb->csb_blr_reader.getByte(); switch (dtype) @@ -423,23 +431,29 @@ USHORT PAR_desc(thread_db* tdbb, CompilerScratch* csb, dsc* desc, ItemInfo* item case blr_domain_name: case blr_domain_name2: + case blr_domain_name3: { const bool fullDomain = (csb->csb_blr_reader.getByte() == blr_domain_full); - MetaName* name = FB_NEW_POOL(csb->csb_pool) MetaName(csb->csb_pool); - csb->csb_blr_reader.getMetaName(*name); + const auto name = FB_NEW_POOL(csb->csb_pool) QualifiedName(csb->csb_pool); - MetaNamePair namePair(*name, ""); + if (dtype == blr_domain_name3) + csb->csb_blr_reader.getMetaName(name->schema); + + csb->csb_blr_reader.getMetaName(name->object); + csb->qualifyExistingName(tdbb, *name, obj_field); + + QualifiedNameMetaNamePair entry(*name, {}); FieldInfo fieldInfo; - bool exist = csb->csb_map_field_info.get(namePair, fieldInfo); + bool exist = csb->csb_map_field_info.get(entry, fieldInfo); MET_get_domain(tdbb, csb->csb_pool, *name, desc, (exist ? NULL : &fieldInfo)); if (!exist) - csb->csb_map_field_info.put(namePair, fieldInfo); + csb->csb_map_field_info.put(entry, fieldInfo); if (itemInfo) { - itemInfo->field = namePair; + itemInfo->field = entry; if (fullDomain) { @@ -450,8 +464,11 @@ USHORT PAR_desc(thread_db* tdbb, CompilerScratch* csb, dsc* desc, ItemInfo* item itemInfo->nullable = true; } - if (dtype == blr_domain_name2) + if (dtype == blr_domain_name2 || + (dtype == blr_domain_name3 && csb->csb_blr_reader.getByte() != 0)) { + explicitCollation = true; + const USHORT ttype = csb->csb_blr_reader.getWord(); switch (desc->dsc_dtype) @@ -485,26 +502,33 @@ USHORT PAR_desc(thread_db* tdbb, CompilerScratch* csb, dsc* desc, ItemInfo* item case blr_column_name: case blr_column_name2: + case blr_column_name3: { const bool fullDomain = (csb->csb_blr_reader.getByte() == blr_domain_full); - MetaName* relationName = FB_NEW_POOL(csb->csb_pool) MetaName(csb->csb_pool); - csb->csb_blr_reader.getMetaName(*relationName); - MetaName* fieldName = FB_NEW_POOL(csb->csb_pool) MetaName(csb->csb_pool); + const auto relationName = FB_NEW_POOL(csb->csb_pool) QualifiedName(csb->csb_pool); + + if (dtype == blr_column_name3) + csb->csb_blr_reader.getMetaName(relationName->schema); + + csb->csb_blr_reader.getMetaName(relationName->object); + csb->qualifyExistingName(tdbb, *relationName, obj_relation); + + const auto fieldName = FB_NEW_POOL(csb->csb_pool) MetaName(csb->csb_pool); csb->csb_blr_reader.getMetaName(*fieldName); - MetaNamePair namePair(*relationName, *fieldName); + QualifiedNameMetaNamePair entry(*relationName, *fieldName); FieldInfo fieldInfo; - bool exist = csb->csb_map_field_info.get(namePair, fieldInfo); + bool exist = csb->csb_map_field_info.get(entry, fieldInfo); MET_get_relation_field(tdbb, csb->csb_pool, *relationName, *fieldName, desc, (exist ? NULL : &fieldInfo)); if (!exist) - csb->csb_map_field_info.put(namePair, fieldInfo); + csb->csb_map_field_info.put(entry, fieldInfo); if (itemInfo) { - itemInfo->field = namePair; + itemInfo->field = entry; if (fullDomain) { @@ -515,8 +539,11 @@ USHORT PAR_desc(thread_db* tdbb, CompilerScratch* csb, dsc* desc, ItemInfo* item itemInfo->nullable = true; } - if (dtype == blr_column_name2) + if (dtype == blr_column_name2 || + (dtype == blr_column_name3 && csb->csb_blr_reader.getByte() != 0)) { + explicitCollation = true; + const USHORT ttype = csb->csb_blr_reader.getWord(); switch (desc->dsc_dtype) @@ -564,8 +591,8 @@ USHORT PAR_desc(thread_db* tdbb, CompilerScratch* csb, dsc* desc, ItemInfo* item if (itemInfo) { - if (dtype == blr_cstring2 || dtype == blr_text2 || dtype == blr_varying2 || - dtype == blr_blob2 || dtype == blr_domain_name2) + if (dtype == blr_cstring2 || dtype == blr_text2 || dtype == blr_varying2 || dtype == blr_blob2 || + explicitCollation) { itemInfo->explicitCollation = true; } @@ -691,9 +718,12 @@ CompilerScratch* PAR_parse(thread_db* tdbb, const UCHAR* blr, ULONG blr_length, csb->csb_blr_reader = BlrReader(blr, blr_length); if (internal_flag) + { csb->csb_g_flags |= csb_internal; + csb->csb_schema = SYSTEM_SCHEMA; + } - getBlrVersion(csb); + getBlrVersionAndFlags(csb); if (dbginfo_length > 0) DBG_parse_debug_info(dbginfo_length, dbginfo, *csb->csb_dbg_info); @@ -985,6 +1015,7 @@ static PlanNode* par_plan(thread_db* tdbb, CompilerScratch* csb) case blr_rid: case blr_relation2: case blr_rid2: + case blr_relation3: { const auto relationNode = RelationSourceNode::parse(tdbb, csb, blrOp, false); plan->recordSourceNode = relationNode; @@ -1048,8 +1079,9 @@ static PlanNode* par_plan(thread_db* tdbb, CompilerScratch* csb) // pick up the index name and look up the appropriate ids - MetaName name; - csb->csb_blr_reader.getMetaName(name); + QualifiedName name; + csb->csb_blr_reader.getMetaName(name.object); + name.schema = relation->rel_name.schema; SLONG relation_id; IndexStatus idx_status; @@ -1059,21 +1091,21 @@ static PlanNode* par_plan(thread_db* tdbb, CompilerScratch* csb) { if (isGbak) { - PAR_warning(Arg::Warning(isc_indexname) << Arg::Str(name) << - Arg::Str(relation->rel_name)); + PAR_warning(Arg::Warning(isc_indexname) << name.toQuotedString() << + relation->rel_name.toQuotedString()); } else { - PAR_error(csb, Arg::Gds(isc_indexname) << Arg::Str(name) << - Arg::Str(relation->rel_name)); + PAR_error(csb, Arg::Gds(isc_indexname) << name.toQuotedString() << + relation->rel_name.toQuotedString()); } } else if (idx_status == MET_object_deferred_active) { if (!isGbak) { - PAR_error(csb, Arg::Gds(isc_indexname) << Arg::Str(name) << - Arg::Str(relation->rel_name)); + PAR_error(csb, Arg::Gds(isc_indexname) << name.toQuotedString() << + relation->rel_name.toQuotedString()); } } @@ -1091,13 +1123,15 @@ static PlanNode* par_plan(thread_db* tdbb, CompilerScratch* csb) CompilerScratch::Dependency dependency(obj_index); dependency.name = &item.indexName; csb->addDependency(dependency); - } + } if (csb->csb_blr_reader.peekByte() != blr_indices) break; // dimitr: FALL INTO, if the plan item is ORDER ... INDEX (...) + [[fallthrough]]; } + case blr_indices: { if (procedure) @@ -1117,8 +1151,9 @@ static PlanNode* par_plan(thread_db* tdbb, CompilerScratch* csb) while (count-- > 0) { - MetaName name; - csb->csb_blr_reader.getMetaName(name); + QualifiedName name; + csb->csb_blr_reader.getMetaName(name.object); + name.schema = relation->rel_name.schema; SLONG relation_id; IndexStatus idx_status; @@ -1128,21 +1163,21 @@ static PlanNode* par_plan(thread_db* tdbb, CompilerScratch* csb) { if (isGbak) { - PAR_warning(Arg::Warning(isc_indexname) << Arg::Str(name) << - Arg::Str(relation->rel_name)); + PAR_warning(Arg::Warning(isc_indexname) << name.toQuotedString() << + relation->rel_name.toQuotedString()); } else { - PAR_error(csb, Arg::Gds(isc_indexname) << Arg::Str(name) << - Arg::Str(relation->rel_name)); + PAR_error(csb, Arg::Gds(isc_indexname) << name.toQuotedString() << + relation->rel_name.toQuotedString()); } } else if (idx_status == MET_object_deferred_active) { if (!isGbak) { - PAR_error(csb, Arg::Gds(isc_indexname) << Arg::Str(name) << - Arg::Str(relation->rel_name)); + PAR_error(csb, Arg::Gds(isc_indexname) << name.toQuotedString() << + relation->rel_name.toQuotedString()); } } @@ -1164,8 +1199,10 @@ static PlanNode* par_plan(thread_db* tdbb, CompilerScratch* csb) } } break; + case blr_sequential: break; + default: PAR_syntax_error(csb, "access type"); } @@ -1206,6 +1243,7 @@ RecordSourceNode* PAR_parseRecordSource(thread_db* tdbb, CompilerScratch* csb) case blr_rid: case blr_relation2: case blr_rid2: + case blr_relation3: return RelationSourceNode::parse(tdbb, csb, blrOp, true); case blr_local_table_id: @@ -1312,11 +1350,11 @@ RseNode* PAR_rse(thread_db* tdbb, CompilerScratch* csb, SSHORT rse_op) const jrd_rel* relation = relNode->relation; fb_assert(relation); if (relation->isVirtual()) - PAR_error(csb, Arg::Gds(isc_forupdate_virtualtbl) << relation->rel_name, false); + PAR_error(csb, Arg::Gds(isc_forupdate_virtualtbl) << relation->rel_name.toQuotedString(), false); if (relation->isSystem()) - PAR_error(csb, Arg::Gds(isc_forupdate_systbl) << relation->rel_name, false); + PAR_error(csb, Arg::Gds(isc_forupdate_systbl) << relation->rel_name.toQuotedString(), false); if (relation->isTemporary()) - PAR_error(csb, Arg::Gds(isc_forupdate_temptbl) << relation->rel_name, false); + PAR_error(csb, Arg::Gds(isc_forupdate_temptbl) << relation->rel_name.toQuotedString(), false); } rse->flags |= RseNode::FLAG_WRITELOCK; break; @@ -1550,6 +1588,7 @@ DmlNode* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb) case blr_rid: case blr_relation2: case blr_rid2: + case blr_relation3: case blr_local_table_id: case blr_union: case blr_recurse: @@ -1618,9 +1657,11 @@ void PAR_warning(const Arg::StatusVector& v) // Get the BLR version from the CSB stream and complain if it's unknown. -static void getBlrVersion(CompilerScratch* csb) +static void getBlrVersionAndFlags(CompilerScratch* csb) { - const SSHORT version = csb->csb_blr_reader.getByte(); + BlrReader::Flags flags; + const SSHORT version = csb->csb_blr_reader.parseHeader(&flags); + switch (version) { case blr_version4: @@ -1637,6 +1678,9 @@ static void getBlrVersion(CompilerScratch* csb) Arg::Gds(isc_wroblrver2) << Arg::Num(blr_version4) << Arg::Num(blr_version5/*6*/) << Arg::Num(version)); } + + if (flags.searchSystemSchema) + csb->csb_g_flags |= csb_search_system_schema; } @@ -1647,14 +1691,16 @@ static void parseSubRoutines(thread_db* tdbb, CompilerScratch* csb) { const auto node = pair.second; Jrd::ContextPoolHolder context(tdbb, &node->subCsb->csb_pool); - PAR_blr(tdbb, nullptr, node->blrStart, node->blrLength, nullptr, &node->subCsb, nullptr, false, 0); + PAR_blr(tdbb, &csb->csb_schema, nullptr, node->blrStart, node->blrLength, nullptr, + &node->subCsb, nullptr, false, 0); } for (auto& pair : csb->subProcedures) { const auto node = pair.second; Jrd::ContextPoolHolder context(tdbb, &node->subCsb->csb_pool); - PAR_blr(tdbb, nullptr, node->blrStart, node->blrLength, nullptr, &node->subCsb, nullptr, false, 0); + PAR_blr(tdbb, &csb->csb_schema, nullptr, node->blrStart, node->blrLength, nullptr, + &node->subCsb, nullptr, false, 0); } } diff --git a/src/jrd/par_proto.h b/src/jrd/par_proto.h index c72d71861c..20c6c077de 100644 --- a/src/jrd/par_proto.h +++ b/src/jrd/par_proto.h @@ -47,11 +47,11 @@ struct dsc; Jrd::ValueListNode* PAR_args(Jrd::thread_db*, Jrd::CompilerScratch*, USHORT, USHORT); Jrd::ValueListNode* PAR_args(Jrd::thread_db*, Jrd::CompilerScratch*); -Jrd::DmlNode* PAR_blr(Jrd::thread_db*, Jrd::jrd_rel*, const UCHAR*, ULONG blr_length, +Jrd::DmlNode* PAR_blr(Jrd::thread_db*, const Jrd::MetaName* schema, Jrd::jrd_rel*, const UCHAR*, ULONG blr_length, Jrd::CompilerScratch*, Jrd::CompilerScratch**, Jrd::Statement**, const bool, USHORT); void PAR_preparsed_node(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::DmlNode*, Jrd::CompilerScratch*, Jrd::CompilerScratch**, Jrd::Statement**, const bool, USHORT); -Jrd::BoolExprNode* PAR_validation_blr(Jrd::thread_db*, Jrd::jrd_rel*, const UCHAR* blr, +Jrd::BoolExprNode* PAR_validation_blr(Jrd::thread_db*, const Jrd::MetaName* schema, Jrd::jrd_rel*, const UCHAR* blr, ULONG blr_length, Jrd::CompilerScratch*, Jrd::CompilerScratch**, USHORT); StreamType PAR_context(Jrd::CompilerScratch*, SSHORT*); StreamType PAR_context2(Jrd::CompilerScratch*, SSHORT*); diff --git a/src/jrd/recsrc/BitmapTableScan.cpp b/src/jrd/recsrc/BitmapTableScan.cpp index df80b4e2ef..0dc4a9aa61 100644 --- a/src/jrd/recsrc/BitmapTableScan.cpp +++ b/src/jrd/recsrc/BitmapTableScan.cpp @@ -140,7 +140,7 @@ void BitmapTableScan::internalGetPlan(thread_db* tdbb, PlanEntry& planEntry, uns { planEntry.className = "BitmapTableScan"; - planEntry.lines.add().text = "Table " + printName(tdbb, m_relation->rel_name.c_str(), m_alias) + " Access By ID"; + planEntry.lines.add().text = "Table " + printName(tdbb, m_relation->rel_name, m_alias) + " Access By ID"; printOptInfo(planEntry.lines); printInversion(tdbb, m_inversion, planEntry.lines, true, 1, false); @@ -148,6 +148,6 @@ void BitmapTableScan::internalGetPlan(thread_db* tdbb, PlanEntry& planEntry, uns planEntry.objectType = m_relation->getObjectType(); planEntry.objectName = m_relation->rel_name; - if (m_alias.hasData() && m_relation->rel_name != m_alias) + if (m_alias.hasData() && m_relation->rel_name.object != m_alias) planEntry.alias = m_alias; } diff --git a/src/jrd/recsrc/Cursor.cpp b/src/jrd/recsrc/Cursor.cpp index fe9face7d7..652f58ac5a 100644 --- a/src/jrd/recsrc/Cursor.cpp +++ b/src/jrd/recsrc/Cursor.cpp @@ -461,6 +461,6 @@ void Cursor::checkState(Request* request) const { status_exception::raise( Arg::Gds(isc_cursor_not_positioned) << - getName()); + getName().toQuotedString()); } } diff --git a/src/jrd/recsrc/ExternalTableScan.cpp b/src/jrd/recsrc/ExternalTableScan.cpp index 47d5330955..9e164a2bf9 100644 --- a/src/jrd/recsrc/ExternalTableScan.cpp +++ b/src/jrd/recsrc/ExternalTableScan.cpp @@ -130,12 +130,12 @@ void ExternalTableScan::internalGetPlan(thread_db* tdbb, PlanEntry& planEntry, u { planEntry.className = "ExternalTableScan"; - planEntry.lines.add().text = "Table " + printName(tdbb, m_relation->rel_name.c_str(), m_alias) + " Full Scan"; + planEntry.lines.add().text = "Table " + printName(tdbb, m_relation->rel_name, m_alias) + " Full Scan"; printOptInfo(planEntry.lines); planEntry.objectType = m_relation->getObjectType(); planEntry.objectName = m_relation->rel_name; - if (m_alias.hasData() && m_relation->rel_name != m_alias) + if (m_alias.hasData() && m_relation->rel_name.object != m_alias) planEntry.alias = m_alias; } diff --git a/src/jrd/recsrc/FullTableScan.cpp b/src/jrd/recsrc/FullTableScan.cpp index dcc8c6a041..bc14bbbfef 100644 --- a/src/jrd/recsrc/FullTableScan.cpp +++ b/src/jrd/recsrc/FullTableScan.cpp @@ -191,12 +191,12 @@ void FullTableScan::internalGetPlan(thread_db* tdbb, PlanEntry& planEntry, unsig else if (upperBounds) bounds += " (upper bound)"; - planEntry.lines.add().text = "Table " + printName(tdbb, m_relation->rel_name.c_str(), m_alias) + " Full Scan" + bounds; + planEntry.lines.add().text = "Table " + printName(tdbb, m_relation->rel_name, m_alias) + " Full Scan" + bounds; printOptInfo(planEntry.lines); planEntry.objectType = m_relation->getObjectType(); planEntry.objectName = m_relation->rel_name; - if (m_alias.hasData() && m_relation->rel_name != m_alias) + if (m_alias.hasData() && m_relation->rel_name.object != m_alias) planEntry.alias = m_alias; } diff --git a/src/jrd/recsrc/IndexTableScan.cpp b/src/jrd/recsrc/IndexTableScan.cpp index 7319e4dd83..7777c37ead 100644 --- a/src/jrd/recsrc/IndexTableScan.cpp +++ b/src/jrd/recsrc/IndexTableScan.cpp @@ -380,7 +380,8 @@ void IndexTableScan::internalGetPlan(thread_db* tdbb, PlanEntry& planEntry, unsi { planEntry.className = "IndexTableScan"; - planEntry.lines.add().text = "Table " + printName(tdbb, m_relation->rel_name.c_str(), m_alias) + " Access By ID"; + planEntry.lines.add().text = "Table " + printName(tdbb, m_relation->rel_name, m_alias) + + " Access By ID"; printOptInfo(planEntry.lines); printInversion(tdbb, m_index, planEntry.lines, true, 1, true); @@ -388,7 +389,7 @@ void IndexTableScan::internalGetPlan(thread_db* tdbb, PlanEntry& planEntry, unsi planEntry.objectType = m_relation->getObjectType(); planEntry.objectName = m_relation->rel_name; - if (m_alias.hasData() && m_relation->rel_name != m_alias) + if (m_alias.hasData() && m_relation->rel_name.object != m_alias) planEntry.alias = m_alias; if (m_inversion) diff --git a/src/jrd/recsrc/ProcedureScan.cpp b/src/jrd/recsrc/ProcedureScan.cpp index a351d4a99d..ed1d8f2a42 100644 --- a/src/jrd/recsrc/ProcedureScan.cpp +++ b/src/jrd/recsrc/ProcedureScan.cpp @@ -61,12 +61,12 @@ void ProcedureScan::internalOpen(thread_db* tdbb) const { status_exception::raise( Arg::Gds(isc_proc_pack_not_implemented) << - Arg::Str(m_procedure->getName().identifier) << Arg::Str(m_procedure->getName().package)); + m_procedure->getName().object << m_procedure->getName().getSchemaAndPackage().toQuotedString()); } else if (!m_procedure->isDefined()) { status_exception::raise( - Arg::Gds(isc_prcnotdef) << Arg::Str(m_procedure->getName().toString()) << + Arg::Gds(isc_prcnotdef) << Arg::Str(m_procedure->getName().toQuotedString()) << Arg::Gds(isc_modnotfound)); } @@ -264,14 +264,13 @@ void ProcedureScan::internalGetPlan(thread_db* tdbb, PlanEntry& planEntry, unsig { planEntry.className = "ProcedureScan"; - planEntry.lines.add().text = "Procedure " + printName(tdbb, m_procedure->getName().toString(), m_alias) + " Scan"; + planEntry.lines.add().text = "Procedure " + printName(tdbb, m_procedure->getName(), m_alias) + " Scan"; printOptInfo(planEntry.lines); planEntry.objectType = obj_procedure; - planEntry.packageName = m_procedure->getName().package; - planEntry.objectName = m_procedure->getName().identifier; + planEntry.objectName = m_procedure->getName(); - if (m_alias.hasData() && m_procedure->getName().toString() != m_alias) + if (m_alias.hasData() && m_procedure->getName().toQuotedString() != m_alias) planEntry.alias = m_alias; } diff --git a/src/jrd/recsrc/RecordSource.cpp b/src/jrd/recsrc/RecordSource.cpp index 8cf68d9de0..37bf1d2e61 100644 --- a/src/jrd/recsrc/RecordSource.cpp +++ b/src/jrd/recsrc/RecordSource.cpp @@ -1,3 +1,17 @@ +/* FIXME: +SQL> create table t1 (n1 integer); +SQL> create view v1 as select * from t1; +SQL> set plan; +SQL> select * from v1; + +PLAN (V1 "PUBLIC"."T1" NATURAL) +SQL> set explain; +SQL> select * from v1; + +Select Expression + -> Table "PUBLIC"."T1" as V1 "PUBLIC"."T1" Full Scan +*/ + /* * The contents of this file are subject to the Initial * Developer's Public License Version 1.0 (the "License"); @@ -139,16 +153,16 @@ bool RecordSource::getRecord(thread_db* tdbb) const string RecordSource::printName(thread_db* tdbb, const string& name, bool quote) { const string result(name.c_str(), name.length()); - return quote ? "\"" + result + "\"" : result; + return quote ? "\"" + result + "\"" : result; // FIXME: } -string RecordSource::printName(thread_db* tdbb, const string& name, const string& alias) +string RecordSource::printName(thread_db* tdbb, const QualifiedName& name, const string& alias) { - if (name == alias || alias.isEmpty()) - return printName(tdbb, name, true); + if (name.object == alias || alias.isEmpty()) + return printName(tdbb, name.toQuotedString(), false); - const string arg1 = printName(tdbb, name, true); - const string arg2 = printName(tdbb, alias, true); + const string arg1 = printName(tdbb, name.toQuotedString(), false); + const string arg2 = printName(tdbb, alias, false); string result; result.printf("%s as %s", arg1.c_str(), arg2.c_str()); @@ -187,11 +201,11 @@ void RecordSource::printInversion(thread_db* tdbb, const InversionNode* inversio { const IndexRetrieval* const retrieval = inversion->retrieval; - MetaName indexName; - if (retrieval->irb_name && retrieval->irb_name->hasData()) + QualifiedName indexName; + if (retrieval->irb_name && retrieval->irb_name->object.hasData()) indexName = *retrieval->irb_name; else - indexName.printf("", retrieval->irb_index + 1); + indexName.object.printf("", retrieval->irb_index + 1); if (detailed) { @@ -246,11 +260,11 @@ void RecordSource::printInversion(thread_db* tdbb, const InversionNode* inversio } } - plan->text = "Index " + printName(tdbb, indexName.c_str()) + + plan->text = "Index " + printName(tdbb, indexName.toQuotedString()) + (fullscan ? " Full" : unique ? " Unique" : list ? " List" : " Range") + " Scan" + bounds; } else - plan->text = printName(tdbb, indexName.c_str(), false); + plan->text = printName(tdbb, indexName.toQuotedString(), false); } break; diff --git a/src/jrd/recsrc/RecordSource.h b/src/jrd/recsrc/RecordSource.h index ee65daf6f1..9893316ace 100644 --- a/src/jrd/recsrc/RecordSource.h +++ b/src/jrd/recsrc/RecordSource.h @@ -125,8 +125,7 @@ namespace Jrd Firebird::ObjectsArray lines{getPool()}; Firebird::ObjectsArray children{getPool()}; std::optional objectType; - MetaName packageName; - MetaName objectName; + QualifiedName objectName; MetaName alias; const AccessPath* accessPath = nullptr; ULONG recordLength = 0; @@ -179,7 +178,7 @@ namespace Jrd RecordSource(CompilerScratch* csb); static Firebird::string printName(thread_db* tdbb, const Firebird::string& name, bool quote = true); - static Firebird::string printName(thread_db* tdbb, const Firebird::string& name, + static Firebird::string printName(thread_db* tdbb, const Jrd::QualifiedName& name, const Firebird::string& alias); static void printInversion(thread_db* tdbb, const InversionNode* inversion, diff --git a/src/jrd/recsrc/VirtualTableScan.cpp b/src/jrd/recsrc/VirtualTableScan.cpp index 8b7200f77b..40f6a3c7cd 100644 --- a/src/jrd/recsrc/VirtualTableScan.cpp +++ b/src/jrd/recsrc/VirtualTableScan.cpp @@ -124,12 +124,12 @@ void VirtualTableScan::internalGetPlan(thread_db* tdbb, PlanEntry& planEntry, un { planEntry.className = "VirtualTableScan"; - planEntry.lines.add().text = "Table " + printName(tdbb, m_relation->rel_name.c_str(), m_alias) + " Full Scan"; + planEntry.lines.add().text = "Table " + printName(tdbb, m_relation->rel_name, m_alias) + " Full Scan"; printOptInfo(planEntry.lines); planEntry.objectType = m_relation->getObjectType(); planEntry.objectName = m_relation->rel_name; - if (m_alias.hasData() && m_relation->rel_name != m_alias) + if (m_alias.hasData() && m_relation->rel_name.object != m_alias) planEntry.alias = m_alias; } diff --git a/src/jrd/relations.h b/src/jrd/relations.h index b2a7aaf57f..a98e0f4cf6 100644 --- a/src/jrd/relations.h +++ b/src/jrd/relations.h @@ -40,6 +40,7 @@ RELATION(nam_database, rel_database, ODS_8_0, rel_persistent) FIELD(f_dat_charset, nam_charset_name, fld_charset_name, 1, ODS_8_0) FIELD(f_dat_linger, nam_linger, fld_linger, 1, ODS_12_0) FIELD(f_dat_sql_security, nam_sql_security, fld_b_sql_security, 1, ODS_13_0) + FIELD(f_dat_charset_schema, nam_charset_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 2 (RDB$FIELDS) @@ -74,6 +75,7 @@ RELATION(nam_fields, rel_fields, ODS_8_0, rel_persistent) FIELD(f_fld_precision, nam_f_precision, fld_f_precision, 1, ODS_10_0) FIELD(f_fld_class, nam_class, fld_class, 1, ODS_12_0) FIELD(f_fld_owner, nam_owner, fld_user, 1, ODS_12_0) + FIELD(f_fld_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 3 (RDB$INDEX_SEGMENTS) @@ -82,6 +84,7 @@ RELATION(nam_i_segments, rel_segments, ODS_8_0, rel_persistent) FIELD(f_seg_field, nam_f_name, fld_f_name, 1, ODS_8_0) FIELD(f_seg_position, nam_f_position, fld_f_position, 1, ODS_8_0) FIELD(f_seg_statistics, nam_statistics, fld_statistics, 1, ODS_11_0) + FIELD(f_seg_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 4 (RDB$INDICES) @@ -101,6 +104,8 @@ RELATION(nam_indices, rel_indices, ODS_8_0, rel_persistent) FIELD(f_idx_statistics, nam_statistics, fld_statistics, 1, ODS_8_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) + FIELD(f_idx_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) + FIELD(f_idx_foreign_schema, nam_foreign_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 5 (RDB$RELATION_FIELDS) @@ -126,6 +131,8 @@ 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_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) + FIELD(f_rfr_field_source_schema, nam_field_source_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 6 (RDB$RELATIONS) @@ -148,6 +155,7 @@ 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_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 7 (RDB$VIEW_RELATIONS) @@ -158,6 +166,8 @@ RELATION(nam_v_relations, rel_vrel, ODS_8_0, rel_persistent) FIELD(f_vrl_cname, nam_context, fld_ctx_name, 1, ODS_8_0) FIELD(f_vrl_context_type, nam_ctx_type, fld_context, 1, ODS_12_0) FIELD(f_vrl_pkg_name, nam_pkg_name, fld_pkg_name, 1, ODS_12_0) + FIELD(f_vrl_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) + FIELD(f_vrl_rname_schema, nam_rel_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 8 (RDB$FORMATS) @@ -210,6 +220,7 @@ RELATION(nam_trgs, rel_triggers, ODS_8_0, rel_persistent) FIELD(f_trg_engine_name, nam_engine_name, fld_engine_name, 1, ODS_12_0) FIELD(f_trg_entry, nam_entry, fld_ext_name, 1, ODS_12_0) FIELD(f_trg_sql_security, nam_sql_security, fld_b_sql_security, 1, ODS_13_0) + FIELD(f_trg_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 13 (RDB$DEPENDENCIES) @@ -220,6 +231,8 @@ RELATION(nam_dpds, rel_dpds, ODS_8_0, rel_persistent) FIELD(f_dpd_type, nam_dpd_type, fld_obj_type, 1, ODS_8_0) FIELD(f_dpd_o_type, nam_dpd_o_type, fld_obj_type, 1, ODS_8_0) FIELD(f_dpd_pkg_name, nam_pkg_name, fld_pkg_name, 1, ODS_12_0) + FIELD(f_dpd_schema, nam_dpd_sch_name, fld_sch_name, 1, ODS_14_0) + FIELD(f_dpd_o_schema, nam_dpd_o_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 14 (RDB$FUNCTIONS) @@ -245,6 +258,7 @@ RELATION(nam_funs, rel_funs, ODS_8_0, rel_persistent) FIELD(f_fun_legacy_flag, nam_legacy_flag, fld_flag_nullable, 0, ODS_12_0) FIELD(f_fun_deterministic_flag, nam_deterministic_flag, fld_flag_nullable, 0, ODS_12_0) FIELD(f_fun_sql_security, nam_sql_security, fld_b_sql_security, 1, ODS_13_0) + FIELD(f_fun_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 15 (RDB$FUNCTION_ARGUMENTS) @@ -271,6 +285,9 @@ RELATION(nam_args, rel_args, ODS_8_0, rel_persistent) FIELD(f_arg_rname, nam_r_name, fld_r_name, 1, ODS_12_0) FIELD(f_arg_sys_flag, nam_sys_flag, fld_flag, 0, ODS_12_0) FIELD(f_arg_desc, nam_description, fld_description, 1, ODS_12_0) + FIELD(f_arg_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) + FIELD(f_arg_rel_schema, nam_rel_sch_name, fld_sch_name, 1, ODS_14_0) + FIELD(f_arg_field_source_schema, nam_field_source_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 16 (RDB$FILTERS) @@ -291,6 +308,7 @@ RELATION(nam_trg_msgs, rel_msgs, ODS_8_0, rel_persistent) FIELD(f_msg_trigger, nam_trg_name, fld_trg_name, 1, ODS_8_0) FIELD(f_msg_number, nam_msg_num, fld_msg_num, 1, ODS_8_0) FIELD(f_msg_msg, nam_msg, fld_msg, 1, ODS_8_0) + FIELD(f_msg_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 18 (RDB$USER_PRIVILEGES) @@ -303,6 +321,8 @@ RELATION(nam_user_privileges, rel_priv, ODS_8_0, rel_persistent) FIELD(f_prv_fname, nam_f_name, fld_f_name, 1, ODS_8_0) FIELD(f_prv_u_type, nam_user_type, fld_obj_type, 1, ODS_8_0) FIELD(f_prv_o_type, nam_obj_type, fld_obj_type, 1, ODS_8_0) + FIELD(f_prv_rel_schema, nam_rel_sch_name, fld_sch_name, 1, ODS_14_0) + FIELD(f_prv_user_schema, nam_user_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 19 (RDB$TRANSACTIONS) @@ -323,6 +343,7 @@ RELATION(nam_gens, rel_gens, ODS_8_0, rel_persistent) FIELD(f_gen_owner, nam_owner, fld_user, 1, ODS_12_0) FIELD(f_gen_init_val, nam_init_val, fld_gen_val, 1, ODS_12_0) FIELD(f_gen_increment, nam_gen_increment, fld_gen_increment, 1, ODS_12_0) + FIELD(f_gen_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 21 (RDB$FIELD_DIMENSIONS) @@ -331,6 +352,7 @@ RELATION(nam_fld_dims, rel_dims, ODS_8_0, rel_persistent) FIELD(f_dims_dim, nam_dim, fld_dim, 1, ODS_8_0) FIELD(f_dims_lower, nam_lower, fld_bound, 1, ODS_8_0) FIELD(f_dims_upper, nam_upper, fld_bound, 1, ODS_8_0) + FIELD(f_dims_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 22 (RDB$RELATION_CONSTRAINTS) @@ -341,6 +363,7 @@ RELATION(nam_rel_constr, rel_rcon, ODS_8_0, rel_persistent) FIELD(f_rcon_dfr, nam_defer, fld_defer, 1, ODS_8_0) FIELD(f_rcon_idfr, nam_init_defer, fld_defer, 1, ODS_8_0) FIELD(f_rcon_iname, nam_i_name, fld_i_name, 1, ODS_8_0) + FIELD(f_rcon_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 23 (RDB$REF_CONSTRAINTS) @@ -350,12 +373,15 @@ RELATION(nam_ref_constr, rel_refc, ODS_8_0, rel_persistent) FIELD(f_refc_match, nam_match, fld_match, 1, ODS_8_0) FIELD(f_refc_upd_rul, nam_upd_rule, fld_rule, 1, ODS_8_0) FIELD(f_refc_del_rul, nam_del_rule, fld_rule, 1, ODS_8_0) + FIELD(f_refc_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) + FIELD(f_refc_uq_schema, nam_con_sch_name_uq, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 24 (RDB$CHECK_CONSTRAINTS) RELATION(nam_chk_constr, rel_ccon, ODS_8_0, rel_persistent) FIELD(f_ccon_cname, nam_con_name, fld_con_name, 1, ODS_8_0) FIELD(f_ccon_tname, nam_trg_name, fld_trg_name, 1, ODS_8_0) + FIELD(f_ccon_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 25 (RDB$LOG_FILES) @@ -389,6 +415,7 @@ RELATION(nam_procedures, rel_procedures, ODS_8_0, rel_persistent) FIELD(f_prc_pkg_name, nam_pkg_name, fld_pkg_name, 1, ODS_12_0) FIELD(f_prc_private_flag, nam_private_flag, fld_flag_nullable, 1, ODS_12_0) FIELD(f_prc_sql_security, nam_sql_security, fld_b_sql_security, 1, ODS_13_0) + FIELD(f_prc_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 27 (RDB$PROCEDURE_PARAMETERS) @@ -408,6 +435,9 @@ RELATION(nam_proc_parameters, rel_prc_prms, ODS_8_0, rel_persistent) FIELD(f_prm_fname, nam_f_name, fld_f_name, 1, ODS_11_2) FIELD(f_prm_rname, nam_r_name, fld_r_name, 1, ODS_11_2) FIELD(f_prm_pkg_name, nam_pkg_name, fld_pkg_name, 1, ODS_12_0) + FIELD(f_prm_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) + FIELD(f_prm_rel_schema, nam_rel_sch_name, fld_sch_name, 1, ODS_14_0) + FIELD(f_prm_field_source_schema, nam_field_source_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 28 (RDB$CHARACTER_SETS) @@ -423,6 +453,8 @@ RELATION(nam_charsets, rel_charsets, ODS_8_0, rel_persistent) FIELD(f_cs_bytes_char, nam_bytes_per_char, fld_f_length, 1, ODS_8_0) FIELD(f_cs_class, nam_class, fld_class, 1, ODS_12_0) FIELD(f_cs_owner, nam_owner, fld_user, 1, ODS_12_0) + FIELD(f_cs_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) + FIELD(f_cs_def_coll_schema, nam_def_coll_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 29 (RDB$COLLATIONS) @@ -438,6 +470,7 @@ RELATION(nam_collations, rel_collations, ODS_8_0, rel_persistent) FIELD(f_coll_specific_attr, nam_specific_attr, fld_specific_attr, 1, ODS_11_0) FIELD(f_coll_class, nam_class, fld_class, 1, ODS_12_0) FIELD(f_coll_owner, nam_owner, fld_user, 1, ODS_12_0) + FIELD(f_coll_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 30 (RDB$EXCEPTIONS) @@ -449,6 +482,7 @@ RELATION(nam_exceptions, rel_exceptions, ODS_8_0, rel_persistent) FIELD(f_xcp_sys_flag, nam_sys_flag, fld_flag, 1, ODS_8_0) FIELD(f_xcp_class, nam_class, fld_class, 1, ODS_12_0) FIELD(f_xcp_owner, nam_owner, fld_user, 1, ODS_12_0) + FIELD(f_xcp_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 31 (RDB$ROLES) @@ -533,6 +567,7 @@ RELATION(nam_mon_attachments, rel_mon_attachments, ODS_11_1, rel_virtual) FIELD(f_mon_att_remote_crypt, nam_wire_crypt_plugin, fld_remote_crypt, 0, ODS_13_0) FIELD(f_mon_att_session_tz, nam_mon_session_tz, fld_tz_name, 0, ODS_13_1) FIELD(f_mon_att_par_workers, nam_par_workers, fld_par_workers, 0, ODS_13_1) + FIELD(f_mon_att_search_path, nam_mon_search_path, fld_text_max, 0, ODS_14_0) END_RELATION // Relation 35 (MON$TRANSACTIONS) @@ -581,6 +616,7 @@ RELATION(nam_mon_calls, rel_mon_calls, ODS_11_1, rel_virtual) FIELD(f_mon_call_stat_id, nam_mon_stat_id, fld_stat_id, 0, ODS_11_1) FIELD(f_mon_call_pkg_name, nam_mon_pkg_name, fld_pkg_name, 0, ODS_12_0) FIELD(f_mon_call_cmp_stmt_id, nam_mon_cmp_stmt_id, fld_stmt_id, 0, ODS_13_1) + FIELD(f_mon_call_sch_name, nam_mon_sch_name, fld_sch_name, 0, ODS_14_0) END_RELATION // Relation 38 (MON$IO_STATS) @@ -643,6 +679,7 @@ RELATION(nam_packages, rel_packages, ODS_12_0, rel_persistent) FIELD(f_pkg_sys_flag, nam_sys_flag, fld_flag, 1, ODS_12_0) FIELD(f_pkg_desc, nam_description, fld_description, 1, ODS_12_0) FIELD(f_pkg_sql_security, nam_sql_security, fld_b_sql_security, 1, ODS_13_0) + FIELD(f_pkg_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 43 (SEC$USERS) @@ -710,6 +747,7 @@ RELATION(nam_mon_tab_stats, rel_mon_tab_stats, ODS_12_0, rel_virtual) FIELD(f_mon_tab_stat_group, nam_mon_stat_group, fld_stat_group, 0, ODS_12_0) FIELD(f_mon_tab_name, nam_mon_tab_name, fld_r_name, 0, ODS_12_0) FIELD(f_mon_tab_rec_stat_id, nam_mon_rec_stat_id, fld_stat_id, 0, ODS_12_0) + FIELD(f_mon_tab_sch_name, nam_mon_sch_name, fld_sch_name, 0, ODS_14_0) END_RELATION // Relation 50 (RDB$TIME_ZONES) @@ -731,6 +769,7 @@ END_RELATION RELATION(nam_pub_tables, rel_pub_tables, ODS_13_0, rel_persistent) FIELD(f_pubtab_pub_name, nam_pub_name, fld_pub_name, 1, ODS_13_0) FIELD(f_pubtab_tab_name, nam_tab_name, fld_r_name, 1, ODS_13_0) + FIELD(f_pubtab_tab_schema, nam_tab_sch_name, fld_sch_name, 1, ODS_14_0) END_RELATION // Relation 53 (RDB$CONFIG) @@ -758,4 +797,16 @@ RELATION(nam_mon_compiled_statements, rel_mon_compiled_statements, ODS_13_1, rel FIELD(f_mon_cmp_stmt_type, nam_mon_obj_type, fld_obj_type, 0, ODS_13_1) FIELD(f_mon_cmp_stmt_pkg_name, nam_mon_pkg_name, fld_pkg_name, 0, ODS_13_1) FIELD(f_mon_cmp_stmt_stat_id, nam_mon_stat_id, fld_stat_id, 0, ODS_13_1) + FIELD(f_mon_cmp_sch_name, nam_mon_sch_name, fld_sch_name, 0, ODS_14_0) +END_RELATION + +// Relation 56 (RDB$SCHEMAS) +RELATION(nam_schemas, rel_schemas, ODS_14_0, rel_persistent) + FIELD(f_sch_schema, nam_sch_name, fld_sch_name, 1, ODS_14_0) + FIELD(f_sch_owner, nam_owner, fld_user, 1, ODS_14_0) + FIELD(f_sch_charset, nam_charset_name, fld_charset_name, 1, ODS_14_0) + FIELD(f_sch_charset_schema, nam_charset_sch_name, fld_sch_name, 1, ODS_14_0) + FIELD(f_sch_class, nam_class, fld_class, 1, ODS_14_0) + FIELD(f_sch_sys_flag, nam_sys_flag, fld_flag, 1, ODS_14_0) + FIELD(f_sch_desc, nam_description, fld_description, 1, ODS_14_0) END_RELATION diff --git a/src/jrd/replication/Applier.cpp b/src/jrd/replication/Applier.cpp index c9fae3bf2e..4e88cea785 100644 --- a/src/jrd/replication/Applier.cpp +++ b/src/jrd/replication/Applier.cpp @@ -60,26 +60,6 @@ using namespace Replication; namespace { - struct NoKeyTable - { - USHORT rel_id; - USHORT rel_fields[8]; - }; - - const auto UNDEF = MAX_USHORT; - - NoKeyTable NO_KEY_TABLES[] = { - { rel_segments, { f_seg_name, f_seg_field, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF } }, - { rel_args, { f_arg_fun_name, f_arg_pos, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF } }, - { rel_ccon, { f_ccon_cname, f_ccon_tname, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF } }, - { rel_vrel, { f_vrl_vname, f_vrl_context, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF } }, - { rel_msgs, { f_msg_trigger, f_msg_number, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF } }, - { rel_dims, { f_dims_fname, f_dims_dim, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF } }, - { rel_files, { f_file_name, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF } }, - { rel_priv, { f_prv_user, f_prv_u_type, f_prv_o_type, f_prv_priv, f_prv_grant, f_prv_grantor, f_prv_rname, f_prv_fname } }, - { rel_db_creators, { f_crt_user, f_crt_u_type, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF } } - }; - class BlockReader : public AutoStorage { public: @@ -143,12 +123,31 @@ namespace return value; } - const MetaString& getMetaName() + const string& getAtomString() { const auto pos = getInt32(); return m_atoms[pos]; } + const MetaString getAtomMetaName() + { + const auto pos = getInt32(); + return m_atoms[pos]; + } + + const QualifiedMetaString getAtomQualifiedName() + { + if (getProtocolVersion() < PROTOCOL_VERSION_2) + return QualifiedMetaString(getAtomMetaName()); + + const auto& schema = getAtomMetaName(); + const auto& object = getAtomMetaName(); + + fb_assert(schema.hasData() && object.hasData()); + + return QualifiedMetaString(object, schema); + } + string getString() { const auto length = getInt32(); @@ -193,7 +192,7 @@ namespace const Block* const m_header; const UCHAR* m_data; const UCHAR* const m_end; - HalfStaticArray m_atoms; + ObjectsArray m_atoms; static void malformed() { @@ -358,7 +357,7 @@ void Applier::process(thread_db* tdbb, ULONG length, const UCHAR* data) case opInsertRecord: { - const auto relName = reader.getMetaName(); + const auto& relName = reader.getAtomQualifiedName(); const ULONG length = reader.getInt32(); const auto record = reader.getBinary(length); insertRecord(tdbb, traNum, relName, length, record); @@ -367,7 +366,7 @@ void Applier::process(thread_db* tdbb, ULONG length, const UCHAR* data) case opUpdateRecord: { - const auto relName = reader.getMetaName(); + const auto& relName = reader.getAtomQualifiedName(); const ULONG orgLength = reader.getInt32(); const auto orgRecord = reader.getBinary(orgLength); const ULONG newLength = reader.getInt32(); @@ -378,7 +377,7 @@ void Applier::process(thread_db* tdbb, ULONG length, const UCHAR* data) case opDeleteRecord: { - const auto relName = reader.getMetaName(); + const auto& relName = reader.getAtomQualifiedName(); const ULONG length = reader.getInt32(); const auto record = reader.getBinary(length); deleteRecord(tdbb, traNum, relName, length, record); @@ -407,17 +406,19 @@ void Applier::process(thread_db* tdbb, ULONG length, const UCHAR* data) case opExecuteSql: case opExecuteSqlIntl: { - const auto ownerName = reader.getMetaName(); + const auto& ownerName = reader.getAtomMetaName(); + const string& schemaSearchPath = op == opExecuteSql || protocol < PROTOCOL_VERSION_2 ? + string() : reader.getAtomString(); const unsigned charset = (op == opExecuteSql) ? CS_UTF8 : reader.getByte(); const string sql = reader.getString(); - executeSql(tdbb, traNum, charset, sql, ownerName); + executeSql(tdbb, traNum, charset, schemaSearchPath, sql, ownerName); } break; case opSetSequence: { - const auto genName = reader.getMetaName(); + const auto& genName = QualifiedName(reader.getAtomQualifiedName()); const auto value = reader.getInt64(); setSequence(tdbb, genName, value); } @@ -540,7 +541,7 @@ void Applier::cleanupSavepoint(thread_db* tdbb, TraNumber traNum, bool undo) } void Applier::insertRecord(thread_db* tdbb, TraNumber traNum, - const MetaName& relName, + const QualifiedName& relName, ULONG length, const UCHAR* data) { jrd_tra* transaction = NULL; @@ -549,12 +550,16 @@ void Applier::insertRecord(thread_db* tdbb, TraNumber traNum, LocalThreadContext context(tdbb, transaction, m_request); Jrd::ContextPoolHolder context2(tdbb, m_request->req_pool); + const auto attachment = tdbb->getAttachment(); TRA_attach_request(transaction, m_request); - const auto relation = MET_lookup_relation(tdbb, relName); + QualifiedName qualifiedRelName(relName); + attachment->qualifyExistingName(tdbb, qualifiedRelName, obj_relation); + + const auto relation = MET_lookup_relation(tdbb, qualifiedRelName); if (!relation) - raiseError("Table %s is not found", relName.c_str()); + raiseError("Table %s is not found", qualifiedRelName.toQuotedString().c_str()); if (!(relation->rel_flags & REL_scanned)) MET_scan_relation(tdbb, relation); @@ -634,7 +639,7 @@ void Applier::insertRecord(thread_db* tdbb, TraNumber traNum, fb_assert(error[2] == isc_arg_string); fb_assert(error[3] != 0); - const char* idxName = reinterpret_cast(error[3]); + const auto idxName = QualifiedName::parseSchemaObject(reinterpret_cast(error[3])); index_desc idx; const auto indexed = lookupRecord(tdbb, relation, record, idx, idxName); @@ -653,7 +658,10 @@ void Applier::insertRecord(thread_db* tdbb, TraNumber traNum, (!indexed || compareKey(tdbb, relation, idx, record, tempRpb.rpb_record))) { if (found) - raiseError("Record in table %s is ambiguously identified using the primary/unique key", relName.c_str()); + { + raiseError("Record in table %s is ambiguously identified using the primary/unique key", + qualifiedRelName.toQuotedString().c_str()); + } rpb = tempRpb; found = true; @@ -666,7 +674,8 @@ void Applier::insertRecord(thread_db* tdbb, TraNumber traNum, if (found) { - logConflict("Record being inserted into table %s already exists, updating instead", relName.c_str()); + logConflict("Record being inserted into table %s already exists, updating instead", + qualifiedRelName.toQuotedString().c_str()); record_param newRpb; newRpb.rpb_relation = relation; @@ -690,7 +699,7 @@ void Applier::insertRecord(thread_db* tdbb, TraNumber traNum, } void Applier::updateRecord(thread_db* tdbb, TraNumber traNum, - const MetaName& relName, + const QualifiedName& relName, ULONG orgLength, const UCHAR* orgData, ULONG newLength, const UCHAR* newData) { @@ -700,12 +709,16 @@ void Applier::updateRecord(thread_db* tdbb, TraNumber traNum, LocalThreadContext context(tdbb, transaction, m_request); Jrd::ContextPoolHolder context2(tdbb, m_request->req_pool); + const auto attachment = tdbb->getAttachment(); TRA_attach_request(transaction, m_request); - const auto relation = MET_lookup_relation(tdbb, relName); + QualifiedName qualifiedRelName(relName); + attachment->qualifyExistingName(tdbb, qualifiedRelName, obj_relation); + + const auto relation = MET_lookup_relation(tdbb, qualifiedRelName); if (!relation) - raiseError("Table %s is not found", relName.c_str()); + raiseError("Table %s is not found", qualifiedRelName.toQuotedString().c_str()); if (!(relation->rel_flags & REL_scanned)) MET_scan_relation(tdbb, relation); @@ -757,7 +770,10 @@ void Applier::updateRecord(thread_db* tdbb, TraNumber traNum, (!indexed || compareKey(tdbb, relation, idx, orgRecord, tempRpb.rpb_record))) { if (found) - raiseError("Record in table %s is ambiguously identified using the primary/unique key", relName.c_str()); + { + raiseError("Record in table %s is ambiguously identified using the primary/unique key", + qualifiedRelName.toQuotedString().c_str()); + } orgRpb = tempRpb; found = true; @@ -823,16 +839,17 @@ void Applier::updateRecord(thread_db* tdbb, TraNumber traNum, else { #ifdef RESOLVE_CONFLICTS - logConflict("Record being updated in table %s does not exist, inserting instead", relName.c_str()); + logConflict("Record being updated in table %s does not exist, inserting instead", + qualifiedRelName.toQuotedString().c_str()); doInsert(tdbb, &newRpb, transaction); #else - raiseError("Record in table %s cannot be located via the primary/unique key", relName.c_str()); + raiseError("Record in table %s cannot be located via the primary/unique key", qualifiedRelName.c_str()); #endif } } void Applier::deleteRecord(thread_db* tdbb, TraNumber traNum, - const MetaName& relName, + const QualifiedName& relName, ULONG length, const UCHAR* data) { jrd_tra* transaction = NULL; @@ -841,12 +858,16 @@ void Applier::deleteRecord(thread_db* tdbb, TraNumber traNum, LocalThreadContext context(tdbb, transaction, m_request); Jrd::ContextPoolHolder context2(tdbb, m_request->req_pool); + const auto attachment = tdbb->getAttachment(); TRA_attach_request(transaction, m_request); - const auto relation = MET_lookup_relation(tdbb, relName); + QualifiedName qualifiedRelName(relName); + attachment->qualifyExistingName(tdbb, qualifiedRelName, obj_relation); + + const auto relation = MET_lookup_relation(tdbb, qualifiedRelName); if (!relation) - raiseError("Table %s is not found", relName.c_str()); + raiseError("Table %s is not found", qualifiedRelName.toQuotedString().c_str()); if (!(relation->rel_flags & REL_scanned)) MET_scan_relation(tdbb, relation); @@ -883,7 +904,10 @@ void Applier::deleteRecord(thread_db* tdbb, TraNumber traNum, (!indexed || compareKey(tdbb, relation, idx, record, tempRpb.rpb_record))) { if (found) - raiseError("Record in table %s is ambiguously identified using the primary/unique key", relName.c_str()); + { + raiseError("Record in table %s is ambiguously identified using the primary/unique key", + qualifiedRelName.toQuotedString().c_str()); + } rpb = tempRpb; found = true; @@ -900,27 +924,30 @@ void Applier::deleteRecord(thread_db* tdbb, TraNumber traNum, else { #ifdef RESOLVE_CONFLICTS - logConflict("Record being deleted from table %s does not exist, ignoring", relName.c_str()); + logConflict("Record being deleted from table %s does not exist, ignoring", qualifiedRelName.toQuotedString().c_str()); #else - raiseError("Record in table %s cannot be located via the primary/unique key", relName.c_str()); + raiseError("Record in table %s cannot be located via the primary/unique key", qualifiedRelName.c_str()); #endif } } -void Applier::setSequence(thread_db* tdbb, const MetaName& genName, SINT64 value) +void Applier::setSequence(thread_db* tdbb, const QualifiedName& genName, SINT64 value) { const auto attachment = tdbb->getAttachment(); - auto gen_id = attachment->att_generators.lookup(genName); + QualifiedName qualifiedGenName(genName); + attachment->qualifyExistingName(tdbb, qualifiedGenName, obj_generator); + + auto gen_id = attachment->att_generators.lookup(qualifiedGenName); if (gen_id < 0) { - gen_id = MET_lookup_generator(tdbb, genName); + gen_id = MET_lookup_generator(tdbb, qualifiedGenName); if (gen_id < 0) - raiseError("Generator %s is not found", genName.c_str()); + raiseError("Generator %s is not found", qualifiedGenName.toQuotedString().c_str()); - attachment->att_generators.store(gen_id, genName); + attachment->att_generators.store(gen_id, qualifiedGenName); } AutoSetRestoreFlag noCascade(&tdbb->tdbb_flags, TDBB_repl_in_progress, !m_enableCascade); @@ -972,6 +999,7 @@ void Applier::storeBlob(thread_db* tdbb, TraNumber traNum, bid* blobId, void Applier::executeSql(thread_db* tdbb, TraNumber traNum, unsigned charset, + const string& schemaSearchPath, const string& sql, const MetaName& ownerName) { @@ -994,9 +1022,26 @@ void Applier::executeSql(thread_db* tdbb, AutoSetRestore autoUser(&attachment->att_user, owner); AutoSetRestoreFlag noCascade(&tdbb->tdbb_flags, TDBB_repl_in_progress, !m_enableCascade); - DSQL_execute_immediate(tdbb, attachment, &transaction, - 0, sql.c_str(), dialect, - NULL, NULL, NULL, NULL, false); + // FIXME: Should use dbb->replConfig()->schemaSearchPath here? Isn't it already in the initial search path? + const string& newSearchPathStr = schemaSearchPath.hasData() ? + schemaSearchPath : dbb->replConfig()->schemaSearchPath; + + if (newSearchPathStr.hasData()) + { + auto newSearchPath = makeRef(FB_NEW AnyRef>(*getDefaultMemoryPool())); + MetaString::parseList(newSearchPathStr, *newSearchPath); + + AutoSetRestore>>> autoSchemaSearchPath( + &attachment->att_schema_search_path, newSearchPath); + + DSQL_execute_immediate(tdbb, attachment, &transaction, 0, sql.c_str(), dialect, + nullptr, nullptr, nullptr, nullptr, false); + } + else + { + DSQL_execute_immediate(tdbb, attachment, &transaction, 0, sql.c_str(), dialect, + nullptr, nullptr, nullptr, nullptr, false); + } } bool Applier::lookupKey(thread_db* tdbb, jrd_rel* relation, index_desc& key) @@ -1087,7 +1132,7 @@ bool Applier::compareKey(thread_db* tdbb, jrd_rel* relation, const index_desc& i bool Applier::lookupRecord(thread_db* tdbb, jrd_rel* relation, Record* record, - index_desc& idx, const char* idxName) + index_desc& idx, const QualifiedName& idxName) { RecordBitmap::reset(m_bitmap); @@ -1099,7 +1144,7 @@ bool Applier::lookupRecord(thread_db* tdbb, } bool haveIdx = false; - if (idxName) + if (idxName.object.hasData()) { SLONG foundRelId; IndexStatus idxStatus; @@ -1131,62 +1176,7 @@ bool Applier::lookupRecord(thread_db* tdbb, return true; } - NoKeyTable* table = NULL; - - for (size_t i = 0; i < FB_NELEM(NO_KEY_TABLES); i++) - { - const auto tab = &NO_KEY_TABLES[i]; - - if (tab->rel_id == relation->rel_id) - { - table = tab; - break; - } - } - - if (!table) - raiseError("Table %s has no unique key", relation->rel_name.c_str()); - - const auto transaction = tdbb->getTransaction(); - - RLCK_reserve_relation(tdbb, transaction, relation, false); - - record_param rpb; - rpb.rpb_relation = relation; - rpb.rpb_number.setValue(BOF_NUMBER); - - while (VIO_next_record(tdbb, &rpb, transaction, tdbb->getDefaultPool(), DPM_next_all)) - { - const auto seq_record = rpb.rpb_record; - fb_assert(seq_record); - - bool matched = true; - - for (size_t i = 0; i < FB_NELEM(table->rel_fields); i++) - { - const USHORT field_id = table->rel_fields[i]; - - if (field_id == MAX_USHORT) - break; - - dsc desc1, desc2; - - const bool null1 = !EVL_field(relation, record, field_id, &desc1); - const bool null2 = !EVL_field(relation, seq_record, field_id, &desc2); - - if (null1 != null2 || !null1 && MOV_compare(tdbb, &desc1, &desc2)) - { - matched = false; - break; - } - } - - if (matched) - RBM_SET(tdbb->getDefaultPool(), &m_bitmap, rpb.rpb_number.getValue()); - } - - delete rpb.rpb_record; - return false; + raiseError("Table %s has no unique key", relation->rel_name.toQuotedString().c_str()); } const Format* Applier::findFormat(thread_db* tdbb, jrd_rel* relation, ULONG length) @@ -1199,7 +1189,7 @@ const Format* Applier::findFormat(thread_db* tdbb, jrd_rel* relation, ULONG leng if (format->fmt_length != length) { raiseError("Record format with length %u is not found for table %s", - length, relation->rel_name.c_str()); + length, relation->rel_name.toQuotedString().c_str()); } return format; @@ -1255,7 +1245,7 @@ void Applier::doInsert(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) const ULONG num1 = blobId->bid_quad.bid_quad_high; const ULONG num2 = blobId->bid_quad.bid_quad_low; raiseError("Blob %u.%u is not found for table %s", - num1, num2, relation->rel_name.c_str()); + num1, num2, relation->rel_name.toQuotedString().c_str()); } } } @@ -1351,7 +1341,7 @@ void Applier::doUpdate(thread_db* tdbb, record_param* orgRpb, record_param* newR const ULONG num1 = dstBlobId->bid_quad.bid_quad_high; const ULONG num2 = dstBlobId->bid_quad.bid_quad_low; raiseError("Blob %u.%u is not found for table %s", - num1, num2, relation->rel_name.c_str()); + num1, num2, relation->rel_name.toQuotedString().c_str()); } } } diff --git a/src/jrd/replication/Applier.h b/src/jrd/replication/Applier.h index f549ca6e72..86ac5a95e2 100644 --- a/src/jrd/replication/Applier.h +++ b/src/jrd/replication/Applier.h @@ -26,6 +26,7 @@ #include "../common/classes/array.h" #include "../common/classes/GenericMap.h" +#include "../jrd/QualifiedName.h" #include "../jrd/jrd.h" #include "../jrd/tra.h" @@ -165,23 +166,24 @@ namespace Jrd void cleanupSavepoint(thread_db* tdbb, TraNumber traNum, bool undo); void insertRecord(thread_db* tdbb, TraNumber traNum, - const MetaName& relName, + const QualifiedName& relName, ULONG length, const UCHAR* data); void updateRecord(thread_db* tdbb, TraNumber traNum, - const MetaName& relName, + const QualifiedName& relName, ULONG orgLength, const UCHAR* orgData, ULONG newLength, const UCHAR* newData); void deleteRecord(thread_db* tdbb, TraNumber traNum, - const MetaName& relName, + const QualifiedName& relName, ULONG length, const UCHAR* data); - void setSequence(thread_db* tdbb, const MetaName& genName, SINT64 value); + void setSequence(thread_db* tdbb, const QualifiedName& genName, SINT64 value); void storeBlob(thread_db* tdbb, TraNumber traNum, bid* blob_id, ULONG length, const UCHAR* data); void executeSql(thread_db* tdbb, TraNumber traNum, unsigned charset, + const Firebird::string& schemaSearchPath, const Firebird::string& sql, const MetaName& owner); @@ -190,7 +192,7 @@ namespace Jrd const index_desc& idx, Record* record1, Record* record2); bool lookupRecord(thread_db* tdbb, jrd_rel* relation, - Record* record, index_desc& idx, const char* idxName = nullptr); + Record* record, index_desc& idx, const QualifiedName& idxName = {}); const Format* findFormat(thread_db* tdbb, jrd_rel* relation, ULONG length); diff --git a/src/jrd/replication/Config.cpp b/src/jrd/replication/Config.cpp index 5a0257f5b4..0efc1c5dc2 100644 --- a/src/jrd/replication/Config.cpp +++ b/src/jrd/replication/Config.cpp @@ -186,6 +186,8 @@ namespace Config::Config() : dbName(getPool()), bufferSize(DEFAULT_BUFFER_SIZE), + includeSchemaFilter(getPool()), + excludeSchemaFilter(getPool()), includeFilter(getPool()), excludeFilter(getPool()), segmentSize(DEFAULT_SEGMENT_SIZE), @@ -201,6 +203,7 @@ Config::Config() verboseLogging(false), applyIdleTimeout(DEFAULT_APPLY_IDLE_TIMEOUT), applyErrorTimeout(DEFAULT_APPLY_ERROR_TIMEOUT), + schemaSearchPath(getPool()), pluginName(getPool()), logErrors(true), reportErrors(false), @@ -212,6 +215,8 @@ Config::Config() Config::Config(const Config& other) : dbName(getPool(), other.dbName), bufferSize(other.bufferSize), + includeSchemaFilter(getPool(), other.includeSchemaFilter), + excludeSchemaFilter(getPool(), other.excludeSchemaFilter), includeFilter(getPool(), other.includeFilter), excludeFilter(getPool(), other.excludeFilter), segmentSize(other.segmentSize), @@ -227,6 +232,7 @@ Config::Config(const Config& other) verboseLogging(other.verboseLogging), applyIdleTimeout(other.applyIdleTimeout), applyErrorTimeout(other.applyErrorTimeout), + schemaSearchPath(getPool(), other.schemaSearchPath), pluginName(getPool(), other.pluginName), logErrors(other.logErrors), reportErrors(other.reportErrors), @@ -310,6 +316,16 @@ Config* Config::get(const PathName& lookupName) { parseLong(value, config->bufferSize); } + else if (key == "include_schema_filter") + { + ISC_systemToUtf8(value); + config->includeSchemaFilter = value; + } + else if (key == "exclude_schema_filter") + { + ISC_systemToUtf8(value); + config->excludeSchemaFilter = value; + } else if (key == "include_filter") { ISC_systemToUtf8(value); @@ -493,6 +509,8 @@ void Config::enumerate(ReplicaList& replicas) { parseLong(value, config->applyErrorTimeout); } + else if (key == "schema_search_path") + config->schemaSearchPath = value; } if (dbName.hasData() && config->sourceDirectory.hasData()) diff --git a/src/jrd/replication/Config.h b/src/jrd/replication/Config.h index dd157f2821..7a6e4f2ba5 100644 --- a/src/jrd/replication/Config.h +++ b/src/jrd/replication/Config.h @@ -62,6 +62,8 @@ namespace Replication Firebird::PathName dbName; ULONG bufferSize; + Firebird::string includeSchemaFilter; + Firebird::string excludeSchemaFilter; Firebird::string includeFilter; Firebird::string excludeFilter; ULONG segmentSize; @@ -78,6 +80,7 @@ namespace Replication bool verboseLogging; ULONG applyIdleTimeout; ULONG applyErrorTimeout; + Firebird::string schemaSearchPath; Firebird::string pluginName; bool logErrors; bool reportErrors; diff --git a/src/jrd/replication/Manager.cpp b/src/jrd/replication/Manager.cpp index 30dfa339f6..33ff35c047 100644 --- a/src/jrd/replication/Manager.cpp +++ b/src/jrd/replication/Manager.cpp @@ -43,10 +43,28 @@ namespace Replication // Table matcher TableMatcher::TableMatcher(MemoryPool& pool, + const string& includeSchemaFilter, + const string& excludeSchemaFilter, const string& includeFilter, const string& excludeFilter) : m_tables(pool) { + if (includeSchemaFilter.hasData()) + { + m_includeSchemaMatcher.reset(FB_NEW_POOL(pool) SimilarToRegex( + pool, SimilarToFlag::CASE_INSENSITIVE, + includeSchemaFilter.c_str(), includeSchemaFilter.length(), + "\\", 1)); + } + + if (excludeSchemaFilter.hasData()) + { + m_excludeSchemaMatcher.reset(FB_NEW_POOL(pool) SimilarToRegex( + pool, SimilarToFlag::CASE_INSENSITIVE, + excludeSchemaFilter.c_str(), excludeSchemaFilter.length(), + "\\", 1)); + } + if (includeFilter.hasData()) { m_includeMatcher.reset(FB_NEW_POOL(pool) SimilarToRegex( @@ -64,7 +82,7 @@ TableMatcher::TableMatcher(MemoryPool& pool, } } -bool TableMatcher::matchTable(const MetaName& tableName) +bool TableMatcher::matchTable(const QualifiedName& tableName) { try { @@ -73,11 +91,17 @@ bool TableMatcher::matchTable(const MetaName& tableName) { enabled = true; - if (m_includeMatcher) - enabled = m_includeMatcher->matches(tableName.c_str(), tableName.length()); + if (m_includeSchemaMatcher) + enabled = m_includeSchemaMatcher->matches(tableName.schema.c_str(), tableName.schema.length()); + + if (enabled && m_excludeSchemaMatcher) + enabled = !m_excludeSchemaMatcher->matches(tableName.schema.c_str(), tableName.schema.length()); + + if (enabled && m_includeMatcher) + enabled = m_includeMatcher->matches(tableName.object.c_str(), tableName.object.length()); if (enabled && m_excludeMatcher) - enabled = !m_excludeMatcher->matches(tableName.c_str(), tableName.length()); + enabled = !m_excludeMatcher->matches(tableName.object.c_str(), tableName.object.length()); m_tables.put(tableName, enabled); } diff --git a/src/jrd/replication/Manager.h b/src/jrd/replication/Manager.h index d38a3d4883..ed6f6b26e5 100644 --- a/src/jrd/replication/Manager.h +++ b/src/jrd/replication/Manager.h @@ -28,6 +28,7 @@ #include "../common/classes/semaphore.h" #include "../common/SimilarToRegex.h" #include "../common/os/guid.h" +#include "../../jrd/QualifiedName.h" #include "../common/isc_s_proto.h" #include "../../jrd/intl_classes.h" @@ -38,16 +39,20 @@ namespace Replication { class TableMatcher { - typedef Firebird::GenericMap > > TablePermissionMap; + typedef Firebird::GenericMap > > TablePermissionMap; public: TableMatcher(MemoryPool& pool, + const Firebird::string& includeSchemaFilter, + const Firebird::string& excludeSchemaFilter, const Firebird::string& includeFilter, const Firebird::string& excludeFilter); - bool matchTable(const Jrd::MetaName& tableName); + bool matchTable(const Jrd::QualifiedName& tableName); private: + Firebird::AutoPtr m_includeSchemaMatcher; + Firebird::AutoPtr m_excludeSchemaMatcher; Firebird::AutoPtr m_includeMatcher; Firebird::AutoPtr m_excludeMatcher; TablePermissionMap m_tables; diff --git a/src/jrd/replication/Protocol.h b/src/jrd/replication/Protocol.h index 1113a43232..582fee0716 100644 --- a/src/jrd/replication/Protocol.h +++ b/src/jrd/replication/Protocol.h @@ -28,7 +28,8 @@ namespace Replication { // Supported protocol versions const USHORT PROTOCOL_VERSION_1 = 1; - const USHORT PROTOCOL_CURRENT_VERSION = PROTOCOL_VERSION_1; + const USHORT PROTOCOL_VERSION_2 = 2; // support for schemas + const USHORT PROTOCOL_CURRENT_VERSION = PROTOCOL_VERSION_2; // Global (protocol neutral) flags const USHORT BLOCK_BEGIN_TRANS = 0x0001; diff --git a/src/jrd/replication/Publisher.cpp b/src/jrd/replication/Publisher.cpp index dd141d55dc..9669899ca0 100644 --- a/src/jrd/replication/Publisher.cpp +++ b/src/jrd/replication/Publisher.cpp @@ -35,9 +35,9 @@ #include "../jrd/met_proto.h" #include "../jrd/mov_proto.h" #include "../common/isc_proto.h" - #include "Publisher.h" #include "Replicator.h" +#include using namespace Firebird; using namespace Jrd; @@ -403,8 +403,9 @@ void REPL_attach(thread_db* tdbb, bool cleanupTransactions) fb_assert(!attachment->att_repl_matcher); auto& pool = *attachment->att_pool; - attachment->att_repl_matcher = FB_NEW_POOL(pool) - TableMatcher(pool, replConfig->includeFilter, replConfig->excludeFilter); + attachment->att_repl_matcher = FB_NEW_POOL(pool) TableMatcher(pool, + replConfig->includeSchemaFilter, replConfig->excludeSchemaFilter, + replConfig->includeFilter, replConfig->excludeFilter); fb_assert(!attachment->att_replicator); attachment->att_flags |= ATT_replicating; @@ -527,9 +528,10 @@ void REPL_store(thread_db* tdbb, const record_param* rpb, jrd_tra* transaction) ReplicatedRecordImpl replRecord(tdbb, relation, record); - replicator->insertRecord(&status, - relation->rel_name.c_str(), - &replRecord); + replicator->insertRecord2(&status, + relation->rel_name.schema.c_str(), + relation->rel_name.object.c_str(), + &replRecord); checkStatus(tdbb, status, transaction); } @@ -577,9 +579,10 @@ void REPL_modify(thread_db* tdbb, const record_param* orgRpb, ReplicatedRecordImpl replOrgRecord(tdbb, relation, orgRecord); ReplicatedRecordImpl replNewRecord(tdbb, relation, newRecord); - replicator->updateRecord(&status, - relation->rel_name.c_str(), - &replOrgRecord, &replNewRecord); + replicator->updateRecord2(&status, + relation->rel_name.schema.c_str(), + relation->rel_name.object.c_str(), + &replOrgRecord, &replNewRecord); checkStatus(tdbb, status, transaction); } @@ -611,9 +614,10 @@ void REPL_erase(thread_db* tdbb, const record_param* rpb, jrd_tra* transaction) ReplicatedRecordImpl replRecord(tdbb, relation, record); - replicator->deleteRecord(&status, - relation->rel_name.c_str(), - &replRecord); + replicator->deleteRecord2(&status, + relation->rel_name.schema.c_str(), + relation->rel_name.object.c_str(), + &replRecord); checkStatus(tdbb, status, transaction); } @@ -639,24 +643,25 @@ void REPL_gen_id(thread_db* tdbb, SLONG genId, SINT64 value) const auto attachment = tdbb->getAttachment(); - MetaName genName; + QualifiedName genName; if (!attachment->att_generators.lookup(genId, genName)) { MET_lookup_generator_id(tdbb, genId, genName, nullptr); attachment->att_generators.store(genId, genName); } - fb_assert(genName.hasData()); + fb_assert(genName.object.hasData()); AutoSetRestoreFlag noRecursion(&tdbb->tdbb_flags, TDBB_repl_in_progress, true); FbLocalStatus status; - replicator->setSequence(&status, genName.c_str(), value); + replicator->setSequence2(&status, genName.schema.c_str(), genName.object.c_str(), value); checkStatus(tdbb, status); } -void REPL_exec_sql(thread_db* tdbb, jrd_tra* transaction, const string& sql) +void REPL_exec_sql(thread_db* tdbb, jrd_tra* transaction, const string& sql, + const ObjectsArray& schemaSearchPath) { fb_assert(tdbb->tdbb_flags & TDBB_repl_in_progress); @@ -673,7 +678,21 @@ void REPL_exec_sql(thread_db* tdbb, jrd_tra* transaction, const string& sql) // This place is already protected from recursion in calling code - replicator->executeSqlIntl(&status, charset, sql.c_str()); + string schemaSearchPathStr; + + if (schemaSearchPath.hasData()) + { + schemaSearchPathStr = std::accumulate( + std::next(schemaSearchPath.begin()), + schemaSearchPath.end(), + schemaSearchPath[0].toQuotedString(), + [](const auto& a, const auto& b) { + return a + " " + b.toQuotedString(); + } + ); + } + + replicator->executeSqlIntl2(&status, charset, schemaSearchPathStr.c_str(), sql.c_str()); checkStatus(tdbb, status, transaction); } diff --git a/src/jrd/replication/Publisher.h b/src/jrd/replication/Publisher.h index ca9f971457..547d86de6c 100644 --- a/src/jrd/replication/Publisher.h +++ b/src/jrd/replication/Publisher.h @@ -44,7 +44,8 @@ void REPL_modify(Jrd::thread_db* tdbb, const Jrd::record_param* orgRpb, const Jrd::record_param* newRpb, Jrd::jrd_tra* transaction); void REPL_erase(Jrd::thread_db* tdbb, const Jrd::record_param* rpb, Jrd::jrd_tra* transaction); void REPL_gen_id(Jrd::thread_db* tdbb, SLONG genId, SINT64 value); -void REPL_exec_sql(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction, const Firebird::string& sql); +void REPL_exec_sql(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction, const Firebird::string& sql, + const Firebird::ObjectsArray& schemaSearchPath); void REPL_journal_switch(Jrd::thread_db* tdbb); #endif // JRD_REPLICATION_PUBLISHER_H diff --git a/src/jrd/replication/Replicator.cpp b/src/jrd/replication/Replicator.cpp index 09c1004d73..4fb719118e 100644 --- a/src/jrd/replication/Replicator.cpp +++ b/src/jrd/replication/Replicator.cpp @@ -209,12 +209,13 @@ void Replicator::commitTransaction(CheckStatusWrapper* status, Transaction* tran for (const auto& generator : m_generators) { - fb_assert(generator.name.hasData()); + fb_assert(generator.name.object.hasData() && generator.name.schema.hasData()); - const auto atom = txnData.defineAtom(generator.name); + const auto [schemaAtom, objectAtom] = txnData.defineQualifiedAtom(generator.name); txnData.putTag(opSetSequence); - txnData.putInt32(atom); + txnData.putInt32(schemaAtom); + txnData.putInt32(objectAtom); txnData.putInt64(generator.value); } @@ -299,7 +300,8 @@ void Replicator::rollbackSavepoint(CheckStatusWrapper* status, Transaction* tran void Replicator::insertRecord(CheckStatusWrapper* status, Transaction* transaction, - const char* relName, + const char* schemaName, + const char* tableName, IReplicatedRecord* record) { try @@ -325,10 +327,11 @@ void Replicator::insertRecord(CheckStatusWrapper* status, auto& txnData = transaction->getData(); - const auto atom = txnData.defineAtom(relName); + const auto [schemaAtom, objectAtom] = txnData.defineQualifiedAtom(QualifiedMetaString(tableName, schemaName)); txnData.putTag(opInsertRecord); - txnData.putInt32(atom); + txnData.putInt32(schemaAtom); + txnData.putInt32(objectAtom); txnData.putInt32(length); txnData.putBinary(length, data); @@ -343,7 +346,8 @@ void Replicator::insertRecord(CheckStatusWrapper* status, void Replicator::updateRecord(CheckStatusWrapper* status, Transaction* transaction, - const char* relName, + const char* schemaName, + const char* tableName, IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord) { @@ -373,10 +377,11 @@ void Replicator::updateRecord(CheckStatusWrapper* status, auto& txnData = transaction->getData(); - const auto atom = txnData.defineAtom(relName); + const auto [schemaAtom, objectAtom] = txnData.defineQualifiedAtom(QualifiedMetaString(tableName, schemaName)); txnData.putTag(opUpdateRecord); - txnData.putInt32(atom); + txnData.putInt32(schemaAtom); + txnData.putInt32(objectAtom); txnData.putInt32(orgLength); txnData.putBinary(orgLength, orgData); txnData.putInt32(newLength); @@ -393,7 +398,8 @@ void Replicator::updateRecord(CheckStatusWrapper* status, void Replicator::deleteRecord(CheckStatusWrapper* status, Transaction* transaction, - const char* relName, + const char* schemaName, + const char* tableName, IReplicatedRecord* record) { try @@ -403,10 +409,11 @@ void Replicator::deleteRecord(CheckStatusWrapper* status, auto& txnData = transaction->getData(); - const auto atom = txnData.defineAtom(relName); + const auto [schemaAtom, objectAtom] = txnData.defineQualifiedAtom(QualifiedMetaString(tableName, schemaName)); txnData.putTag(opDeleteRecord); - txnData.putInt32(atom); + txnData.putInt32(schemaAtom); + txnData.putInt32(objectAtom); txnData.putInt32(length); txnData.putBinary(length, data); @@ -419,19 +426,22 @@ void Replicator::deleteRecord(CheckStatusWrapper* status, } } -void Replicator::executeSqlIntl(CheckStatusWrapper* status, - Transaction* transaction, - unsigned charset, - const char* sql) +void Replicator::executeSqlIntl2(CheckStatusWrapper* status, + Transaction* transaction, + unsigned charset, + const char* schemaSearchPath, + const char* sql) { try { auto& txnData = transaction->getData(); - const auto atom = txnData.defineAtom(m_user); + const auto userAtom = txnData.defineAtom(m_user); + const auto schemaSearchPathAtom = txnData.defineAtom(schemaSearchPath); txnData.putTag(opExecuteSqlIntl); - txnData.putInt32(atom); + txnData.putInt32(userAtom); + txnData.putInt32(schemaSearchPathAtom); txnData.putByte(charset); txnData.putString(sql); @@ -462,15 +472,18 @@ void Replicator::cleanupTransaction(CheckStatusWrapper* status, } } -void Replicator::setSequence(CheckStatusWrapper* status, - const char* genName, - SINT64 value) +void Replicator::setSequence2(CheckStatusWrapper* status, + const char* schemaName, + const char* genName, + SINT64 value) { try { + const QualifiedName qualifiedName(genName, schemaName); + for (auto& generator : m_generators) { - if (generator.name == genName) + if (generator.name == qualifiedName) { generator.value = value; return; @@ -478,7 +491,7 @@ void Replicator::setSequence(CheckStatusWrapper* status, } GeneratorValue generator; - generator.name = genName; + generator.name = qualifiedName; generator.value = value; m_generators.add(generator); diff --git a/src/jrd/replication/Replicator.h b/src/jrd/replication/Replicator.h index 0cfefe7574..46e440f946 100644 --- a/src/jrd/replication/Replicator.h +++ b/src/jrd/replication/Replicator.h @@ -26,25 +26,27 @@ #include "../common/classes/timestamp.h" #include "../common/classes/MetaString.h" +#include "../common/classes/objects_array.h" +#include "../common/classes/QualifiedMetaString.h" #include "../common/os/guid.h" #include "../jrd/status.h" - #include "Protocol.h" #include "Manager.h" +#include namespace Replication { class Replicator : public Firebird::StdPlugin > { - typedef Firebird::Array MetaNameCache; + typedef Firebird::ObjectsArray NameCache; typedef Firebird::HalfStaticArray SavepointStack; struct BatchBlock { Block header; Firebird::UCharBuffer* buffer; - MetaNameCache atoms; + NameCache atoms; ULONG lastAtom; ULONG flushes; @@ -88,7 +90,8 @@ namespace Replication buffer->add(ptr, sizeof(SINT64)); } - ULONG defineAtom(const Firebird::MetaString& name) + template + ULONG defineAtom(const T& name) { if (lastAtom < atoms.getCount() && atoms[lastAtom] == name) return lastAtom; @@ -106,6 +109,14 @@ namespace Replication return lastAtom; } + std::pair defineQualifiedAtom(const Firebird::QualifiedMetaString& name) + { + const auto schemaAtom = defineAtom(name.schema); + const auto objectAtom = defineAtom(name.object); + + return std::make_pair(schemaAtom, objectAtom); + } + void putMetaName(const Firebird::MetaString& name) { const auto length = name.length(); @@ -186,35 +197,60 @@ namespace Replication m_replicator->rollbackSavepoint(status, this); } - void insertRecord(Firebird::CheckStatusWrapper* status, const char* name, - Firebird::IReplicatedRecord* record) override + void deprecatedInsertRecord(Firebird::CheckStatusWrapper* status, const char* name, + Firebird::IReplicatedRecord* record) override { - m_replicator->insertRecord(status, this, name, record); + insertRecord2(status, nullptr, name, record); } - void updateRecord(Firebird::CheckStatusWrapper* status, const char* name, - Firebird::IReplicatedRecord* orgRecord, + void insertRecord2(Firebird::CheckStatusWrapper* status, const char* schemaName, const char* tableName, + Firebird::IReplicatedRecord* record) override + { + m_replicator->insertRecord(status, this, schemaName, tableName, record); + } + + void deprecatedUpdateRecord(Firebird::CheckStatusWrapper* status, const char* name, + Firebird::IReplicatedRecord* orgRecord, Firebird::IReplicatedRecord* newRecord) override + { + updateRecord2(status, nullptr, name, orgRecord, newRecord); + } + + void updateRecord2(Firebird::CheckStatusWrapper* status, const char* schemaName, const char* tableName, + Firebird::IReplicatedRecord* orgRecord, Firebird::IReplicatedRecord* newRecord) override { - m_replicator->updateRecord(status, this, name, orgRecord, newRecord); + m_replicator->updateRecord(status, this, schemaName, tableName, orgRecord, newRecord); } - void deleteRecord(Firebird::CheckStatusWrapper* status, const char* name, - Firebird::IReplicatedRecord* record) override + void deprecatedDeleteRecord(Firebird::CheckStatusWrapper* status, const char* name, + Firebird::IReplicatedRecord* record) override { - m_replicator->deleteRecord(status, this, name, record); + deleteRecord2(status, nullptr, name, record); } - void executeSql(Firebird::CheckStatusWrapper* status, const char* sql) override + void deleteRecord2(Firebird::CheckStatusWrapper* status, const char* schemaName, const char* tableName, + Firebird::IReplicatedRecord* record) override + { + m_replicator->deleteRecord(status, this, schemaName, tableName, record); + } + + void deprecatedExecuteSql(Firebird::CheckStatusWrapper* status, const char* sql) override { m_replicator->executeSql(status, this, sql); } - void executeSqlIntl(Firebird::CheckStatusWrapper* status, unsigned charset, const char* sql) override + void deprecatedExecuteSqlIntl(Firebird::CheckStatusWrapper* status, unsigned charset, + const char* sql) override { m_replicator->executeSqlIntl(status, this, charset, sql); } + void executeSqlIntl2(Firebird::CheckStatusWrapper* status, unsigned charset, const char* schemaSearchPath, + const char* sql) override + { + m_replicator->executeSqlIntl2(status, this, charset, schemaSearchPath, sql); + } + private: Replicator* const m_replicator; Firebird::RefPtr m_transaction; @@ -223,7 +259,7 @@ namespace Replication struct GeneratorValue { - Jrd::MetaName name; + Jrd::QualifiedName name; SINT64 value; }; @@ -252,7 +288,14 @@ namespace Replication Firebird::IReplicatedTransaction* startTransaction(Firebird::CheckStatusWrapper* status, Firebird::ITransaction* trans, SINT64 number) override; void cleanupTransaction(Firebird::CheckStatusWrapper* status, SINT64 number) override; - void setSequence(Firebird::CheckStatusWrapper* status, const char* name, SINT64 value) override; + + void deprecatedSetSequence(Firebird::CheckStatusWrapper* status, const char* name, SINT64 value) override + { + setSequence2(status, nullptr, name, value); + } + + void setSequence2(Firebird::CheckStatusWrapper* status, const char* schemaName, const char* genName, + SINT64 value) override; private: Manager* const m_manager; @@ -278,25 +321,33 @@ namespace Replication void rollbackSavepoint(Firebird::CheckStatusWrapper* status, Transaction* transaction); void insertRecord(Firebird::CheckStatusWrapper* status, Transaction* transaction, - const char* name, + const char* schemaName, const char* tableName, Firebird::IReplicatedRecord* record); void updateRecord(Firebird::CheckStatusWrapper* status, Transaction* transaction, - const char* name, + const char* schemaName, const char* tableName, Firebird::IReplicatedRecord* orgRecord, Firebird::IReplicatedRecord* newRecord); void deleteRecord(Firebird::CheckStatusWrapper* status, Transaction* transaction, - const char* name, + const char* schemaName, const char* tableName, Firebird::IReplicatedRecord* record); void executeSql(Firebird::CheckStatusWrapper* status, Transaction* transaction, const char* sql) { - executeSqlIntl(status, transaction, CS_UTF8, sql); + executeSqlIntl2(status, transaction, CS_UTF8, "", sql); } void executeSqlIntl(Firebird::CheckStatusWrapper* status, Transaction* transaction, unsigned charset, - const char* sql); + const char* sql) + { + executeSqlIntl2(status, transaction, charset, "", sql); + } + + void executeSqlIntl2(Firebird::CheckStatusWrapper* status, Transaction* transaction, + unsigned charset, + const char* schemaSearchPath, + const char* sql); }; } // namespace diff --git a/src/jrd/replication/Utils.h b/src/jrd/replication/Utils.h index 8aaeeb6fe1..96fc9da180 100644 --- a/src/jrd/replication/Utils.h +++ b/src/jrd/replication/Utils.h @@ -47,7 +47,7 @@ namespace Replication VERBOSE_MSG }; - void raiseError(const char* msg, ...); + [[noreturn]] void raiseError(const char* msg, ...); int executeShell(const Firebird::string& command); void logPrimaryError(const Firebird::PathName& database, diff --git a/src/jrd/rlck.cpp b/src/jrd/rlck.cpp index deb912b524..9fd8411b6d 100644 --- a/src/jrd/rlck.cpp +++ b/src/jrd/rlck.cpp @@ -123,7 +123,7 @@ Lock* RLCK_reserve_relation(thread_db* tdbb, jrd_tra* transaction, jrd_rel* rela if (!result) { string err; - err.printf("Acquire lock for relation (%s) failed", relation->rel_name.c_str()); + err.printf("Acquire lock for relation (%s) failed", relation->rel_name.toQuotedString().c_str()); ERR_append_status(tdbb->tdbb_status_vector, Arg::Gds(isc_random) << Arg::Str(err)); ERR_punt(); diff --git a/src/jrd/scl.epp b/src/jrd/scl.epp index 7b48dd78af..dbe835e81e 100644 --- a/src/jrd/scl.epp +++ b/src/jrd/scl.epp @@ -71,14 +71,14 @@ DATABASE DB = FILENAME "ODS.RDB"; static bool check_number(const UCHAR*, USHORT); static bool check_user_group(thread_db* tdbb, const UCHAR*, USHORT); static bool check_string(const UCHAR*, const MetaName&); -static SecurityClass::flags_t compute_access(thread_db* tdbb, const SecurityClass*, SLONG, const MetaName&); +static SecurityClass::flags_t compute_access(thread_db* tdbb, const SecurityClass*, SLONG, const QualifiedName&); static SecurityClass::flags_t get_sys_privileges(thread_db* tdbb); static SecurityClass::flags_t walk_acl(thread_db* tdbb, const Acl&, const MetaName&, - SLONG, const MetaName&); -static void raiseError(thread_db* tdbb, SecurityClass::flags_t mask, ObjectType type, const MetaName& name, - const MetaName& r_name, const MetaName &invoker); + SLONG, const QualifiedName&); +static void raiseError(thread_db* tdbb, SecurityClass::flags_t mask, ObjectType type, const QualifiedName& name, + const MetaName& col_name, const MetaName& invoker); static bool check_object(thread_db* tdbb, bool found, const SecurityClass* s_class, SLONG obj_type, - const MetaName& obj_name, SecurityClass::flags_t mask, ObjectType type, const MetaName& name); + const QualifiedName& obj_name, SecurityClass::flags_t mask, ObjectType type, const QualifiedName& name); namespace @@ -108,8 +108,8 @@ namespace } // anonymous namespace -static void raiseError(thread_db* tdbb, SecurityClass::flags_t mask, ObjectType type, const MetaName& name, - const MetaName& r_name, const MetaName& invoker) +static void raiseError(thread_db* tdbb, SecurityClass::flags_t mask, ObjectType type, const QualifiedName& name, + const MetaName& col_name, const MetaName& invoker) { const P_NAMES* names; for (names = p_names; names->p_names_priv; names++) @@ -119,8 +119,8 @@ static void raiseError(thread_db* tdbb, SecurityClass::flags_t mask, ObjectType } const char* const ddlObjectName = getDdlObjectName(type); - const Firebird::string fullName = r_name.hasData() ? - r_name.c_str() + Firebird::string(".") + name.c_str() : name.c_str(); + const Firebird::string fullName = col_name.hasData() ? + name.toQuotedString() + "." + col_name.c_str() : name.toQuotedString(); Arg::StatusVector status; status << Arg::Gds(isc_no_priv) << Arg::Str(names->p_names_string) << @@ -135,16 +135,15 @@ static void raiseError(thread_db* tdbb, SecurityClass::flags_t mask, ObjectType } - void SCL_check_access(thread_db* tdbb, const SecurityClass* s_class, SLONG obj_id, - const MetaName& obj_name, + const QualifiedName& obj_name, SecurityClass::flags_t mask, ObjectType type, bool recursive, - const MetaName& name, - const MetaName& r_name) + const QualifiedName& name, + const MetaName& col_name) { /************************************** * @@ -170,7 +169,7 @@ void SCL_check_access(thread_db* tdbb, Arg::StatusVector status; status << Arg::Gds(isc_no_priv) << Arg::Str("(ACL unrecognized)") << Arg::Str("security_class") << - Arg::Str(s_class->sclClassUser.first); + s_class->sclClassUser.first; if (userName.hasData()) { status << Arg::Gds(isc_effective_user) << Arg::Str(userName); @@ -183,13 +182,13 @@ void SCL_check_access(thread_db* tdbb, return; // Check global DDL permissions with ANY option which allow user to make changes non owned objects - if (isDdlObject(type) && (mask & SCL_get_object_mask(type))) + if (isDdlObject(type) && (mask & SCL_get_object_mask(type, name.schema))) return; if (!s_class || (mask & s_class->scl_flags) ) return; - if (obj_name.hasData() && (compute_access(tdbb, s_class, obj_id, obj_name) & mask) ) + if (obj_name.object.hasData() && (compute_access(tdbb, s_class, obj_id, obj_name) & mask) ) { return; } @@ -204,11 +203,11 @@ void SCL_check_access(thread_db* tdbb, return; } - raiseError(tdbb, mask, type, name, r_name, userName); + raiseError(tdbb, mask, type, name, col_name, userName); } -void SCL_check_create_access(thread_db* tdbb, ObjectType type) +void SCL_check_create_access(thread_db* tdbb, ObjectType type, const MetaName& schema) { /************************************** * @@ -232,7 +231,7 @@ void SCL_check_create_access(thread_db* tdbb, ObjectType type) if (attachment->locksmith(tdbb, SystemPrivilege::MODIFY_ANY_OBJECT_IN_DATABASE)) return; - const SecurityClass::flags_t obj_mask = SCL_get_object_mask(type); + const SecurityClass::flags_t obj_mask = SCL_get_object_mask(type, schema); if (!(obj_mask & SCL_create)) { @@ -242,7 +241,7 @@ void SCL_check_create_access(thread_db* tdbb, ObjectType type) } -void SCL_check_charset(thread_db* tdbb, const MetaName& name, SecurityClass::flags_t mask) +void SCL_check_charset(thread_db* tdbb, const QualifiedName& name, SecurityClass::flags_t mask) { /************************************** * @@ -262,7 +261,8 @@ void SCL_check_charset(thread_db* tdbb, const MetaName& name, SecurityClass::fla FOR (REQUEST_HANDLE request) CS IN RDB$CHARACTER_SETS - WITH CS.RDB$CHARACTER_SET_NAME EQ name.c_str() + WITH CS.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + CS.RDB$CHARACTER_SET_NAME EQ name.object.c_str() { if (!CS.RDB$SECURITY_CLASS.NULL) s_class = SCL_get_class(tdbb, CS.RDB$SECURITY_CLASS); @@ -273,7 +273,7 @@ void SCL_check_charset(thread_db* tdbb, const MetaName& name, SecurityClass::fla } -void SCL_check_collation(thread_db* tdbb, const MetaName& name, SecurityClass::flags_t mask) +void SCL_check_collation(thread_db* tdbb, const QualifiedName& name, SecurityClass::flags_t mask) { /************************************** * @@ -293,7 +293,8 @@ void SCL_check_collation(thread_db* tdbb, const MetaName& name, SecurityClass::f FOR (REQUEST_HANDLE request) COLL IN RDB$COLLATIONS - WITH COLL.RDB$COLLATION_NAME EQ name.c_str() + WITH COLL.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + COLL.RDB$COLLATION_NAME EQ name.object.c_str() { if (!COLL.RDB$SECURITY_CLASS.NULL) s_class = SCL_get_class(tdbb, COLL.RDB$SECURITY_CLASS); @@ -342,7 +343,7 @@ void SCL_check_database(thread_db* tdbb, SecurityClass::flags_t mask) } -void SCL_check_domain(thread_db* tdbb, const MetaName& name, SecurityClass::flags_t mask) +void SCL_check_domain(thread_db* tdbb, const QualifiedName& name, SecurityClass::flags_t mask) { /************************************** * @@ -362,7 +363,8 @@ void SCL_check_domain(thread_db* tdbb, const MetaName& name, SecurityClass::flag FOR (REQUEST_HANDLE request) FLD IN RDB$FIELDS - WITH FLD.RDB$FIELD_NAME EQ name.c_str() + WITH FLD.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + FLD.RDB$FIELD_NAME EQ name.object.c_str() { if (!FLD.RDB$SECURITY_CLASS.NULL) s_class = SCL_get_class(tdbb, FLD.RDB$SECURITY_CLASS); @@ -373,7 +375,7 @@ void SCL_check_domain(thread_db* tdbb, const MetaName& name, SecurityClass::flag } -bool SCL_check_exception(thread_db* tdbb, const MetaName& name, SecurityClass::flags_t mask) +bool SCL_check_exception(thread_db* tdbb, const QualifiedName& name, SecurityClass::flags_t mask) { /************************************** * @@ -394,7 +396,8 @@ bool SCL_check_exception(thread_db* tdbb, const MetaName& name, SecurityClass::f FOR (REQUEST_HANDLE request) XCP IN RDB$EXCEPTIONS - WITH XCP.RDB$EXCEPTION_NAME EQ name.c_str() + WITH XCP.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + XCP.RDB$EXCEPTION_NAME EQ name.object.c_str() { if (!XCP.RDB$SECURITY_CLASS.NULL) s_class = SCL_get_class(tdbb, XCP.RDB$SECURITY_CLASS); @@ -406,7 +409,7 @@ bool SCL_check_exception(thread_db* tdbb, const MetaName& name, SecurityClass::f } -bool SCL_check_generator(thread_db* tdbb, const MetaName& name, SecurityClass::flags_t mask) +bool SCL_check_generator(thread_db* tdbb, const QualifiedName& name, SecurityClass::flags_t mask) { /************************************** * @@ -427,7 +430,8 @@ bool SCL_check_generator(thread_db* tdbb, const MetaName& name, SecurityClass::f FOR (REQUEST_HANDLE request) GEN IN RDB$GENERATORS - WITH GEN.RDB$GENERATOR_NAME EQ name.c_str() + WITH GEN.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + GEN.RDB$GENERATOR_NAME EQ name.object.c_str() { if (!GEN.RDB$SECURITY_CLASS.NULL) s_class = SCL_get_class(tdbb, GEN.RDB$SECURITY_CLASS); @@ -439,7 +443,7 @@ bool SCL_check_generator(thread_db* tdbb, const MetaName& name, SecurityClass::f } -void SCL_check_index(thread_db* tdbb, const MetaName& index_name, UCHAR index_id, +void SCL_check_index(thread_db* tdbb, const QualifiedName& index_name, UCHAR index_id, SecurityClass::flags_t mask) { /****************************************************** @@ -467,13 +471,13 @@ void SCL_check_index(thread_db* tdbb, const MetaName& index_name, UCHAR index_id // No security to check for if the index is not yet created - if ((index_name.length() == 0) && (index_id < 1)) { + if ((index_name.object.length() == 0) && (index_id < 1)) { return; } - MetaName reln_name, aux_idx_name; - const MetaName* idx_name_ptr = &index_name; - const MetaName* relation_name_ptr = &index_name; + QualifiedName reln_name, aux_idx_name; + auto idx_name_ptr = &index_name; + const auto relation_name_ptr = &index_name; AutoRequest request; int systemFlag = 0; @@ -483,12 +487,13 @@ void SCL_check_index(thread_db* tdbb, const MetaName& index_name, UCHAR index_id if (index_id < 1) { - FOR(REQUEST_HANDLE request) IND IN RDB$INDICES - CROSS REL IN RDB$RELATIONS - OVER RDB$RELATION_NAME - WITH IND.RDB$INDEX_NAME EQ index_name.c_str() + FOR(REQUEST_HANDLE request) + IND IN RDB$INDICES + CROSS REL IN RDB$RELATIONS OVER RDB$SCHEMA_NAME, RDB$RELATION_NAME + WITH IND.RDB$SCHEMA_NAME EQ index_name.schema.c_str() AND + IND.RDB$INDEX_NAME EQ index_name.object.c_str() { - reln_name = REL.RDB$RELATION_NAME; + reln_name = QualifiedName(REL.RDB$RELATION_NAME, REL.RDB$SCHEMA_NAME); if (!REL.RDB$SECURITY_CLASS.NULL) s_class = SCL_get_class(tdbb, REL.RDB$SECURITY_CLASS); if (!REL.RDB$DEFAULT_CLASS.NULL) @@ -500,14 +505,15 @@ void SCL_check_index(thread_db* tdbb, const MetaName& index_name, UCHAR index_id else { idx_name_ptr = &aux_idx_name; - FOR (REQUEST_HANDLE request) IND IN RDB$INDICES - CROSS REL IN RDB$RELATIONS - OVER RDB$RELATION_NAME - WITH IND.RDB$RELATION_NAME EQ relation_name_ptr->c_str() - AND IND.RDB$INDEX_ID EQ index_id + FOR (REQUEST_HANDLE request) + IND IN RDB$INDICES + CROSS REL IN RDB$RELATIONS OVER RDB$SCHEMA_NAME, RDB$RELATION_NAME + WITH IND.RDB$SCHEMA_NAME EQ relation_name_ptr->schema.c_str() AND + IND.RDB$RELATION_NAME EQ relation_name_ptr->object.c_str() AND + IND.RDB$INDEX_ID EQ index_id { - reln_name = REL.RDB$RELATION_NAME; - aux_idx_name = IND.RDB$INDEX_NAME; + reln_name = QualifiedName(REL.RDB$RELATION_NAME, REL.RDB$SCHEMA_NAME); + aux_idx_name = QualifiedName(IND.RDB$INDEX_NAME, IND.RDB$SCHEMA_NAME); if (!REL.RDB$SECURITY_CLASS.NULL) s_class = SCL_get_class(tdbb, REL.RDB$SECURITY_CLASS); if (!REL.RDB$DEFAULT_CLASS.NULL) @@ -521,16 +527,16 @@ void SCL_check_index(thread_db* tdbb, const MetaName& index_name, UCHAR index_id { // Someone is going to reference system table in FK // Usually it's not good idea - raiseError(tdbb, mask, obj_relations, reln_name, "", NULL); + raiseError(tdbb, mask, obj_relations, reln_name, {}, {}); } // Check if the relation exists. It may not have been created yet. // Just return in that case. - if (reln_name.isEmpty()) + if (reln_name.object.isEmpty()) return; - SCL_check_access(tdbb, s_class, 0, NULL, mask, obj_relations, false, reln_name); + SCL_check_access(tdbb, s_class, 0, {}, mask, obj_relations, false, reln_name); request.reset(); @@ -542,22 +548,23 @@ void SCL_check_index(thread_db* tdbb, const MetaName& index_name, UCHAR index_id // No need to cache this request handle, it's only used when // new constraints are created - FOR(REQUEST_HANDLE request) ISEG IN RDB$INDEX_SEGMENTS - CROSS RF IN RDB$RELATION_FIELDS - OVER RDB$FIELD_NAME - WITH RF.RDB$RELATION_NAME EQ reln_name.c_str() - AND ISEG.RDB$INDEX_NAME EQ idx_name_ptr->c_str() + FOR(REQUEST_HANDLE request) + ISEG IN RDB$INDEX_SEGMENTS + CROSS RF IN RDB$RELATION_FIELDS OVER RDB$SCHEMA_NAME, RDB$FIELD_NAME + WITH RF.RDB$SCHEMA_NAME EQ reln_name.schema.c_str() AND + RF.RDB$RELATION_NAME EQ reln_name.object.c_str() AND + ISEG.RDB$INDEX_NAME EQ idx_name_ptr->object.c_str() { s_class = (!RF.RDB$SECURITY_CLASS.NULL) ? SCL_get_class(tdbb, RF.RDB$SECURITY_CLASS) : default_s_class; - SCL_check_access(tdbb, s_class, 0, NULL, mask, - obj_column, false, RF.RDB$FIELD_NAME, reln_name); + SCL_check_access(tdbb, s_class, 0, {}, mask, + obj_column, false, reln_name, RF.RDB$FIELD_NAME); } END_FOR } -bool SCL_check_package(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flags_t mask) +bool SCL_check_package(thread_db* tdbb, const QualifiedName& name, SecurityClass::flags_t mask) { /************************************** * @@ -574,9 +581,6 @@ bool SCL_check_package(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flag SET_TDBB(tdbb); // Get the name in CSTRING format, ending on NULL or SPACE - fb_assert(dsc_name->dsc_dtype == dtype_text); - const MetaName name(reinterpret_cast(dsc_name->dsc_address), - dsc_name->dsc_length); Jrd::Attachment* const attachment = tdbb->getAttachment(); @@ -586,7 +590,8 @@ bool SCL_check_package(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flag FOR (REQUEST_HANDLE request) PKG IN RDB$PACKAGES - WITH PKG.RDB$PACKAGE_NAME EQ name.c_str() + WITH PKG.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + PKG.RDB$PACKAGE_NAME EQ name.object.c_str() { if (!PKG.RDB$SECURITY_CLASS.NULL) s_class = SCL_get_class(tdbb, PKG.RDB$SECURITY_CLASS); @@ -598,7 +603,7 @@ bool SCL_check_package(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flag } -bool SCL_check_procedure(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flags_t mask) +bool SCL_check_procedure(thread_db* tdbb, const QualifiedName& name, SecurityClass::flags_t mask) { /************************************** * @@ -614,11 +619,6 @@ bool SCL_check_procedure(thread_db* tdbb, const dsc* dsc_name, SecurityClass::fl **************************************/ SET_TDBB(tdbb); - // Get the name in CSTRING format, ending on NULL or SPACE - fb_assert(dsc_name->dsc_dtype == dtype_text); - const MetaName name(reinterpret_cast(dsc_name->dsc_address), - dsc_name->dsc_length); - Jrd::Attachment* const attachment = tdbb->getAttachment(); const SecurityClass* s_class = NULL; @@ -626,12 +626,13 @@ bool SCL_check_procedure(thread_db* tdbb, const dsc* dsc_name, SecurityClass::fl AutoCacheRequest request(tdbb, irq_p_security, IRQ_REQUESTS); FOR (REQUEST_HANDLE request) - SPROC IN RDB$PROCEDURES - WITH SPROC.RDB$PROCEDURE_NAME EQ name.c_str() AND - SPROC.RDB$PACKAGE_NAME MISSING + PRC IN RDB$PROCEDURES + WITH PRC.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + PRC.RDB$PROCEDURE_NAME EQ name.object.c_str() AND + PRC.RDB$PACKAGE_NAME MISSING { - if (!SPROC.RDB$SECURITY_CLASS.NULL) - s_class = SCL_get_class(tdbb, SPROC.RDB$SECURITY_CLASS); + if (!PRC.RDB$SECURITY_CLASS.NULL) + s_class = SCL_get_class(tdbb, PRC.RDB$SECURITY_CLASS); found = true; } END_FOR @@ -640,7 +641,7 @@ bool SCL_check_procedure(thread_db* tdbb, const dsc* dsc_name, SecurityClass::fl } -bool SCL_check_function(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flags_t mask) +bool SCL_check_function(thread_db* tdbb, const QualifiedName& name, SecurityClass::flags_t mask) { /************************************** * @@ -656,11 +657,6 @@ bool SCL_check_function(thread_db* tdbb, const dsc* dsc_name, SecurityClass::fla **************************************/ SET_TDBB(tdbb); - // Get the name in CSTRING format, ending on NULL or SPACE - fb_assert(dsc_name->dsc_dtype == dtype_text); - const MetaName name(reinterpret_cast(dsc_name->dsc_address), - dsc_name->dsc_length); - Jrd::Attachment* const attachment = tdbb->getAttachment(); const SecurityClass* s_class = NULL; @@ -668,12 +664,13 @@ bool SCL_check_function(thread_db* tdbb, const dsc* dsc_name, SecurityClass::fla AutoCacheRequest request(tdbb, irq_f_security, IRQ_REQUESTS); FOR (REQUEST_HANDLE request) - SFUN IN RDB$FUNCTIONS - WITH SFUN.RDB$FUNCTION_NAME EQ name.c_str() AND - SFUN.RDB$PACKAGE_NAME MISSING + FUN IN RDB$FUNCTIONS + WITH FUN.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + FUN.RDB$FUNCTION_NAME EQ name.object.c_str() AND + FUN.RDB$PACKAGE_NAME MISSING { - if (!SFUN.RDB$SECURITY_CLASS.NULL) - s_class = SCL_get_class(tdbb, SFUN.RDB$SECURITY_CLASS); + if (!FUN.RDB$SECURITY_CLASS.NULL) + s_class = SCL_get_class(tdbb, FUN.RDB$SECURITY_CLASS); found = true; } END_FOR @@ -682,7 +679,7 @@ bool SCL_check_function(thread_db* tdbb, const dsc* dsc_name, SecurityClass::fla } -void SCL_check_filter(thread_db* tdbb, const MetaName &name, SecurityClass::flags_t mask) +void SCL_check_filter(thread_db* tdbb, const MetaName& name, SecurityClass::flags_t mask) { /************************************** * @@ -704,19 +701,20 @@ void SCL_check_filter(thread_db* tdbb, const MetaName &name, SecurityClass::flag AutoCacheRequest request(tdbb, irq_f_security, IRQ_REQUESTS); FOR (REQUEST_HANDLE request) - F IN RDB$FILTERS - WITH F.RDB$FUNCTION_NAME EQ name.c_str() + FLT IN RDB$FILTERS + WITH FLT.RDB$FUNCTION_NAME EQ name.c_str() { - if (!F.RDB$SECURITY_CLASS.NULL) - s_class = SCL_get_class(tdbb, F.RDB$SECURITY_CLASS); + if (!FLT.RDB$SECURITY_CLASS.NULL) + s_class = SCL_get_class(tdbb, FLT.RDB$SECURITY_CLASS); } END_FOR - SCL_check_access(tdbb, s_class, id_filter, name, mask, obj_filters, false, name); + SCL_check_access(tdbb, s_class, id_filter, QualifiedName(name), mask, + obj_filters, false, QualifiedName(name)); } -void SCL_check_relation(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flags_t mask, +void SCL_check_relation(thread_db* tdbb, const QualifiedName& name, SecurityClass::flags_t mask, bool protectSys) { /************************************** @@ -733,35 +731,56 @@ void SCL_check_relation(thread_db* tdbb, const dsc* dsc_name, SecurityClass::fla **************************************/ SET_TDBB(tdbb); - // Get the name in CSTRING format, ending on NULL or SPACE - fb_assert(dsc_name->dsc_dtype == dtype_text); - const 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_v_security_r, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) REL IN RDB$RELATIONS - WITH REL.RDB$RELATION_NAME EQ name.c_str() + WITH REL.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + REL.RDB$RELATION_NAME EQ name.object.c_str() { if (protectSys && REL.RDB$SYSTEM_FLAG == 1 && !attachment->isRWGbak()) { // Someone is going to modify system table layout // Usually it's not good idea - raiseError(tdbb, mask, obj_relations, name, "", NULL); + raiseError(tdbb, mask, obj_relations, name, {}, {}); } - if (!REL.RDB$SECURITY_CLASS.NULL) + if (!REL.RDB$SECURITY_CLASS.NULL) s_class = SCL_get_class(tdbb, REL.RDB$SECURITY_CLASS); } END_FOR - SCL_check_access(tdbb, s_class, 0, NULL, mask, obj_relations, false, name); + SCL_check_access(tdbb, s_class, 0, {}, mask, obj_relations, false, name); } -bool SCL_check_view(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flags_t mask) +// Given a schema name, check for a set of privileges. +bool SCL_check_schema(thread_db* tdbb, const MetaName& name, SecurityClass::flags_t mask) +{ + SET_TDBB(tdbb); + + Jrd::Attachment* const attachment = tdbb->getAttachment(); + + const SecurityClass* s_class = nullptr; + bool found = false; + + static const CachedRequestId requestId; + AutoCacheRequest request(tdbb, requestId); + + FOR(REQUEST_HANDLE request) SCH IN RDB$SCHEMAS + WITH SCH.RDB$SCHEMA_NAME EQ name.c_str() + { + if (!SCH.RDB$SECURITY_CLASS.NULL) + s_class = SCL_get_class(tdbb, SCH.RDB$SECURITY_CLASS); + found = true; + } + END_FOR + + return check_object(tdbb, found, s_class, 0, {}, mask, obj_schemas, QualifiedName(name)); +} + +bool SCL_check_view(thread_db* tdbb, const QualifiedName& name, SecurityClass::flags_t mask) { /************************************** * @@ -777,11 +796,6 @@ bool SCL_check_view(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flags_t **************************************/ SET_TDBB(tdbb); - // Get the name in CSTRING format, ending on NULL or SPACE - fb_assert(dsc_name->dsc_dtype == dtype_text); - const MetaName name(reinterpret_cast(dsc_name->dsc_address), - dsc_name->dsc_length); - Jrd::Attachment* const attachment = tdbb->getAttachment(); const SecurityClass* s_class = NULL; @@ -789,7 +803,8 @@ bool SCL_check_view(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flags_t AutoCacheRequest request(tdbb, irq_v_security_v, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) REL IN RDB$RELATIONS - WITH REL.RDB$RELATION_NAME EQ name.c_str() + WITH REL.RDB$SCHEMA_NAME EQ name.schema.c_str() AND + REL.RDB$RELATION_NAME EQ name.object.c_str() { if (!REL.RDB$SECURITY_CLASS.NULL) s_class = SCL_get_class(tdbb, REL.RDB$SECURITY_CLASS); @@ -797,7 +812,7 @@ bool SCL_check_view(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flags_t } END_FOR - return check_object(tdbb, found, s_class, 0, NULL, mask, obj_views, name); + return check_object(tdbb, found, s_class, 0, {}, mask, obj_views, name); } void SCL_check_role(thread_db* tdbb, const MetaName& name, SecurityClass::flags_t mask) @@ -827,10 +842,10 @@ void SCL_check_role(thread_db* tdbb, const MetaName& name, SecurityClass::flags_ } END_FOR - SCL_check_access(tdbb, s_class, 0, NULL, mask, obj_roles, false, name); + SCL_check_access(tdbb, s_class, 0, {}, mask, obj_roles, false, QualifiedName(name)); } -SecurityClass* SCL_get_class(thread_db* tdbb, const TEXT* par_string) +SecurityClass* SCL_get_class(thread_db* tdbb, const MetaName& name) { /************************************** * @@ -845,19 +860,14 @@ SecurityClass* SCL_get_class(thread_db* tdbb, const TEXT* par_string) **************************************/ SET_TDBB(tdbb); - // Name may be absent or terminated with NULL or blank. Clean up name. - - if (!par_string) - return NULL; - - MetaName string(par_string); - if (string.isEmpty()) - return NULL; + // Name may be absent. + if (name.isEmpty()) + return nullptr; Jrd::Attachment* const attachment = tdbb->getAttachment(); const MetaString& userName = attachment->getEffectiveUserName(); - MetaNamePair key(string, userName); + const MetaNamePair key(name, userName); // Look for the class already known SecurityClassList* list = attachment->att_security_classes; @@ -868,8 +878,8 @@ SecurityClass* SCL_get_class(thread_db* tdbb, const TEXT* par_string) MemoryPool& pool = *attachment->att_pool; - SecurityClass* const s_class = FB_NEW_POOL(pool) SecurityClass(pool, string, userName); - s_class->scl_flags = compute_access(tdbb, s_class, 0, NULL); + SecurityClass* const s_class = FB_NEW_POOL(pool) SecurityClass(pool, name, userName); + s_class->scl_flags = compute_access(tdbb, s_class, 0, {}); if (s_class->scl_flags & SCL_exists) { @@ -887,7 +897,7 @@ SecurityClass* SCL_get_class(thread_db* tdbb, const TEXT* par_string) } -SecurityClass::flags_t SCL_get_mask(thread_db* tdbb, const TEXT* relation_name, const TEXT* field_name) +SecurityClass::flags_t SCL_get_mask(thread_db* tdbb, const QualifiedName& relation_name, const TEXT* field_name) { /************************************** * @@ -907,11 +917,11 @@ SecurityClass::flags_t SCL_get_mask(thread_db* tdbb, const TEXT* relation_name, // If there's a relation, track it down jrd_rel* relation; - if (relation_name && (relation = MET_lookup_relation(tdbb, relation_name))) + if (relation_name.object.hasData() && (relation = MET_lookup_relation(tdbb, relation_name))) { MET_scan_relation(tdbb, relation); const SecurityClass* s_class; - if ( (s_class = SCL_get_class(tdbb, relation->rel_security_name.c_str())) ) + if ( (s_class = SCL_get_class(tdbb, relation->rel_security_name.object)) ) { access &= s_class->scl_flags; } @@ -921,7 +931,7 @@ SecurityClass::flags_t SCL_get_mask(thread_db* tdbb, const TEXT* relation_name, if (field_name && (id = MET_lookup_field(tdbb, relation, field_name)) >= 0 && (field = MET_get_field(relation, id)) && - (s_class = SCL_get_class(tdbb, field->fld_security_name.c_str()))) + (s_class = SCL_get_class(tdbb, field->fld_security_name))) { access &= s_class->scl_flags; } @@ -995,20 +1005,20 @@ void UserId::findGrantedRoles(thread_db* tdbb) const MetaName usr_get_role; string usr_get_priv; sql << "with recursive role_tree as ( " - << " select rdb$relation_name as nm, 0 as ur from rdb$user_privileges " + << " select rdb$relation_name as nm, 0 as ur from system.rdb$user_privileges " << " where rdb$privilege = 'M' and rdb$field_name = 'D'" << " and (rdb$user = " << usr_user_name << " or rdb$user = 'PUBLIC')" << " and rdb$user_type = 8 " << " union all " - << " select rdb$role_name as nm, 1 as ur from rdb$roles " + << " select rdb$role_name as nm, 1 as ur from system.rdb$roles " << " where rdb$role_name = " << usr_sql_role_name << " union all " - << " select p.rdb$relation_name as nm, t.ur from rdb$user_privileges p " + << " select p.rdb$relation_name as nm, t.ur from system.rdb$user_privileges p " << " join role_tree t on t.nm = p.rdb$user " << " where p.rdb$privilege = 'M' and (p.rdb$field_name = 'D' or t.ur = 1)) " << "select " << sql("r.rdb$role_name, ", usr_get_role) << sql("r.rdb$system_privileges ", usr_get_priv) - << " from role_tree t join rdb$roles r on t.nm = r.rdb$role_name "; + << " from role_tree t join system.rdb$roles r on t.nm = r.rdb$role_name "; AutoPreparedStatement stmt(attachment->prepareStatement(tdbb, attachment->getSysTransaction(), sql)); AutoResultSet rs(stmt->executeQuery(tdbb, attachment->getSysTransaction())); @@ -1126,7 +1136,8 @@ void UserId::sclInit(thread_db* tdbb, bool create) FOR(REQUEST_HANDLE request2) FIRST 1 REL IN RDB$RELATIONS - WITH REL.RDB$RELATION_NAME EQ "RDB$DATABASE" + WITH REL.RDB$SCHEMA_NAME EQ SYSTEM_SCHEMA AND + REL.RDB$RELATION_NAME EQ "RDB$DATABASE" { if (!REL.RDB$OWNER_NAME.NULL) dbb->dbb_owner = REL.RDB$OWNER_NAME; @@ -1179,7 +1190,7 @@ bool SCL_move_priv(SecurityClass::flags_t mask, Acl& acl) } -void SCL_clear_classes(thread_db* tdbb, const TEXT* string) +void SCL_clear_classes(thread_db* tdbb, const MetaName& name) { /************************************** * @@ -1200,11 +1211,11 @@ void SCL_clear_classes(thread_db* tdbb, const TEXT* string) if (!list) return; - MetaNamePair key(string, NULL); + MetaNamePair key(name, {}); if (!list->locate(Firebird::locGreatEqual, key)) return; - while (list->current()->sclClassUser.first == string) + while (list->current()->sclClassUser.first == name) { delete list->current(); if (!list->fastRemove()) // removing moves current item to the next one @@ -1240,7 +1251,7 @@ void SCL_release_all(SecurityClassList*& list) } -SecurityClass::flags_t SCL_get_object_mask(ObjectType object_type) +SecurityClass::flags_t SCL_get_object_mask(ObjectType object_type, const MetaName& schema) { /************************************** * @@ -1255,13 +1266,14 @@ SecurityClass::flags_t SCL_get_object_mask(ObjectType object_type) thread_db* tdbb = JRD_get_thread_data(); Database* dbb = tdbb->getDatabase(); - const TEXT* object_name = getSecurityClassName(object_type); - if (!*object_name) + const TEXT* className = getSecurityClassName(object_type); + if (!*className) return 0; - const Jrd::SecurityClass* s_class = SCL_get_class(tdbb, object_name); - if (s_class) - return s_class->scl_flags; + const MetaName securityClass(className + (schema.hasData() ? string("$") + schema.c_str() : "")); + + if (const auto* const secClass = SCL_get_class(tdbb, securityClass)) + return secClass->scl_flags; return -1 & ~SCL_corrupt; } @@ -1435,7 +1447,7 @@ static SecurityClass::flags_t get_sys_privileges(thread_db* tdbb) static SecurityClass::flags_t compute_access(thread_db* tdbb, const SecurityClass* s_class, SLONG obj_type, - const MetaName& obj_name) + const QualifiedName& obj_name) { /************************************** * @@ -1499,7 +1511,7 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb, const Acl& acl, const MetaName& userName, SLONG obj_type, - const MetaName& obj_name) + const QualifiedName& obj_name) { /************************************** * @@ -1578,7 +1590,14 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb, case id_procedure: case id_trigger: case id_function: - if (c != obj_type || check_string(a, obj_name)) + if (c != obj_type) + hit = false; + + if (check_string(a, obj_name.schema)) + hit = false; + a += *a + 1; + + if (check_string(a, obj_name.object)) hit = false; break; @@ -1609,6 +1628,7 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb, default: return SCL_corrupt; } + a += *a + 1; } break; @@ -1782,10 +1802,10 @@ static bool check_object(thread_db* tdbb, bool found, const SecurityClass* s_class, SLONG obj_type, - const MetaName& obj_name, + const QualifiedName& obj_name, SecurityClass::flags_t mask, ObjectType type, - const MetaName& name) + const QualifiedName& name) { if (s_class) { diff --git a/src/jrd/scl.h b/src/jrd/scl.h index caaef2f4eb..ff6e0f9d4e 100644 --- a/src/jrd/scl.h +++ b/src/jrd/scl.h @@ -25,6 +25,7 @@ #define JRD_SCL_H #include "../jrd/MetaName.h" +#include "../jrd/QualifiedName.h" #include "../common/classes/tree.h" #include "../common/security.h" #include "../jrd/obj.h" @@ -48,8 +49,8 @@ public: typedef ULONG flags_t; enum BlobAccessCheck { BA_UNKNOWN, BA_SUCCESS, BA_FAILURE }; - SecurityClass(Firebird::MemoryPool &pool, const MetaName& name, const MetaName& userName) - : scl_flags(0), sclClassUser(pool, MetaNamePair(name, userName)), scl_blb_access(BA_UNKNOWN) + SecurityClass(Firebird::MemoryPool& pool, const MetaName& name, const MetaName& userName) + : scl_flags(0), sclClassUser(pool, {name, userName}), scl_blb_access(BA_UNKNOWN) {} flags_t scl_flags; // Access permissions diff --git a/src/jrd/scl_proto.h b/src/jrd/scl_proto.h index ab5fb5429d..a7906c7323 100644 --- a/src/jrd/scl_proto.h +++ b/src/jrd/scl_proto.h @@ -34,30 +34,32 @@ struct dsc; void SCL_check_access(Jrd::thread_db*, const Jrd::SecurityClass*, - SLONG, const Jrd::MetaName&, - Jrd::SecurityClass::flags_t, ObjectType type, bool recursive, const Jrd::MetaName&, - const Jrd::MetaName& = ""); -void SCL_check_create_access(Jrd::thread_db*, ObjectType type); -void SCL_check_charset(Jrd::thread_db* tdbb, const Jrd::MetaName&, Jrd::SecurityClass::flags_t); -void SCL_check_collation(Jrd::thread_db* tdbb, const Jrd::MetaName&, Jrd::SecurityClass::flags_t); + SLONG, const Jrd::QualifiedName&, + Jrd::SecurityClass::flags_t, ObjectType type, bool recursive, const Jrd::QualifiedName&, + const Jrd::MetaName& = {}); +void SCL_check_create_access(Jrd::thread_db*, ObjectType type, const Jrd::MetaName& schema); +void SCL_check_charset(Jrd::thread_db* tdbb, const Jrd::QualifiedName&, Jrd::SecurityClass::flags_t); +void SCL_check_collation(Jrd::thread_db* tdbb, const Jrd::QualifiedName&, Jrd::SecurityClass::flags_t); void SCL_check_database(Jrd::thread_db* tdbb, Jrd::SecurityClass::flags_t mask); -void SCL_check_domain(Jrd::thread_db* tdbb, const Jrd::MetaName&, Jrd::SecurityClass::flags_t); -bool SCL_check_exception(Jrd::thread_db* tdbb, const Jrd::MetaName&, Jrd::SecurityClass::flags_t); -bool SCL_check_generator(Jrd::thread_db* tdbb, const Jrd::MetaName&, Jrd::SecurityClass::flags_t); -void SCL_check_index(Jrd::thread_db*, const Jrd::MetaName&, UCHAR, Jrd::SecurityClass::flags_t); -bool SCL_check_package(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t); -bool SCL_check_procedure(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t); -bool SCL_check_function(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t); -void SCL_check_filter(Jrd::thread_db* tdbb, const Jrd::MetaName &name, Jrd::SecurityClass::flags_t); -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_domain(Jrd::thread_db* tdbb, const Jrd::QualifiedName&, Jrd::SecurityClass::flags_t); +bool SCL_check_exception(Jrd::thread_db* tdbb, const Jrd::QualifiedName&, Jrd::SecurityClass::flags_t); +bool SCL_check_generator(Jrd::thread_db* tdbb, const Jrd::QualifiedName&, Jrd::SecurityClass::flags_t); +void SCL_check_index(Jrd::thread_db*, const Jrd::QualifiedName&, UCHAR, Jrd::SecurityClass::flags_t); +bool SCL_check_package(Jrd::thread_db* tdbb, const Jrd::QualifiedName& name, Jrd::SecurityClass::flags_t); +bool SCL_check_procedure(Jrd::thread_db* tdbb, const Jrd::QualifiedName& name, Jrd::SecurityClass::flags_t); +bool SCL_check_function(Jrd::thread_db* tdbb, const Jrd::QualifiedName& name, Jrd::SecurityClass::flags_t); +void SCL_check_filter(Jrd::thread_db* tdbb, const Jrd::MetaName& name, Jrd::SecurityClass::flags_t); +void SCL_check_relation(Jrd::thread_db* tdbb, const Jrd::QualifiedName& name, Jrd::SecurityClass::flags_t, + bool protectSys = true); +bool SCL_check_schema(Jrd::thread_db* tdbb, const Jrd::MetaName&, Jrd::SecurityClass::flags_t); +bool SCL_check_view(Jrd::thread_db* tdbb, const Jrd::QualifiedName& name, Jrd::SecurityClass::flags_t); void SCL_check_role(Jrd::thread_db* tdbb, const Jrd::MetaName&, 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*); +Jrd::SecurityClass* SCL_get_class(Jrd::thread_db*, const Jrd::MetaName& name); +Jrd::SecurityClass::flags_t SCL_get_mask(Jrd::thread_db* tdbb, const Jrd::QualifiedName&, const TEXT*); +void SCL_clear_classes(Jrd::thread_db*, const Jrd::MetaName&); void SCL_release_all(Jrd::SecurityClassList*&); bool SCL_role_granted(Jrd::thread_db* tdbb, const Jrd::UserId& usr, const TEXT* sql_role); -Jrd::SecurityClass::flags_t SCL_get_object_mask(ObjectType object_type); +Jrd::SecurityClass::flags_t SCL_get_object_mask(ObjectType object_type, const Jrd::MetaName& schema); ULONG SCL_get_number(const UCHAR*); USHORT SCL_convert_privilege(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction, const Firebird::string& priv); diff --git a/src/jrd/svc.cpp b/src/jrd/svc.cpp index 7d0dfdbeb3..f574b185ce 100644 --- a/src/jrd/svc.cpp +++ b/src/jrd/svc.cpp @@ -3139,6 +3139,8 @@ bool Service::process_switches(ClumpletReader& spb, string& switches) } val_database = true; // fall thru + case isc_spb_val_sch_incl: + case isc_spb_val_sch_excl: case isc_spb_val_tab_incl: case isc_spb_val_tab_excl: case isc_spb_val_idx_incl: diff --git a/src/jrd/sys-packages/SqlPackage.cpp b/src/jrd/sys-packages/SqlPackage.cpp index e6ba10635d..14579cd858 100644 --- a/src/jrd/sys-packages/SqlPackage.cpp +++ b/src/jrd/sys-packages/SqlPackage.cpp @@ -105,13 +105,23 @@ SqlPackage::ExplainResultSet::ExplainResultSet(ThrowStatusExceptionWrapper* stat if (planEntry->objectType.has_value()) resultEntry.objectType = planEntry->objectType.value(); - resultEntry.packageNameNull = planEntry->packageName.hasData() ? FB_FALSE : FB_TRUE; - if (planEntry->packageName.hasData()) - resultEntry.packageName.set(planEntry->packageName.c_str(), planEntry->packageName.length()); + resultEntry.schemaNameNull = planEntry->objectName.schema.hasData() ? FB_FALSE : FB_TRUE; + if (planEntry->objectName.schema.hasData()) + { + resultEntry.schemaName.set(planEntry->objectName.schema.c_str(), + planEntry->objectName.schema.length()); + } - resultEntry.objectNameNull = planEntry->objectName.hasData() ? FB_FALSE : FB_TRUE; - if (planEntry->objectName.hasData()) - resultEntry.objectName.set(planEntry->objectName.c_str(), planEntry->objectName.length()); + resultEntry.packageNameNull = planEntry->objectName.package.hasData() ? FB_FALSE : FB_TRUE; + if (planEntry->objectName.package.hasData()) + { + resultEntry.packageName.set(planEntry->objectName.package.c_str(), + planEntry->objectName.package.length()); + } + + resultEntry.objectNameNull = planEntry->objectName.object.hasData() ? FB_FALSE : FB_TRUE; + if (planEntry->objectName.object.hasData()) + resultEntry.objectName.set(planEntry->objectName.object.c_str(), planEntry->objectName.object.length()); resultEntry.aliasNull = planEntry->alias.hasData() ? FB_FALSE : FB_TRUE; if (planEntry->alias.hasData()) @@ -184,6 +194,7 @@ SqlPackage::SqlPackage(MemoryPool& pool) {"PARENT_RECORD_SOURCE_ID", fld_gen_val, true}, {"LEVEL", fld_integer, false}, {"OBJECT_TYPE", fld_obj_type, true}, + {"SCHEMA_NAME", fld_sch_name, true}, {"PACKAGE_NAME", fld_pkg_name, true}, {"OBJECT_NAME", fld_r_name, true}, {"ALIAS", fld_short_description, true}, diff --git a/src/jrd/sys-packages/SqlPackage.h b/src/jrd/sys-packages/SqlPackage.h index 8ee8a685e8..a1dde4e317 100644 --- a/src/jrd/sys-packages/SqlPackage.h +++ b/src/jrd/sys-packages/SqlPackage.h @@ -50,6 +50,7 @@ private: (FB_BIGINT, parentRecordSourceId) (FB_INTEGER, level) (FB_SMALLINT, objectType) + (FB_INTL_VARCHAR(METADATA_IDENTIFIER_CHAR_LEN * METADATA_BYTES_PER_CHAR, CS_METADATA), schemaName) (FB_INTL_VARCHAR(METADATA_IDENTIFIER_CHAR_LEN * METADATA_BYTES_PER_CHAR, CS_METADATA), packageName) (FB_INTL_VARCHAR(METADATA_IDENTIFIER_CHAR_LEN * METADATA_BYTES_PER_CHAR, CS_METADATA), objectName) (FB_INTL_VARCHAR(255 * METADATA_BYTES_PER_CHAR, CS_METADATA), alias) diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index a8149d7988..dc236a590b 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -2194,8 +2194,6 @@ static void expand_view_lock(thread_db* tdbb, jrd_tra* transaction, jrd_rel* rel Arg::Gds(isc_tpb_reserv_max_recursion) << Arg::Num(30)); } - const char* const relation_name = relation->rel_name.c_str(); - // LCK_none < LCK_SR < LCK_PR < LCK_SW < LCK_EX UCHAR oldlock; const bool found = lockmap.get(relation->rel_id, oldlock); @@ -2208,14 +2206,14 @@ static void expand_view_lock(thread_db* tdbb, jrd_tra* transaction, jrd_rel* rel if (level) { lock_type = oldlock; // Preserve the old, more powerful lock. - ERR_post_warning(Arg::Warning(isc_tpb_reserv_stronger_wng) << Arg::Str(relation_name) << + ERR_post_warning(Arg::Warning(isc_tpb_reserv_stronger_wng) << relation->rel_name.toQuotedString() << Arg::Str(oldname) << Arg::Str(newname)); } else { ERR_post(Arg::Gds(isc_bad_tpb_content) << - Arg::Gds(isc_tpb_reserv_stronger) << Arg::Str(relation_name) << + Arg::Gds(isc_tpb_reserv_stronger) << relation->rel_name.toQuotedString() << Arg::Str(oldname) << Arg::Str(newname)); } @@ -2228,14 +2226,14 @@ static void expand_view_lock(thread_db* tdbb, jrd_tra* transaction, jrd_rel* rel if (relation->isVirtual()) { ERR_post(Arg::Gds(isc_bad_tpb_content) << - Arg::Gds(isc_tpb_reserv_virtualtbl) << Arg::Str(relation_name)); + Arg::Gds(isc_tpb_reserv_virtualtbl) << relation->rel_name.toQuotedString()); } // Reject explicit attempts to take locks on system tables. if (relation->isSystem()) { ERR_post(Arg::Gds(isc_bad_tpb_content) << - Arg::Gds(isc_tpb_reserv_systbl) << Arg::Str(relation_name)); + Arg::Gds(isc_tpb_reserv_systbl) << relation->rel_name.toQuotedString()); } if (relation->isTemporary() && (lock_type == LCK_PR || lock_type == LCK_EX)) @@ -2243,7 +2241,7 @@ static void expand_view_lock(thread_db* tdbb, jrd_tra* transaction, jrd_rel* rel ERR_post(Arg::Gds(isc_bad_tpb_content) << Arg::Gds(isc_tpb_reserv_temptbl) << Arg::Str(get_lockname_v3(LCK_PR)) << Arg::Str(get_lockname_v3(LCK_EX)) << - Arg::Str(relation_name)); + relation->rel_name.toQuotedString()); } } else @@ -2287,8 +2285,8 @@ static void expand_view_lock(thread_db* tdbb, jrd_tra* transaction, jrd_rel* rel { // should be a BUGCHECK ERR_post(Arg::Gds(isc_bad_tpb_content) << - Arg::Gds(isc_tpb_reserv_baserelnotfound) << Arg::Str(ctx[i]->vcx_relation_name) << - Arg::Str(relation_name) << + Arg::Gds(isc_tpb_reserv_baserelnotfound) << ctx[i]->vcx_relation_name.toQuotedString() << + relation->rel_name.toQuotedString() << Arg::Str(option_name)); } @@ -3217,14 +3215,14 @@ static void transaction_options(thread_db* tdbb, } const MetaName orgName(reinterpret_cast(tpb), len); - const MetaName metaName = attachment->nameToMetaCharSet(tdbb, orgName); + const QualifiedName relationName(attachment->nameToMetaCharSet(tdbb, orgName)); tpb += len; - jrd_rel* relation = MET_lookup_relation(tdbb, metaName); + jrd_rel* relation = MET_lookup_relation(tdbb, relationName); if (!relation) { ERR_post(Arg::Gds(isc_bad_tpb_content) << - Arg::Gds(isc_tpb_reserv_relnotfound) << Arg::Str(metaName) << + Arg::Gds(isc_tpb_reserv_relnotfound) << relationName.toQuotedString() << Arg::Str(option_name)); } @@ -4092,16 +4090,16 @@ void jrd_tra::checkBlob(thread_db* tdbb, const bid* blob_id, jrd_fld* fld, bool if ((rel_id < vector->count() && (blb_relation = (*vector)[rel_id])) || (blb_relation = MET_relation(tdbb, rel_id))) { - MetaName security_name = (fld && fld->fld_security_name.hasData()) ? - fld->fld_security_name : blb_relation->rel_security_name; + auto security_name = (fld && fld->fld_security_name.hasData()) ? + fld->fld_security_name : blb_relation->rel_security_name.object; if (security_name.isEmpty()) { MET_scan_relation(tdbb, blb_relation); - security_name = blb_relation->rel_security_name; + security_name = blb_relation->rel_security_name.object; } - SecurityClass* s_class = SCL_get_class(tdbb, security_name.c_str()); + SecurityClass* s_class = SCL_get_class(tdbb, security_name); if (!s_class) return; @@ -4114,14 +4112,16 @@ void jrd_tra::checkBlob(thread_db* tdbb, const bid* blob_id, jrd_fld* fld, bool { ThreadStatusGuard status_vector(tdbb); + SCL_check_schema(tdbb, blb_relation->rel_name.schema, SCL_usage); + if (fld) { - SCL_check_access(tdbb, s_class, 0, 0, SCL_select, obj_column, - false, fld->fld_name, blb_relation->rel_name); + SCL_check_access(tdbb, s_class, 0, {}, SCL_select, obj_column, + false, blb_relation->rel_name, fld->fld_name); } else { - SCL_check_access(tdbb, s_class, 0, 0, SCL_select, obj_relations, + SCL_check_access(tdbb, s_class, 0, {}, SCL_select, obj_relations, false, blb_relation->rel_name); } @@ -4152,7 +4152,7 @@ void jrd_tra::checkBlob(thread_db* tdbb, const bid* blob_id, jrd_fld* fld, bool { ERR_post(Arg::Gds(isc_no_priv) << Arg::Str("SELECT") << (fld ? Arg::Str("COLUMN") : Arg::Str("TABLE")) << - (fld ? Arg::Str(fld->fld_name) : Arg::Str(blb_relation->rel_name))); + (Arg::Str(fld ? fld->fld_name.c_str() : blb_relation->rel_name.toQuotedString().c_str()))); } else tra_fetched_blobs.add(*blob_id); @@ -4218,7 +4218,7 @@ void TraceSweepEvent::beginSweepRelation(jrd_rel* relation) if (!m_need_trace) return; - if (relation && relation->rel_name.isEmpty()) + if (relation && relation->rel_name.object.isEmpty()) { // don't accumulate per-relation stats for metadata query below MET_lookup_relation_id(m_tdbb, relation->rel_id, false); diff --git a/src/jrd/tra.h b/src/jrd/tra.h index d42711bcca..8e551b0de5 100644 --- a/src/jrd/tra.h +++ b/src/jrd/tra.h @@ -110,7 +110,7 @@ typedef Firebird::BePlusTree FetchedBlobIdTree; struct CallerName { - CallerName(int aType, const MetaName& aName, const Firebird::MetaString& aUserName) + CallerName(int aType, const QualifiedName& aName, const Firebird::MetaString& aUserName) : type(aType), name(aName), userName(aUserName) @@ -140,7 +140,7 @@ struct CallerName } int type; - MetaName name; + QualifiedName name; Firebird::MetaString userName; }; diff --git a/src/jrd/trace/TraceJrdHelpers.h b/src/jrd/trace/TraceJrdHelpers.h index 3a4614c462..7dee7243a3 100644 --- a/src/jrd/trace/TraceJrdHelpers.h +++ b/src/jrd/trace/TraceJrdHelpers.h @@ -437,8 +437,8 @@ public: if (!m_need_trace) return; - m_name = trigger->name.c_str(); - m_relationName = trigger->relation ? trigger->relation->rel_name.c_str() : ""; + m_name = trigger->name.toQuotedString(); + m_relationName = trigger->relation ? trigger->relation->rel_name.toQuotedString().c_str() : ""; const auto type = (trigger->type & ~TRIGGER_TYPE_MASK); diff --git a/src/jrd/trace/TraceObjects.cpp b/src/jrd/trace/TraceObjects.cpp index dc6bab8889..1036b597a8 100644 --- a/src/jrd/trace/TraceObjects.cpp +++ b/src/jrd/trace/TraceObjects.cpp @@ -635,7 +635,7 @@ TraceRuntimeStats::TraceRuntimeStats(Attachment* att, RuntimeStatistics* baselin m_info.pin_records_fetched = records_fetched; if (baseline && stats) - baseline->computeDifference(att, *stats, m_info, m_counts); + baseline->computeDifference(att, *stats, m_info, m_counts, m_tempNames); else { // Report all zero counts for the moment. diff --git a/src/jrd/trace/TraceObjects.h b/src/jrd/trace/TraceObjects.h index 31c7077848..13e414fd98 100644 --- a/src/jrd/trace/TraceObjects.h +++ b/src/jrd/trace/TraceObjects.h @@ -75,13 +75,13 @@ public: if (m_statement) { if (m_statement->procedure) - return m_statement->procedure->getName().toString(); + return m_statement->procedure->getName().toQuotedString(); if (m_statement->function) - return m_statement->function->getName().toString(); + return m_statement->function->getName().toQuotedString(); - if (m_statement->triggerName.hasData()) - return m_statement->triggerName.c_str(); + if (m_statement->triggerName.object.hasData()) + return m_statement->triggerName.toQuotedString(); } return ""; @@ -580,7 +580,7 @@ public: StatementHolder(request), m_name(getName()), m_relationName((request->req_rpb.hasData() && request->req_rpb[0].rpb_relation) ? - request->req_rpb[0].rpb_relation->rel_name : ""), + request->req_rpb[0].rpb_relation->rel_name.toQuotedString() : ""), m_which(which), m_action(request->req_trigger_action), m_perf(perf) @@ -675,6 +675,7 @@ public: private: Firebird::PerformanceInfo m_info; TraceCountsArray m_counts; + Firebird::ObjectsArray m_tempNames; static SINT64 m_dummy_counts[RuntimeStatistics::TOTAL_ITEMS]; // Zero-initialized array with zero counts }; diff --git a/src/jrd/val.h b/src/jrd/val.h index c0056fa940..13814943f1 100644 --- a/src/jrd/val.h +++ b/src/jrd/val.h @@ -33,7 +33,6 @@ #include "../common/classes/array.h" #include "../jrd/intl_classes.h" #include "../jrd/MetaName.h" -#include "../jrd/QualifiedName.h" #include "../jrd/RecordNumber.h" #include "../common/dsc.h" diff --git a/src/jrd/val_proto.h b/src/jrd/val_proto.h index e7ebe2e02b..2a5352531b 100644 --- a/src/jrd/val_proto.h +++ b/src/jrd/val_proto.h @@ -33,17 +33,19 @@ const int IN_SW_VAL_IDX_INCL = 3; const int IN_SW_VAL_IDX_EXCL = 4; const int IN_SW_VAL_LOCK_TIMEOUT = 5; const int IN_SW_VAL_DATABASE = 6; +const int IN_SW_VAL_SCH_INCL = 7; +const int IN_SW_VAL_SCH_EXCL = 8; static const Switches::in_sw_tab_t val_option_in_sw_table[] = { + {IN_SW_VAL_SCH_INCL, isc_spb_val_sch_incl, "SCH_INCLUDE", 0, 0, 0, false, false, 0, 5, NULL}, + {IN_SW_VAL_SCH_EXCL, isc_spb_val_sch_excl, "SCH_EXCLUDE", 0, 0, 0, false, false, 0, 5, NULL}, {IN_SW_VAL_TAB_INCL, isc_spb_val_tab_incl, "TAB_INCLUDE", 0, 0, 0, false, false, 0, 5, NULL}, {IN_SW_VAL_TAB_EXCL, isc_spb_val_tab_excl, "TAB_EXCLUDE", 0, 0, 0, false, false, 0, 5, NULL}, {IN_SW_VAL_IDX_INCL, isc_spb_val_idx_incl, "IDX_INCLUDE", 0, 0, 0, false, false, 0, 5, NULL}, {IN_SW_VAL_IDX_EXCL, isc_spb_val_idx_excl, "IDX_EXCLUDE", 0, 0, 0, false, false, 0, 5, NULL}, {IN_SW_VAL_LOCK_TIMEOUT, isc_spb_val_lock_timeout, "WAIT", 0, 0, 0, false, false, 0, 1, NULL}, - {IN_SW_VAL_DATABASE, isc_spb_dbname, "DATABASE", 0, 0, 0, false, false, 0, 1, NULL}, - {0, 0, NULL, 0, 0, 0, false, false, 0, 0, NULL} // End of List }; diff --git a/src/jrd/validation.cpp b/src/jrd/validation.cpp index ec0f498177..edd2fe8c9a 100644 --- a/src/jrd/validation.cpp +++ b/src/jrd/validation.cpp @@ -912,6 +912,8 @@ void Validation::parse_args(thread_db* tdbb) switch (sw->in_sw) { + case IN_SW_VAL_SCH_INCL: + case IN_SW_VAL_SCH_EXCL: case IN_SW_VAL_TAB_INCL: case IN_SW_VAL_TAB_EXCL: case IN_SW_VAL_IDX_INCL: @@ -933,6 +935,14 @@ void Validation::parse_args(thread_db* tdbb) switch (sw->in_sw) { + case IN_SW_VAL_SCH_INCL: + vdr_sch_incl = createPatternMatcher(tdbb, *argv); + break; + + case IN_SW_VAL_SCH_EXCL: + vdr_sch_excl = createPatternMatcher(tdbb, *argv); + break; + case IN_SW_VAL_TAB_INCL: vdr_tab_incl = createPatternMatcher(tdbb, *argv); break; @@ -1156,7 +1166,7 @@ Validation::RTN Validation::corrupt(int err_code, const jrd_rel* relation, ...) if (relation) { gds__log("Database: %s\n\t%s in table %s (%d)", - fn, s.c_str(), relation->rel_name.c_str(), relation->rel_id); + fn, s.c_str(), relation->rel_name.toQuotedString().c_str(), relation->rel_id); } else gds__log("Database: %s\n\t%s", fn, s.c_str()); @@ -1648,15 +1658,27 @@ void Validation::walk_database() if ((vdr_flags & VDR_online) && relation->isSystem()) continue; + if (vdr_sch_incl) + { + if (!vdr_sch_incl->matches(relation->rel_name.schema.c_str(), relation->rel_name.schema.length())) + continue; + } + + if (vdr_sch_excl) + { + if (vdr_sch_excl->matches(relation->rel_name.schema.c_str(), relation->rel_name.schema.length())) + continue; + } + if (vdr_tab_incl) { - if (!vdr_tab_incl->matches(relation->rel_name.c_str(), relation->rel_name.length())) + if (!vdr_tab_incl->matches(relation->rel_name.object.c_str(), relation->rel_name.object.length())) continue; } if (vdr_tab_excl) { - if (vdr_tab_excl->matches(relation->rel_name.c_str(), relation->rel_name.length())) + if (vdr_tab_excl->matches(relation->rel_name.object.c_str(), relation->rel_name.object.length())) continue; } @@ -1666,7 +1688,7 @@ void Validation::walk_database() vdr_page_bitmap->clear(); string relName; - relName.printf("Relation %d (%s)", relation->rel_id, relation->rel_name.c_str()); + relName.printf("Relation %d (%s)", relation->rel_id, relation->rel_name.toQuotedString().c_str()); output("%s\n", relName.c_str()); int errs = vdr_errors; @@ -3170,10 +3192,13 @@ Validation::RTN Validation::walk_relation(jrd_rel* relation) { if (!(vdr_flags & VDR_online)) { - const char* msg = relation->rel_name.length() > 0 ? - "bugcheck during scan of table %d (%s)" : - "bugcheck during scan of table %d"; - gds__log(msg, relation->rel_id, relation->rel_name.c_str()); + if (relation->rel_name.object.hasData()) + { + gds__log("bugcheck during scan of table %d (%s)", + relation->rel_id, relation->rel_name.toQuotedString().c_str()); + } + else + gds__log("bugcheck during scan of table %d", relation->rel_id); } #ifdef DEBUG_VAL_VERBOSE if (VAL_debug_level) @@ -3219,21 +3244,23 @@ Validation::RTN Validation::walk_root(jrd_rel* relation, bool getInfo) if (page->irt_rpt[i].getRoot() == 0) continue; - MetaName index; + QualifiedName 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); + // FIXME: schema + if (vdr_idx_incl) { - if (!vdr_idx_incl->matches(index.c_str(), index.length())) + if (!vdr_idx_incl->matches(index.object.c_str(), index.object.length())) continue; } if (vdr_idx_excl) { - if (vdr_idx_excl->matches(index.c_str(), index.length())) + if (vdr_idx_excl->matches(index.object.c_str(), index.object.length())) continue; } @@ -3251,7 +3278,7 @@ Validation::RTN Validation::walk_root(jrd_rel* relation, bool getInfo) continue; } - output("Index %d (%s)\n", i + 1, index.c_str()); + output("Index %d (%s)\n", i + 1, index.toQuotedString().c_str()); walk_index(relation, *page, i); } diff --git a/src/jrd/validation.h b/src/jrd/validation.h index 971e061794..dc2c988d53 100644 --- a/src/jrd/validation.h +++ b/src/jrd/validation.h @@ -162,6 +162,8 @@ private: ULONG vdr_err_counts[VAL_MAX_ERROR]; Firebird::UtilSvc* vdr_service; + Firebird::AutoPtr vdr_sch_incl; + Firebird::AutoPtr vdr_sch_excl; Firebird::AutoPtr vdr_tab_incl; Firebird::AutoPtr vdr_tab_excl; Firebird::AutoPtr vdr_idx_incl; diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index 3d23566bbc..4e8bab9e3e 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -42,6 +42,7 @@ */ #include "firebird.h" +#include #include #include #include "../jrd/jrd.h" @@ -441,7 +442,7 @@ bool SweepTask::handler(WorkItem& _item) if (!gcGuard.gcEnabled()) { string str; - str.printf("Acquire garbage collection lock failed (%s)", relation->rel_name.c_str()); + str.printf("Acquire garbage collection lock failed (%s)", relation->rel_name.toQuotedString().c_str()); status_exception::raise(Arg::Gds(isc_random) << Arg::Str(str)); } @@ -656,7 +657,7 @@ inline void check_gbak_cheating_insupd(thread_db* tdbb, const jrd_rel* relation, !request->hasInternalStatement()) { status_exception::raise(Arg::Gds(isc_protect_sys_tab) << - Arg::Str(op) << Arg::Str(relation->rel_name)); + Arg::Str(op) << relation->rel_name.toQuotedString()); } } @@ -1963,7 +1964,7 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) * stub. * **************************************/ - MetaName object_name, package_name; + QualifiedName object_name; SET_TDBB(tdbb); Request* request = tdbb->getRequest(); @@ -2010,7 +2011,7 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) // If we're about to erase a system relation, check to make sure // everything is completely kosher. - DSC desc, desc2; + DSC desc, desc2, schemaDesc; if (needDfw(tdbb, transaction)) { @@ -2070,7 +2071,8 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) IBERROR(187); // msg 187 cannot delete system relations } EVL_field(0, rpb->rpb_record, f_rel_name, &desc); - DFW_post_work(transaction, dfw_delete_relation, &desc, id); + EVL_field(0, rpb->rpb_record, f_rel_schema, &schemaDesc); + DFW_post_work(transaction, dfw_delete_relation, &desc, &schemaDesc, id); jrd_rel* rel_drop = MET_lookup_relation_id(tdbb, id, false); if (rel_drop) MET_scan_relation(tdbb, rel_drop); @@ -2083,16 +2085,20 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) id = MOV_get_long(tdbb, &desc2, 0); if (EVL_field(0, rpb->rpb_record, f_prc_pkg_name, &desc2)) - MOV_get_metaname(tdbb, &desc2, package_name); + MOV_get_metaname(tdbb, &desc2, object_name.package); + EVL_field(0, rpb->rpb_record, f_prc_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_prc_name, &desc); - DFW_post_work(transaction, dfw_delete_procedure, &desc, id, package_name); + DFW_post_work(transaction, dfw_delete_procedure, &desc, &schemaDesc, id, object_name.package); MET_lookup_procedure_id(tdbb, id, false, true, 0); break; case rel_collations: protect_system_table_delupd(tdbb, relation, "DELETE"); + + EVL_field(0, rpb->rpb_record, f_coll_schema, &schemaDesc); + EVL_field(0, rpb->rpb_record, f_coll_cs_id, &desc2); id = MOV_get_long(tdbb, &desc2, 0); @@ -2100,32 +2106,36 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) id = INTL_CS_COLL_TO_TTYPE(id, MOV_get_long(tdbb, &desc2, 0)); EVL_field(0, rpb->rpb_record, f_coll_name, &desc); - DFW_post_work(transaction, dfw_delete_collation, &desc, id); + DFW_post_work(transaction, dfw_delete_collation, &desc, &schemaDesc, id); break; case rel_exceptions: protect_system_table_delupd(tdbb, relation, "DELETE"); + EVL_field(0, rpb->rpb_record, f_xcp_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_xcp_name, &desc); - DFW_post_work(transaction, dfw_delete_exception, &desc, 0); + DFW_post_work(transaction, dfw_delete_exception, &desc, &schemaDesc, 0); break; case rel_gens: protect_system_table_delupd(tdbb, relation, "DELETE"); + EVL_field(0, rpb->rpb_record, f_gen_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_gen_name, &desc); - DFW_post_work(transaction, dfw_delete_generator, &desc, 0); + DFW_post_work(transaction, dfw_delete_generator, &desc, &schemaDesc, 0); break; case rel_funs: protect_system_table_delupd(tdbb, relation, "DELETE"); + + EVL_field(0, rpb->rpb_record, f_fun_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_fun_name, &desc); if (EVL_field(0, rpb->rpb_record, f_fun_pkg_name, &desc2)) - MOV_get_metaname(tdbb, &desc2, package_name); + MOV_get_metaname(tdbb, &desc2, object_name.package); EVL_field(0, rpb->rpb_record, f_fun_id, &desc2); id = MOV_get_long(tdbb, &desc2, 0); - DFW_post_work(transaction, dfw_delete_function, &desc, id, package_name); + DFW_post_work(transaction, dfw_delete_function, &desc, &schemaDesc, id, object_name.package); Function::lookup(tdbb, id, false, true, 0); break; @@ -2135,8 +2145,12 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) EVL_field(0, rpb->rpb_record, f_idx_id, &desc2); if ( (id = MOV_get_long(tdbb, &desc2, 0)) ) { - MetaName relation_name; - MOV_get_metaname(tdbb, &desc, relation_name); + QualifiedName relation_name; + + EVL_field(0, rpb->rpb_record, f_idx_schema, &schemaDesc); + MOV_get_metaname(tdbb, &schemaDesc, relation_name.schema); + + MOV_get_metaname(tdbb, &desc, relation_name.object); r2 = MET_lookup_relation(tdbb, relation_name); fb_assert(r2); @@ -2146,10 +2160,10 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) // hvlad: lets add index name to the DFW item even if we add it again later within // additional argument. This is needed to make DFW work items different for different // indexes dropped at the same transaction and to not merge them at DFW_merge_work. - work = DFW_post_work(transaction, dfw_delete_index, &idx_name, r2->rel_id); + work = DFW_post_work(transaction, dfw_delete_index, &idx_name, &schemaDesc, r2->rel_id); // add index id and name (the latter is required to delete dependencies correctly) - DFW_post_work_arg(transaction, work, &idx_name, id, dfw_arg_index_name); + DFW_post_work_arg(transaction, work, &idx_name, &schemaDesc, id, dfw_arg_index_name); // get partner relation for FK index if (EVL_field(0, rpb->rpb_record, f_idx_foreign, &desc2)) @@ -2157,17 +2171,18 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) DSC desc3; EVL_field(0, rpb->rpb_record, f_idx_name, &desc3); - MetaName index_name; - MOV_get_metaname(tdbb, &desc3, index_name); + QualifiedName index_name; + MOV_get_metaname(tdbb, &schemaDesc, index_name.schema); + MOV_get_metaname(tdbb, &desc3, index_name.object); - jrd_rel *partner; + jrd_rel* partner; index_desc idx; if ((BTR_lookup(tdbb, r2, id - 1, &idx, r2->getBasePages())) && - MET_lookup_partner(tdbb, r2, &idx, index_name.nullStr()) && + MET_lookup_partner(tdbb, r2, &idx, index_name) && (partner = MET_lookup_relation_id(tdbb, idx.idx_primary_relation, false)) ) { - DFW_post_work_arg(transaction, work, 0, partner->rel_id, + DFW_post_work_arg(transaction, work, nullptr, nullptr, partner->rel_id, dfw_arg_partner_rel_id); } else @@ -2175,7 +2190,7 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) // can't find partner relation - impossible ? // add empty argument to let DFW know dropping // index was bound with FK - DFW_post_work_arg(transaction, work, 0, 0, dfw_arg_partner_rel_id); + DFW_post_work_arg(transaction, work, nullptr, nullptr, 0, dfw_arg_partner_rel_id); } } } @@ -2184,57 +2199,67 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_rfr: protect_system_table_delupd(tdbb, relation, "DELETE"); + EVL_field(0, rpb->rpb_record, f_rfr_schema, &schemaDesc); + MOV_get_metaname(tdbb, &schemaDesc, object_name.schema); + EVL_field(0, rpb->rpb_record, f_rfr_rname, &desc); - DFW_post_work(transaction, dfw_update_format, &desc, 0); + DFW_post_work(transaction, dfw_update_format, &desc, &schemaDesc, 0); EVL_field(0, rpb->rpb_record, f_rfr_fname, &desc2); - MOV_get_metaname(tdbb, &desc, object_name); + MOV_get_metaname(tdbb, &desc, object_name.object); + if ( (r2 = MET_lookup_relation(tdbb, object_name)) ) - DFW_post_work(transaction, dfw_delete_rfr, &desc2, r2->rel_id); + DFW_post_work(transaction, dfw_delete_rfr, &desc2, &schemaDesc, r2->rel_id); + + EVL_field(0, rpb->rpb_record, f_rfr_field_source_schema, &schemaDesc); + MOV_get_metaname(tdbb, &schemaDesc, object_name.schema); EVL_field(0, rpb->rpb_record, f_rfr_sname, &desc2); - MOV_get_metaname(tdbb, &desc2, object_name); + MOV_get_metaname(tdbb, &desc2, object_name.object); - if (fb_utils::implicit_domain(object_name.c_str())) - DFW_post_work(transaction, dfw_delete_global, &desc2, 0); + if (fb_utils::implicit_domain(object_name.object.c_str())) + DFW_post_work(transaction, dfw_delete_global, &desc2, &schemaDesc, 0); break; case rel_prc_prms: protect_system_table_delupd(tdbb, relation, "DELETE"); + + EVL_field(0, rpb->rpb_record, f_prm_schema, &schemaDesc); + MOV_get_metaname(tdbb, &schemaDesc, object_name.schema); + EVL_field(0, rpb->rpb_record, f_prm_procedure, &desc); - MOV_get_metaname(tdbb, &desc, object_name); + MOV_get_metaname(tdbb, &desc, object_name.object); if (EVL_field(0, rpb->rpb_record, f_prm_pkg_name, &desc2)) - { - MOV_get_metaname(tdbb, &desc2, package_name); - } + MOV_get_metaname(tdbb, &desc2, object_name.package); EVL_field(0, rpb->rpb_record, f_prm_name, &desc2); - if ( (procedure = MET_lookup_procedure(tdbb, - QualifiedName(object_name, package_name), true)) ) + if ((procedure = MET_lookup_procedure(tdbb, object_name, true))) { - work = DFW_post_work(transaction, dfw_delete_prm, &desc2, procedure->getId(), - package_name); + work = DFW_post_work(transaction, dfw_delete_prm, &desc2, &schemaDesc, procedure->getId(), + object_name.package); // procedure name to track parameter dependencies - DFW_post_work_arg(transaction, work, &desc, procedure->getId(), dfw_arg_proc_name); + DFW_post_work_arg(transaction, work, &desc, &schemaDesc, procedure->getId(), dfw_arg_proc_name); } if (!EVL_field(0, rpb->rpb_record, f_prm_fname, &desc2)) { + EVL_field(0, rpb->rpb_record, f_prm_field_source_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_prm_sname, &desc2); - DFW_post_work(transaction, dfw_delete_global, &desc2, 0); + DFW_post_work(transaction, dfw_delete_global, &desc2, &schemaDesc, 0); } break; case rel_fields: protect_system_table_delupd(tdbb, relation, "DELETE"); + EVL_field(0, rpb->rpb_record, f_fld_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_fld_name, &desc); - DFW_post_work(transaction, dfw_delete_field, &desc, 0); - MET_change_fields(tdbb, transaction, &desc); + DFW_post_work(transaction, dfw_delete_field, &desc, &schemaDesc, 0); + MET_change_fields(tdbb, transaction, &schemaDesc, &desc); break; case rel_files: @@ -2255,16 +2280,16 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) const auto work = (fileFlags & FILE_nodelete) ? dfw_delete_shadow_nodelete : dfw_delete_shadow; - DFW_post_work(transaction, work, &desc, shadowNumber); + DFW_post_work(transaction, work, &desc, nullptr, shadowNumber); } } else if (fileFlags & FILE_difference) { if (fileFlags & FILE_backing_up) - DFW_post_work(transaction, dfw_end_backup, &desc, 0); + DFW_post_work(transaction, dfw_end_backup, &desc, nullptr, 0); if (nameDefined) - DFW_post_work(transaction, dfw_delete_difference, &desc, 0); + DFW_post_work(transaction, dfw_delete_difference, &desc, nullptr, 0); } } break; @@ -2272,22 +2297,23 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_classes: protect_system_table_delupd(tdbb, relation, "DELETE"); EVL_field(0, rpb->rpb_record, f_cls_class, &desc); - DFW_post_work(transaction, dfw_compute_security, &desc, 0); + DFW_post_work(transaction, dfw_compute_security, &desc, nullptr, 0); break; case rel_triggers: protect_system_table_delupd(tdbb, relation, "DELETE"); + EVL_field(0, rpb->rpb_record, f_trg_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_trg_rname, &desc2); - DFW_post_work(transaction, dfw_update_format, &desc2, 0); + DFW_post_work(transaction, dfw_update_format, &desc2, &schemaDesc, 0); EVL_field(0, rpb->rpb_record, f_trg_name, &desc); - work = DFW_post_work(transaction, dfw_delete_trigger, &desc, 0); + work = DFW_post_work(transaction, dfw_delete_trigger, &desc, &schemaDesc, 0); if (!(desc2.dsc_flags & DSC_null)) - DFW_post_work_arg(transaction, work, &desc2, 0, dfw_arg_rel_name); + DFW_post_work_arg(transaction, work, &desc2, &schemaDesc, 0, dfw_arg_rel_name); if (EVL_field(0, rpb->rpb_record, f_trg_type, &desc2)) { - DFW_post_work_arg(transaction, work, &desc2, + DFW_post_work_arg(transaction, work, &desc2, &schemaDesc, (USHORT) MOV_get_int64(tdbb, &desc2, 0), dfw_arg_trg_type); } @@ -2315,7 +2341,11 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) EVL_field(0, rpb->rpb_record, f_prv_rname, &desc); EVL_field(0, rpb->rpb_record, f_prv_o_type, &desc2); id = MOV_get_long(tdbb, &desc2, 0); - DFW_post_work(transaction, dfw_grant, &desc, id); + + if (EVL_field(0, rpb->rpb_record, f_prv_rel_schema, &schemaDesc)) + DFW_post_work(transaction, dfw_grant, &desc, &schemaDesc, id); + else + DFW_post_work(transaction, dfw_grant, &desc, nullptr, id); break; case rel_rcon: @@ -2323,15 +2353,21 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) // ensure relation partners is known EVL_field(0, rpb->rpb_record, f_rcon_rname, &desc); + { - MetaName relation_name; - MOV_get_metaname(tdbb, &desc, relation_name); + QualifiedName relation_name; + + EVL_field(0, rpb->rpb_record, f_rcon_schema, &schemaDesc); + MOV_get_metaname(tdbb, &schemaDesc, relation_name.schema); + + MOV_get_metaname(tdbb, &desc, relation_name.object); r2 = MET_lookup_relation(tdbb, relation_name); fb_assert(r2); if (r2) MET_scan_partners(tdbb, r2); } + break; case rel_backup_history: @@ -2341,7 +2377,7 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_pub_tables: protect_system_table_delupd(tdbb, relation, "DELETE"); - DFW_post_work(transaction, dfw_change_repl_state, "", 1); + DFW_post_work(transaction, dfw_change_repl_state, {}, {}, 1); break; default: // Shut up compiler warnings @@ -2421,16 +2457,27 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) if ((RIDS) relation->rel_id == rel_priv) { + if (EVL_field(0, rpb->rpb_record, f_prv_rel_schema, &desc)) + MOV_get_metaname(tdbb, &desc, object_name.schema); + EVL_field(0, rpb->rpb_record, f_prv_rname, &desc); - MOV_get_metaname(tdbb, &desc, object_name); + MOV_get_metaname(tdbb, &desc, object_name.object); + EVL_field(0, rpb->rpb_record, f_prv_grant, &desc2); + if (MOV_get_long(tdbb, &desc2, 0) == WITH_GRANT_OPTION) // ADMIN option should not cause cascade { + QualifiedName revokee; + + if (EVL_field(0, rpb->rpb_record, f_prv_user_schema, &desc2)) + MOV_get_metaname(tdbb, &desc2, revokee.schema); + EVL_field(0, rpb->rpb_record, f_prv_user, &desc2); - MetaName revokee; - MOV_get_metaname(tdbb, &desc2, revokee); + MOV_get_metaname(tdbb, &desc2, revokee.object); + EVL_field(0, rpb->rpb_record, f_prv_priv, &desc2); const string privilege = MOV_make_string2(tdbb, &desc2, ttype_ascii); + MET_revoke(tdbb, transaction, object_name, revokee, privilege); } } @@ -3289,7 +3336,7 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j **************************************/ SET_TDBB(tdbb); - MetaName object_name, package_name; + QualifiedName object_name; jrd_rel* relation = org_rpb->rpb_relation; #ifdef VIO_DEBUG @@ -3349,7 +3396,7 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j // If we're about to modify a system relation, check to make sure // everything is completely kosher. - DSC desc1, desc2; + DSC desc1, desc2, schemaDesc; if (needDfw(tdbb, transaction)) { @@ -3404,46 +3451,64 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j if (!EVL_field(0, new_rpb->rpb_record, f_dat_linger, &desc2)) desc2.makeLong(0, const_cast(&nullLinger)); if (MOV_compare(tdbb, &desc1, &desc2)) - DFW_post_work(transaction, dfw_set_linger, &desc2, 0); + DFW_post_work(transaction, dfw_set_linger, &desc2, nullptr, 0); break; case rel_relations: + EVL_field(0, org_rpb->rpb_record, f_rel_schema, &schemaDesc); EVL_field(0, org_rpb->rpb_record, f_rel_name, &desc1); if (!check_nullify_source(tdbb, org_rpb, new_rpb, f_rel_source)) protect_system_table_delupd(tdbb, relation, "UPDATE"); else - SCL_check_relation(tdbb, &desc1, SCL_alter); + { + MOV_get_metaname(tdbb, &schemaDesc, object_name.schema); + MOV_get_metaname(tdbb, &desc1, object_name.object); + SCL_check_relation(tdbb, object_name, SCL_alter); + } check_class(tdbb, transaction, org_rpb, new_rpb, f_rel_class); check_owner(tdbb, transaction, org_rpb, new_rpb, f_rel_owner); - DFW_post_work(transaction, dfw_update_format, &desc1, 0); + DFW_post_work(transaction, dfw_update_format, &desc1, &schemaDesc, 0); break; case rel_packages: + EVL_field(0, org_rpb->rpb_record, f_pkg_schema, &schemaDesc); if (!check_nullify_source(tdbb, org_rpb, new_rpb, f_pkg_header_source, f_pkg_body_source)) protect_system_table_delupd(tdbb, relation, "UPDATE"); else { if (EVL_field(0, org_rpb->rpb_record, f_pkg_name, &desc1)) - SCL_check_package(tdbb, &desc1, SCL_alter); + { + MOV_get_metaname(tdbb, &schemaDesc, object_name.schema); + MOV_get_metaname(tdbb, &desc1, object_name.object); + SCL_check_package(tdbb, object_name, SCL_alter); + } } check_class(tdbb, transaction, org_rpb, new_rpb, f_pkg_class); check_owner(tdbb, transaction, org_rpb, new_rpb, f_pkg_owner); break; case rel_procedures: + EVL_field(0, org_rpb->rpb_record, f_prc_schema, &schemaDesc); EVL_field(0, org_rpb->rpb_record, f_prc_name, &desc1); if (EVL_field(0, org_rpb->rpb_record, f_prc_pkg_name, &desc2)) - MOV_get_metaname(tdbb, &desc2, package_name); + MOV_get_metaname(tdbb, &desc2, object_name.package); if (!check_nullify_source(tdbb, org_rpb, new_rpb, f_prc_source)) protect_system_table_delupd(tdbb, relation, "UPDATE"); else { - if (package_name.hasData()) - SCL_check_package(tdbb, &desc2, SCL_alter); + if (object_name.package.hasData()) + { + QualifiedName package(object_name.package, object_name.schema); + SCL_check_package(tdbb, package, SCL_alter); + } else - SCL_check_procedure(tdbb, &desc1, SCL_alter); + { + MOV_get_metaname(tdbb, &schemaDesc, object_name.schema); + MOV_get_metaname(tdbb, &desc1, object_name.object); + SCL_check_procedure(tdbb, object_name, SCL_alter); + } } check_class(tdbb, transaction, org_rpb, new_rpb, f_prc_class); @@ -3453,24 +3518,33 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j { EVL_field(0, org_rpb->rpb_record, f_prc_id, &desc2); const USHORT id = MOV_get_long(tdbb, &desc2, 0); - DFW_post_work(transaction, dfw_modify_procedure, &desc1, id, package_name); + DFW_post_work(transaction, dfw_modify_procedure, &desc1, &schemaDesc, id, object_name.package); } break; case rel_funs: + EVL_field(0, org_rpb->rpb_record, f_fun_schema, &schemaDesc); EVL_field(0, org_rpb->rpb_record, f_fun_name, &desc1); if (EVL_field(0, org_rpb->rpb_record, f_fun_pkg_name, &desc2)) - MOV_get_metaname(tdbb, &desc2, package_name); + MOV_get_metaname(tdbb, &desc2, object_name.package); if (!check_nullify_source(tdbb, org_rpb, new_rpb, f_fun_source)) protect_system_table_delupd(tdbb, relation, "UPDATE"); else { - if (package_name.hasData()) - SCL_check_package(tdbb, &desc2, SCL_alter); + if (object_name.package.hasData()) + { + QualifiedName package(object_name.package, object_name.schema); + SCL_check_package(tdbb, package, SCL_alter); + SCL_check_package(tdbb, package, SCL_alter); + } else - SCL_check_function(tdbb, &desc1, SCL_alter); + { + MOV_get_metaname(tdbb, &schemaDesc, object_name.schema); + MOV_get_metaname(tdbb, &desc1, object_name.object); + SCL_check_function(tdbb, object_name, SCL_alter); + } } check_class(tdbb, transaction, org_rpb, new_rpb, f_fun_class); @@ -3480,7 +3554,7 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j { EVL_field(0, org_rpb->rpb_record, f_fun_id, &desc2); const USHORT id = MOV_get_long(tdbb, &desc2, 0); - DFW_post_work(transaction, dfw_modify_function, &desc1, id, package_name); + DFW_post_work(transaction, dfw_modify_function, &desc1, &schemaDesc, id, object_name.package); } break; @@ -3509,10 +3583,11 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j if ((rc2 && MOV_get_long(tdbb, &desc2, 0) != 0) || (rc3 && rc4 && MOV_compare(tdbb, &desc3, &desc4))) { + EVL_field(0, new_rpb->rpb_record, f_rfr_schema, &schemaDesc); EVL_field(0, new_rpb->rpb_record, f_rfr_rname, &desc1); EVL_field(0, new_rpb->rpb_record, f_rfr_id, &desc2); - DeferredWork* work = DFW_post_work(transaction, dfw_check_not_null, &desc1, 0); + DeferredWork* work = DFW_post_work(transaction, dfw_check_not_null, &desc1, &schemaDesc, 0); SortedArray& ids = DFW_get_ids(work); int id = MOV_get_long(tdbb, &desc2, 0); @@ -3530,9 +3605,11 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j if (dfw_should_know(tdbb, org_rpb, new_rpb, f_fld_desc, true)) { - MET_change_fields(tdbb, transaction, &desc1); + EVL_field(0, org_rpb->rpb_record, f_fld_schema, &schemaDesc); + + MET_change_fields(tdbb, transaction, &schemaDesc, &desc1); EVL_field(0, new_rpb->rpb_record, f_fld_name, &desc2); - DeferredWork* dw = MET_change_fields(tdbb, transaction, &desc2); + DeferredWork* dw = MET_change_fields(tdbb, transaction, &schemaDesc, &desc2); dsc desc3, desc4; bool rc1, rc2; @@ -3546,18 +3623,18 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j rc1 = EVL_field(0, org_rpb->rpb_record, f_fld_computed, &desc3); rc2 = EVL_field(0, new_rpb->rpb_record, f_fld_computed, &desc4); if (rc1 != rc2 || rc1 && MOV_compare(tdbb, &desc3, &desc4)) { - DFW_post_work_arg(transaction, dw, &desc1, 0, dfw_arg_force_computed); + DFW_post_work_arg(transaction, dw, &desc1, &schemaDesc, 0, dfw_arg_force_computed); } } - dw = DFW_post_work(transaction, dfw_modify_field, &desc1, 0); - DFW_post_work_arg(transaction, dw, &desc2, 0, dfw_arg_new_name); + dw = DFW_post_work(transaction, dfw_modify_field, &desc1, &schemaDesc, 0); + DFW_post_work_arg(transaction, dw, &desc2, &schemaDesc, 0, dfw_arg_new_name); rc1 = EVL_field(NULL, org_rpb->rpb_record, f_fld_null_flag, &desc3); rc2 = EVL_field(NULL, new_rpb->rpb_record, f_fld_null_flag, &desc4); if ((!rc1 || MOV_get_long(tdbb, &desc3, 0) == 0) && rc2 && MOV_get_long(tdbb, &desc4, 0) != 0) - DFW_post_work_arg(transaction, dw, &desc2, 0, dfw_arg_field_not_null); + DFW_post_work_arg(transaction, dw, &desc2, &schemaDesc, 0, dfw_arg_field_not_null); } check_class(tdbb, transaction, org_rpb, new_rpb, f_fld_class); check_owner(tdbb, transaction, org_rpb, new_rpb, f_fld_owner); @@ -3566,9 +3643,13 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j case rel_classes: protect_system_table_delupd(tdbb, relation, "UPDATE"); EVL_field(0, org_rpb->rpb_record, f_cls_class, &desc1); - DFW_post_work(transaction, dfw_compute_security, &desc1, 0); + DFW_post_work(transaction, dfw_compute_security, &desc1, nullptr, 0); EVL_field(0, new_rpb->rpb_record, f_cls_class, &desc1); - DFW_post_work(transaction, dfw_compute_security, &desc1, 0); +#ifdef DEV_BUILD + MOV_get_metaname(tdbb, &desc1, object_name.object); + fb_assert(strncmp(object_name.object.c_str(), "SQL$", 4) == 0); +#endif + DFW_post_work(transaction, dfw_compute_security, &desc1, nullptr, 0); break; case rel_indices: @@ -3577,43 +3658,49 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j if (dfw_should_know(tdbb, org_rpb, new_rpb, f_idx_desc, true)) { + EVL_field(0, new_rpb->rpb_record, f_idx_schema, &schemaDesc); EVL_field(0, new_rpb->rpb_record, f_idx_name, &desc1); 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); + &desc1, &schemaDesc, tdbb->getDatabase()->dbb_max_idx); } else { - DFW_post_work(transaction, dfw_create_index, &desc1, + DFW_post_work(transaction, dfw_create_index, &desc1, &schemaDesc, tdbb->getDatabase()->dbb_max_idx); } } break; case rel_triggers: + EVL_field(0, new_rpb->rpb_record, f_trg_schema, &schemaDesc); EVL_field(0, new_rpb->rpb_record, f_trg_rname, &desc1); if (!check_nullify_source(tdbb, org_rpb, new_rpb, f_trg_source)) protect_system_table_delupd(tdbb, relation, "UPDATE"); else - SCL_check_relation(tdbb, &desc1, SCL_control | SCL_alter); + { + MOV_get_metaname(tdbb, &schemaDesc, object_name.schema); + MOV_get_metaname(tdbb, &desc1, object_name.object); + SCL_check_relation(tdbb, object_name, SCL_control | SCL_alter); + } if (dfw_should_know(tdbb, org_rpb, new_rpb, f_trg_desc, true)) { EVL_field(0, new_rpb->rpb_record, f_trg_rname, &desc1); - DFW_post_work(transaction, dfw_update_format, &desc1, 0); + DFW_post_work(transaction, dfw_update_format, &desc1, &schemaDesc, 0); EVL_field(0, org_rpb->rpb_record, f_trg_rname, &desc1); - DFW_post_work(transaction, dfw_update_format, &desc1, 0); + DFW_post_work(transaction, dfw_update_format, &desc1, &schemaDesc, 0); EVL_field(0, org_rpb->rpb_record, f_trg_name, &desc1); - DeferredWork* dw = DFW_post_work(transaction, dfw_modify_trigger, &desc1, 0); + DeferredWork* dw = DFW_post_work(transaction, dfw_modify_trigger, &desc1, &schemaDesc, 0); if (EVL_field(0, new_rpb->rpb_record, f_trg_rname, &desc2)) - DFW_post_work_arg(transaction, dw, &desc2, 0, dfw_arg_rel_name); + DFW_post_work_arg(transaction, dw, &desc2, &schemaDesc, 0, dfw_arg_rel_name); if (EVL_field(0, new_rpb->rpb_record, f_trg_type, &desc2)) { - DFW_post_work_arg(transaction, dw, &desc2, + DFW_post_work_arg(transaction, dw, &desc2, &schemaDesc, (USHORT) MOV_get_int64(tdbb, &desc2, 0), dfw_arg_trg_type); } } @@ -3633,7 +3720,7 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j { DFW_post_work(transaction, (newFileFlags & FILE_backing_up) ? dfw_begin_backup : dfw_end_backup, - &desc1, 0); + &desc1, nullptr, 0); } } // Nullify the unsupported fields @@ -3983,13 +4070,13 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) * **************************************/ SET_TDBB(tdbb); - Request* const request = tdbb->getRequest(); - jrd_rel* relation = rpb->rpb_relation; + const auto attachment = tdbb->getAttachment(); + const auto request = tdbb->getRequest(); + const auto relation = rpb->rpb_relation; DeferredWork* work = NULL; - MetaName package_name; USHORT object_id; - MetaName object_name; + QualifiedName object_name; #ifdef VIO_DEBUG VIO_trace(DEBUG_WRITES, @@ -3999,10 +4086,277 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) #endif transaction->tra_flags |= TRA_write; - DSC desc, desc2; + DSC desc, desc2, schemaDesc; check_gbak_cheating_insupd(tdbb, relation, "INSERT"); + if (attachment->isGbak() && !(attachment->att_flags & ATT_gbak_restore_has_schema)) + { + struct ObjTypeFieldId + { + ObjectType objType; + USHORT fieldId; + }; + + struct SchemaFieldDependency + { + USHORT fieldId; + std::optional dependencyId; + }; + + static const std::unordered_map> schemaFields = { + {rel_database, { + {f_dat_charset_schema, ObjTypeFieldId{obj_charset, f_dat_charset}} + }}, + {rel_fields, { + {f_fld_schema} + }}, + {rel_segments, { + {f_seg_schema} + }}, + {rel_indices, { + {f_idx_schema}, + {f_idx_foreign_schema, ObjTypeFieldId{obj_index, f_idx_foreign}} + }}, + {rel_rfr, { + {f_rfr_schema}, + {f_rfr_field_source_schema, ObjTypeFieldId{obj_field, f_rfr_sname}} + }}, + {rel_relations, { + {f_rel_schema} + }}, + {rel_vrel, { + {f_vrl_schema}, + {f_vrl_rname_schema, ObjTypeFieldId{obj_relation, f_vrl_rname}} + }}, + {rel_triggers, { + {f_trg_schema} + }}, + {rel_dpds, { + // FIXME: + {f_dpd_schema}, + {f_dpd_o_schema} + }}, + {rel_funs, { + {f_fun_schema} + }}, + {rel_args, { + {f_arg_schema}, + {f_arg_rel_schema, ObjTypeFieldId{obj_relation, f_arg_rname}}, + {f_arg_field_source_schema, ObjTypeFieldId{obj_field, f_arg_sname}} + }}, + {rel_msgs, { + {f_msg_schema} + }}, + {rel_gens, { + {f_gen_schema} + }}, + {rel_dims, { + {f_dims_schema} + }}, + {rel_rcon, { + {f_rcon_schema} + }}, + {rel_refc, { + {f_refc_schema}, + {f_refc_uq_schema, ObjTypeFieldId{obj_any, f_refc_uq}} + }}, + {rel_ccon, { + {f_ccon_schema} + }}, + {rel_procedures, { + {f_prc_schema} + }}, + {rel_prc_prms, { + {f_prm_schema}, + {f_prm_rel_schema, ObjTypeFieldId{obj_relation, f_prm_rname}}, + {f_prm_field_source_schema, ObjTypeFieldId{obj_field, f_prm_sname}} + }}, + {rel_charsets, { + {f_cs_schema}, + {f_cs_def_coll_schema, ObjTypeFieldId{obj_collation, f_cs_def_collate}} + }}, + {rel_collations, { + {f_coll_schema} + }}, + {rel_exceptions, { + {f_xcp_schema} + }}, + {rel_packages, { + {f_pkg_schema} + }}, + {rel_pub_tables, { + {f_pubtab_tab_schema, ObjTypeFieldId{obj_relation, f_pubtab_tab_name}} + }}, + }; + + ObjectsArray schemaSearchPath({SYSTEM_SCHEMA, PUBLIC_SCHEMA}); + + if (const auto relSchemaFields = schemaFields.find(relation->rel_id); relSchemaFields != schemaFields.end()) + { + for (const auto [fieldId, dependency] : relSchemaFields->second) + { + if (rpb->rpb_record->isNull(fieldId) && + (!dependency.has_value() || !rpb->rpb_record->isNull(dependency->fieldId)) && + !EVL_field(0, rpb->rpb_record, fieldId, &schemaDesc)) + { + auto schemaName = PUBLIC_SCHEMA; + QualifiedName depName; + + if (dependency.has_value() && + dependency->objType != obj_any && + EVL_field(0, rpb->rpb_record, dependency->fieldId, &desc)) + { + MOV_get_metaname(tdbb, &desc, depName.object); + + if (MET_qualify_existing_name(tdbb, depName, dependency->objType, &schemaSearchPath)) + schemaName = depName.schema.c_str(); + } + + desc.makeText(strlen(schemaName), CS_METADATA, (UCHAR*) schemaName); + + MOV_move(tdbb, &desc, &schemaDesc); + rpb->rpb_record->clearNull(fieldId); + } + } + } + + if (relation->rel_id == rel_priv) + { + static constexpr int privSchemaFields[][2] = { + {f_prv_user_schema, f_prv_u_type}, + {f_prv_rel_schema, f_prv_o_type} + }; + + for (const auto [fieldId, objTypeId] : privSchemaFields) + { + if (rpb->rpb_record->isNull(fieldId) && + !rpb->rpb_record->isNull(objTypeId) && + EVL_field(0, rpb->rpb_record, objTypeId, &desc2)) + { + const auto objType = MOV_get_long(tdbb, &desc2, 0); + + switch (objType) + { + case obj_relations: + case obj_views: + case obj_procedures: + case obj_functions: + case obj_packages: + case obj_generators: + case obj_domains: + case obj_exceptions: + case obj_charsets: + case obj_collations: + + case obj_relation: + case obj_view: + case obj_trigger: + case obj_procedure: + case obj_exception: + case obj_field: + case obj_index: + case obj_charset: + case obj_generator: + case obj_udf: + case obj_collation: + case obj_package_header: + case obj_package_body: + EVL_field(0, rpb->rpb_record, fieldId, &desc2); + + desc.makeText(strlen(PUBLIC_SCHEMA), CS_METADATA, (UCHAR*) PUBLIC_SCHEMA); // FIXME: + + MOV_move(tdbb, &desc, &desc2); + rpb->rpb_record->clearNull(fieldId); + + break; + } + } + } + + desc2.setNull(); + } + + static const std::unordered_map> schemaBlrFields = { + {rel_args, {f_arg_default}}, + {rel_fields, {f_fld_v_blr, f_fld_computed, f_fld_default, f_fld_missing}}, + {rel_funs, {f_fun_blr}}, + {rel_indices, {f_idx_exp_blr, f_idx_cond_blr}}, + {rel_prc_prms, {f_prm_default}}, + {rel_procedures, {f_prc_blr}}, + {rel_relations, {f_rel_blr}}, + {rel_rfr, {f_rfr_default}}, + {rel_triggers, {f_trg_blr}} + }; + + static const UCHAR bpb[] = { + isc_bpb_version1, + isc_bpb_type, 1, isc_bpb_type_stream + }; + + if (const auto relBlrFields = schemaBlrFields.find(relation->rel_id); relBlrFields != schemaBlrFields.end()) + { + UCHAR buffer[BUFFER_MEDIUM]; + + for (const auto field : relBlrFields->second) + { + if (EVL_field(0, rpb->rpb_record, field, &desc)) + { + AutoBlb blob(tdbb, blb::open(tdbb, transaction, reinterpret_cast(desc.dsc_address))); + bid newBid; + const auto newBlob = blb::create2(tdbb, transaction, &newBid, sizeof(bpb), bpb); + bool firstSegment = true; + UCHAR newHeader[] = { + 0, + blr_flags, + blr_flags_search_system_schema, + 0, 0, + blr_end + }; + + while (!(blob->blb_flags & BLB_eof)) + { + const auto len = blob->BLB_get_data(tdbb, buffer, sizeof(buffer), false); + + if (len > 1 && firstSegment) + { + newHeader[0] = buffer[0]; + fb_assert(newHeader[0] == blr_version4 || newHeader[0] == blr_version5); + + if ((newHeader[0] == blr_version4 || newHeader[0] == blr_version5) && + buffer[1] != blr_flags) + { + newBlob->BLB_put_data(tdbb, newHeader, sizeof(newHeader)); + newBlob->BLB_put_data(tdbb, buffer + 1, len - 1); + + firstSegment = false; + } + else + { + newBid.clear(); + break; + } + } + else + newBlob->BLB_put_data(tdbb, buffer, len); + } + + newBlob->BLB_close(tdbb); + + if (!newBid.isEmpty()) + { + desc2.makeBlob(isc_blob_untyped, 0, reinterpret_cast(&newBid)); + blb::move(tdbb, &desc2, &desc, relation, rpb->rpb_record, field); + } + } + } + } + + desc2.setNull(); + } + + desc.setNull(); + if (needDfw(tdbb, transaction)) { switch ((RIDS) relation->rel_id) @@ -4029,7 +4383,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) protect_system_table_insert(tdbb, request, relation); EVL_field(0, rpb->rpb_record, f_rol_name, &desc); if (set_security_class(tdbb, rpb->rpb_record, f_rol_class)) - DFW_post_work(transaction, dfw_grant, &desc, obj_sql_role); + DFW_post_work(transaction, dfw_grant, &desc, nullptr, obj_sql_role); break; case rel_db_creators: @@ -4055,39 +4409,51 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_database: protect_system_table_insert(tdbb, request, relation); if (set_security_class(tdbb, rpb->rpb_record, f_dat_class)) - DFW_post_work(transaction, dfw_grant, "", obj_database); + DFW_post_work(transaction, dfw_grant, {}, {}, obj_database); + break; + + case rel_schemas: + protect_system_table_insert(tdbb, request, relation); + EVL_field(0, rpb->rpb_record, f_sch_schema, &desc); + if (set_security_class(tdbb, rpb->rpb_record, f_sch_class)) + DFW_post_work(transaction, dfw_grant, &desc, nullptr, obj_schema); break; case rel_relations: protect_system_table_insert(tdbb, request, relation); + EVL_field(0, rpb->rpb_record, f_rel_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_rel_name, &desc); - DFW_post_work(transaction, dfw_create_relation, &desc, 0); - DFW_post_work(transaction, dfw_update_format, &desc, 0); + DFW_post_work(transaction, dfw_create_relation, &desc, &schemaDesc, 0); + DFW_post_work(transaction, dfw_update_format, &desc, &schemaDesc, 0); set_system_flag(tdbb, rpb->rpb_record, f_rel_sys_flag); set_owner_name(tdbb, rpb->rpb_record, f_rel_owner); if (set_security_class(tdbb, rpb->rpb_record, f_rel_class)) - DFW_post_work(transaction, dfw_grant, &desc, obj_relation); + DFW_post_work(transaction, dfw_grant, &desc, &schemaDesc, obj_relation); break; case rel_packages: protect_system_table_insert(tdbb, request, relation); + EVL_field(0, rpb->rpb_record, f_pkg_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_pkg_name, &desc); set_system_flag(tdbb, rpb->rpb_record, f_pkg_sys_flag); set_owner_name(tdbb, rpb->rpb_record, f_pkg_owner); if (set_security_class(tdbb, rpb->rpb_record, f_pkg_class)) - DFW_post_work(transaction, dfw_grant, &desc, obj_package_header); + DFW_post_work(transaction, dfw_grant, &desc, &schemaDesc, obj_package_header); break; case rel_procedures: protect_system_table_insert(tdbb, request, relation); + + EVL_field(0, rpb->rpb_record, f_prc_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_prc_name, &desc); if (EVL_field(0, rpb->rpb_record, f_prc_pkg_name, &desc2)) - MOV_get_metaname(tdbb, &desc2, package_name); + MOV_get_metaname(tdbb, &desc2, object_name.package); object_id = set_metadata_id(tdbb, rpb->rpb_record, f_prc_id, drq_g_nxt_prc_id, "RDB$PROCEDURES"); - work = DFW_post_work(transaction, dfw_create_procedure, &desc, object_id, package_name); + + work = DFW_post_work(transaction, dfw_create_procedure, &desc, &schemaDesc, object_id, object_name.package); { // scope bool check_blr = true; @@ -4095,29 +4461,32 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) check_blr = MOV_get_long(tdbb, &desc2, 0) != 0; if (check_blr) - DFW_post_work_arg(transaction, work, NULL, 0, dfw_arg_check_blr); + DFW_post_work_arg(transaction, work, nullptr, nullptr, 0, dfw_arg_check_blr); } // scope set_system_flag(tdbb, rpb->rpb_record, f_prc_sys_flag); set_owner_name(tdbb, rpb->rpb_record, f_prc_owner); - if (package_name.isEmpty()) + if (object_name.package.isEmpty()) { if (set_security_class(tdbb, rpb->rpb_record, f_prc_class)) - DFW_post_work(transaction, dfw_grant, &desc, obj_procedure); + DFW_post_work(transaction, dfw_grant, &desc, &schemaDesc, obj_procedure); } break; case rel_funs: protect_system_table_insert(tdbb, request, relation); + + EVL_field(0, rpb->rpb_record, f_fun_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_fun_name, &desc); if (EVL_field(0, rpb->rpb_record, f_fun_pkg_name, &desc2)) - MOV_get_metaname(tdbb, &desc2, package_name); + MOV_get_metaname(tdbb, &desc2, object_name.package); object_id = set_metadata_id(tdbb, rpb->rpb_record, f_fun_id, drq_g_nxt_fun_id, "RDB$FUNCTIONS"); - work = DFW_post_work(transaction, dfw_create_function, &desc, object_id, package_name); + + work = DFW_post_work(transaction, dfw_create_function, &desc, &schemaDesc, object_id, object_name.package); { // scope bool check_blr = true; @@ -4125,62 +4494,72 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) check_blr = MOV_get_long(tdbb, &desc2, 0) != 0; if (check_blr) - DFW_post_work_arg(transaction, work, NULL, 0, dfw_arg_check_blr); + DFW_post_work_arg(transaction, work, nullptr, nullptr, 0, dfw_arg_check_blr); } // scope set_system_flag(tdbb, rpb->rpb_record, f_fun_sys_flag); set_owner_name(tdbb, rpb->rpb_record, f_fun_owner); - if (package_name.isEmpty()) + if (object_name.package.isEmpty()) { if (set_security_class(tdbb, rpb->rpb_record, f_fun_class)) - DFW_post_work(transaction, dfw_grant, &desc, obj_udf); + DFW_post_work(transaction, dfw_grant, &desc, &schemaDesc, obj_udf); } break; case rel_indices: protect_system_table_insert(tdbb, request, relation); + + EVL_field(0, rpb->rpb_record, f_idx_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_idx_name, &desc); + if (EVL_field(0, rpb->rpb_record, f_idx_exp_blr, &desc2)) { - DFW_post_work(transaction, dfw_create_expression_index, &desc, + DFW_post_work(transaction, dfw_create_expression_index, &desc, &schemaDesc, tdbb->getDatabase()->dbb_max_idx); } - else { - DFW_post_work(transaction, dfw_create_index, &desc, tdbb->getDatabase()->dbb_max_idx); - } + else + DFW_post_work(transaction, dfw_create_index, &desc, &schemaDesc, tdbb->getDatabase()->dbb_max_idx); + set_system_flag(tdbb, rpb->rpb_record, f_idx_sys_flag); break; case rel_rfr: protect_system_table_insert(tdbb, request, relation); + EVL_field(0, rpb->rpb_record, f_rfr_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_rfr_rname, &desc); - DFW_post_work(transaction, dfw_update_format, &desc, 0); + DFW_post_work(transaction, dfw_update_format, &desc, &schemaDesc, 0); set_system_flag(tdbb, rpb->rpb_record, f_rfr_sys_flag); break; case rel_classes: protect_system_table_insert(tdbb, request, relation); EVL_field(0, rpb->rpb_record, f_cls_class, &desc); - DFW_post_work(transaction, dfw_compute_security, &desc, 0); +#ifdef DEV_BUILD + MOV_get_metaname(tdbb, &desc, object_name.object); + fb_assert(strncmp(object_name.object.c_str(), "SQL$", 4) == 0); +#endif + DFW_post_work(transaction, dfw_compute_security, &desc, nullptr, 0); break; case rel_fields: + EVL_field(0, rpb->rpb_record, f_fld_schema, &schemaDesc); + MOV_get_metaname(tdbb, &schemaDesc, object_name.schema); EVL_field(0, rpb->rpb_record, f_fld_name, &desc); - MOV_get_metaname(tdbb, &desc, object_name); + MOV_get_metaname(tdbb, &desc, object_name.object); SCL_check_domain(tdbb, object_name, SCL_create); - DFW_post_work(transaction, dfw_create_field, &desc, 0); + DFW_post_work(transaction, dfw_create_field, &desc, &schemaDesc, 0); set_system_flag(tdbb, rpb->rpb_record, f_fld_sys_flag); set_owner_name(tdbb, rpb->rpb_record, f_fld_owner); if (set_security_class(tdbb, rpb->rpb_record, f_fld_class)) - DFW_post_work(transaction, dfw_grant, &desc, obj_field); + DFW_post_work(transaction, dfw_grant, &desc, &schemaDesc, obj_field); break; case rel_filters: protect_system_table_insert(tdbb, request, relation); EVL_field(0, rpb->rpb_record, f_flt_name, &desc); if (set_security_class(tdbb, rpb->rpb_record, f_flt_class)) - DFW_post_work(transaction, dfw_grant, &desc, obj_blob_filter); + DFW_post_work(transaction, dfw_grant, &desc, nullptr, obj_blob_filter); break; case rel_files: @@ -4197,15 +4576,15 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) if (shadowNumber) { if (!(fileFlags & FILE_inactive)) - DFW_post_work(transaction, dfw_add_shadow, &desc, 0); + DFW_post_work(transaction, dfw_add_shadow, &desc, nullptr, 0); } else if (fileFlags & FILE_difference) { if (nameDefined) - DFW_post_work(transaction, dfw_add_difference, &desc, 0); + DFW_post_work(transaction, dfw_add_difference, &desc, nullptr, 0); if (fileFlags & FILE_backing_up) - DFW_post_work(transaction, dfw_begin_backup, &desc, 0); + DFW_post_work(transaction, dfw_begin_backup, &desc, nullptr, 0); } } // Nullify the unsupported fields @@ -4215,24 +4594,29 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) break; case rel_triggers: + EVL_field(0, rpb->rpb_record, f_trg_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_trg_rname, &desc); // check if this request go through without checking permissions if (!(request->getStatement()->flags & (Statement::FLAG_IGNORE_PERM | Statement::FLAG_INTERNAL))) - SCL_check_relation(tdbb, &desc, SCL_control | SCL_alter); + { + MOV_get_metaname(tdbb, &schemaDesc, object_name.schema); + MOV_get_metaname(tdbb, &desc, object_name.object); + SCL_check_relation(tdbb, object_name, SCL_control | SCL_alter); + } if (EVL_field(0, rpb->rpb_record, f_trg_rname, &desc2)) - DFW_post_work(transaction, dfw_update_format, &desc2, 0); + DFW_post_work(transaction, dfw_update_format, &desc2, &schemaDesc, 0); EVL_field(0, rpb->rpb_record, f_trg_name, &desc); - work = DFW_post_work(transaction, dfw_create_trigger, &desc, 0); + work = DFW_post_work(transaction, dfw_create_trigger, &desc, &schemaDesc, 0); if (!(desc2.dsc_flags & DSC_null)) - DFW_post_work_arg(transaction, work, &desc2, 0, dfw_arg_rel_name); + DFW_post_work_arg(transaction, work, &desc2, &schemaDesc, 0, dfw_arg_rel_name); if (EVL_field(0, rpb->rpb_record, f_trg_type, &desc2)) { - DFW_post_work_arg(transaction, work, &desc2, + DFW_post_work_arg(transaction, work, &desc2, &schemaDesc, (USHORT) MOV_get_int64(tdbb, &desc2, 0), dfw_arg_trg_type); } set_system_flag(tdbb, rpb->rpb_record, f_trg_sys_flag); @@ -4240,10 +4624,11 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_priv: protect_system_table_insert(tdbb, request, relation); + EVL_field(0, rpb->rpb_record, f_prv_rel_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_prv_rname, &desc); EVL_field(0, rpb->rpb_record, f_prv_o_type, &desc2); object_id = MOV_get_long(tdbb, &desc2, 0); - DFW_post_work(transaction, dfw_grant, &desc, object_id); + DFW_post_work(transaction, dfw_grant, &desc, &schemaDesc, object_id); break; case rel_vrel: @@ -4254,53 +4639,59 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) if (EVL_field(0, rpb->rpb_record, f_vrl_vname, &desc) && EVL_field(0, rpb->rpb_record, f_vrl_context, &desc2)) { + EVL_field(0, rpb->rpb_record, f_vrl_schema, &schemaDesc); + const USHORT id = MOV_get_long(tdbb, &desc2, 0); - DFW_post_work(transaction, dfw_store_view_context_type, &desc, id); + DFW_post_work(transaction, dfw_store_view_context_type, &desc, &schemaDesc, id); } } break; case rel_gens: protect_system_table_insert(tdbb, request, relation); + EVL_field(0, rpb->rpb_record, f_gen_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_gen_name, &desc); EVL_field(0, rpb->rpb_record, f_gen_id, &desc2); object_id = set_metadata_id(tdbb, rpb->rpb_record, f_gen_id, drq_g_nxt_gen_id, MASTER_GENERATOR); transaction->getGenIdCache()->put(object_id, 0); - DFW_post_work(transaction, dfw_set_generator, &desc, object_id); + DFW_post_work(transaction, dfw_set_generator, &desc, &schemaDesc, object_id); set_system_flag(tdbb, rpb->rpb_record, f_gen_sys_flag); set_owner_name(tdbb, rpb->rpb_record, f_gen_owner); if (set_security_class(tdbb, rpb->rpb_record, f_gen_class)) - DFW_post_work(transaction, dfw_grant, &desc, obj_generator); + DFW_post_work(transaction, dfw_grant, &desc, &schemaDesc, obj_generator); break; case rel_charsets: protect_system_table_insert(tdbb, request, relation); + EVL_field(0, rpb->rpb_record, f_cs_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_cs_cs_name, &desc); set_system_flag(tdbb, rpb->rpb_record, f_cs_sys_flag); set_owner_name(tdbb, rpb->rpb_record, f_cs_owner); if (set_security_class(tdbb, rpb->rpb_record, f_cs_class)) - DFW_post_work(transaction, dfw_grant, &desc, obj_charset); + DFW_post_work(transaction, dfw_grant, &desc, &schemaDesc, obj_charset); break; case rel_collations: protect_system_table_insert(tdbb, request, relation); + EVL_field(0, rpb->rpb_record, f_coll_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_coll_name, &desc); set_system_flag(tdbb, rpb->rpb_record, f_coll_sys_flag); set_owner_name(tdbb, rpb->rpb_record, f_coll_owner); if (set_security_class(tdbb, rpb->rpb_record, f_coll_class)) - DFW_post_work(transaction, dfw_grant, &desc, obj_collation); + DFW_post_work(transaction, dfw_grant, &desc, &schemaDesc, obj_collation); break; case rel_exceptions: protect_system_table_insert(tdbb, request, relation); + EVL_field(0, rpb->rpb_record, f_xcp_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_xcp_name, &desc); set_metadata_id(tdbb, rpb->rpb_record, f_xcp_number, drq_g_nxt_xcp_id, "RDB$EXCEPTIONS"); set_system_flag(tdbb, rpb->rpb_record, f_xcp_sys_flag); set_owner_name(tdbb, rpb->rpb_record, f_xcp_owner); if (set_security_class(tdbb, rpb->rpb_record, f_xcp_class)) - DFW_post_work(transaction, dfw_grant, &desc, obj_exception); + DFW_post_work(transaction, dfw_grant, &desc, &schemaDesc, obj_exception); break; case rel_backup_history: @@ -4318,7 +4709,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_pub_tables: protect_system_table_insert(tdbb, request, relation); - DFW_post_work(transaction, dfw_change_repl_state, "", 1); + DFW_post_work(transaction, dfw_change_repl_state, {}, {}, 1); break; default: // Shut up compiler warnings @@ -4331,6 +4722,8 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) { case rel_collations: { + EVL_field(0, rpb->rpb_record, f_coll_schema, &schemaDesc); + EVL_field(0, rpb->rpb_record, f_coll_cs_id, &desc); USHORT id = MOV_get_long(tdbb, &desc, 0); @@ -4338,7 +4731,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) id = INTL_CS_COLL_TO_TTYPE(id, MOV_get_long(tdbb, &desc, 0)); EVL_field(0, rpb->rpb_record, f_coll_name, &desc); - DFW_post_work(transaction, dfw_create_collation, &desc, id); + DFW_post_work(transaction, dfw_create_collation, &desc, &schemaDesc, id); } break; @@ -4740,9 +5133,10 @@ static void check_rel_field_class(thread_db* tdbb, **************************************/ SET_TDBB(tdbb); - DSC desc; + DSC schemaDesc, desc; + EVL_field(0, rpb->rpb_record, f_rfr_schema, &schemaDesc); EVL_field(0, rpb->rpb_record, f_rfr_rname, &desc); - DFW_post_work(transaction, dfw_update_format, &desc, 0); + DFW_post_work(transaction, dfw_update_format, &desc, &schemaDesc, 0); } static void check_class(thread_db* tdbb, @@ -4772,7 +5166,7 @@ static void check_class(thread_db* tdbb, if (!flag_new || (flag_org && !MOV_compare(tdbb, &desc1, &desc2))) return; - DFW_post_work(transaction, dfw_compute_security, &desc2, 0); + DFW_post_work(transaction, dfw_compute_security, &desc2, nullptr, 0); } @@ -4906,7 +5300,7 @@ static void check_repl_state(thread_db* tdbb, if (flag_org && flag_new && !MOV_compare(tdbb, &desc1, &desc2)) return; - DFW_post_work(transaction, dfw_change_repl_state, "", 0); + DFW_post_work(transaction, dfw_change_repl_state, {}, {}, 0); } @@ -6438,7 +6832,7 @@ static void protect_system_table_insert(thread_db* tdbb, } status_exception::raise(Arg::Gds(isc_protect_sys_tab) << - Arg::Str("INSERT") << Arg::Str(relation->rel_name)); + Arg::Str("INSERT") << relation->rel_name.toQuotedString()); } @@ -6470,7 +6864,7 @@ static void protect_system_table_delupd(thread_db* tdbb, } status_exception::raise(Arg::Gds(isc_protect_sys_tab) << - Arg::Str(operation) << Arg::Str(relation->rel_name)); + Arg::Str(operation) << relation->rel_name.toQuotedString()); } diff --git a/src/plugins/profiler/Profiler.cpp b/src/plugins/profiler/Profiler.cpp index 5845b53899..585548a3bf 100644 --- a/src/plugins/profiler/Profiler.cpp +++ b/src/plugins/profiler/Profiler.cpp @@ -1,3 +1,4 @@ +// FIXME: Migrate in gbak. /* * The contents of this file are subject to the Initial * Developer's Public License Version 1.0 (the "License"); @@ -124,6 +125,7 @@ struct Statement { unsigned level = 0; string type{defaultPool()}; + MetaString schemaName{defaultPool()}; MetaString packageName{defaultPool()}; MetaString routineName{defaultPool()}; SINT64 parentStatementId; @@ -180,8 +182,11 @@ public: void finish(ThrowStatusExceptionWrapper* status, ISC_TIMESTAMP_TZ timestamp) override; - void defineStatement(ThrowStatusExceptionWrapper* status, SINT64 statementId, SINT64 parentStatementId, - const char* type, const char* packageName, const char* routineName, const char* sqlText) override; + void deprecatedDefineStatement(ThrowStatusExceptionWrapper* status, SINT64 statementId, SINT64 parentStatementId, + const char* type, const char* packageName, const char* routineName, const char* sqlText) override + { + defineStatement2(status, statementId, parentStatementId, type, nullptr, packageName, routineName, sqlText); + } void defineCursor(SINT64 statementId, unsigned cursorId, const char* name, unsigned line, unsigned column) override; @@ -216,6 +221,10 @@ public: void afterRecordSourceGetRecord(SINT64 statementId, SINT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) override; + void defineStatement2(ThrowStatusExceptionWrapper* status, SINT64 statementId, SINT64 parentStatementId, + const char* type, const char* schemaName, const char* packageName, const char* routineName, + const char* sqlText) override; + private: Request* getRequest(SINT64 statementId, SINT64 requestId) { @@ -251,7 +260,11 @@ public: void flush(ThrowStatusExceptionWrapper* status) override; private: - void createMetadata(ThrowStatusExceptionWrapper* status, RefPtr attachment, + void createInitialMetadata(ThrowStatusExceptionWrapper* status, RefPtr attachment, + RefPtr transaction); + void upgradeMetadataWithSchemaName(ThrowStatusExceptionWrapper* status, RefPtr attachment, + RefPtr transaction); + void recreateViews(ThrowStatusExceptionWrapper* status, RefPtr attachment, RefPtr transaction); void loadMetadata(ThrowStatusExceptionWrapper* status); @@ -271,21 +284,30 @@ void ProfilerPlugin::init(ThrowStatusExceptionWrapper* status, IAttachment* atta constexpr auto sql = R"""( select exists( select true - from rdb$roles + from system.rdb$roles where rdb$role_name = 'PLG$PROFILER' ) metadata_created, + exists( + select true + from system.rdb$relation_fields + where rdb$schema_name = 'PLG$PROFILER' and + rdb$relation_name = 'PLG$PROF_STATEMENTS' and + rdb$field_name = 'SCHEMA_NAME' + ) has_schema_name, rdb$get_context('SYSTEM', 'DB_NAME') db_name, (select rdb$owner_name - from rdb$relations - where rdb$relation_name = 'RDB$DATABASE' + from system.rdb$relations + where rdb$schema_name = 'SYSTEM' and + rdb$relation_name = 'RDB$DATABASE' ) owner_name, current_role, rdb$role_in_use('PLG$PROFILER') role_in_use - from rdb$database + from system.rdb$database )"""; FB_MESSAGE(message, ThrowStatusExceptionWrapper, (FB_BOOLEAN, metadataCreated) + (FB_BOOLEAN, hasSchemaName) (FB_INTL_VARCHAR(MAXPATHLEN * 4, CS_METADATA), dbName) (FB_INTL_VARCHAR(MAX_SQL_IDENTIFIER_LEN, CS_METADATA), ownerName) (FB_INTL_VARCHAR(MAX_SQL_IDENTIFIER_LEN, CS_METADATA), currentRole) @@ -318,7 +340,7 @@ void ProfilerPlugin::init(ThrowStatusExceptionWrapper* status, IAttachment* atta roleInUse = message->roleInUse; - if (message->metadataCreated) + if (message->metadataCreated && message->hasSchemaName) break; auto dispatcher = makeNoIncRef(MasterInterfacePtr()->getDispatcher()); @@ -340,7 +362,9 @@ void ProfilerPlugin::init(ThrowStatusExceptionWrapper* status, IAttachment* atta } if (!message->metadataCreated) - createMetadata(status, refAttachment, refTransaction); + createInitialMetadata(status, refAttachment, refTransaction); + else if (!message->hasSchemaName) + upgradeMetadataWithSchemaName(status, refAttachment, refTransaction); if (!roleInUse) { @@ -394,7 +418,7 @@ IProfilerSession* ProfilerPlugin::startSession(ThrowStatusExceptionWrapper* stat void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status) { constexpr auto sessionSql = R"""( - update or insert into plg$prof_sessions + update or insert into plg$profiler.plg$prof_sessions (profile_id, attachment_id, user_name, description, start_timestamp, finish_timestamp) values (?, current_connection, current_user, ?, ?, ?) matching (profile_id) @@ -409,9 +433,10 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status) sessionMessage.clear(); constexpr auto statementSql = R"""( - update or insert into plg$prof_statements - (profile_id, statement_id, parent_statement_id, statement_type, package_name, routine_name, sql_text) - values (?, ?, ?, ?, ?, ?, ?) + update or insert into plg$profiler.plg$prof_statements + (profile_id, statement_id, parent_statement_id, statement_type, schema_name, package_name, routine_name, + sql_text) + values (?, ?, ?, ?, ?, ?, ?, ?) matching (profile_id, statement_id) )"""; @@ -420,6 +445,7 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status) (FB_BIGINT, statementId) (FB_BIGINT, parentStatementId) (FB_INTL_VARCHAR(20 * 4, CS_UTF8), statementType) + (FB_INTL_VARCHAR(METADATA_IDENTIFIER_CHAR_LEN * 4, CS_UTF8), schemaName) (FB_INTL_VARCHAR(METADATA_IDENTIFIER_CHAR_LEN * 4, CS_UTF8), packageName) (FB_INTL_VARCHAR(METADATA_IDENTIFIER_CHAR_LEN * 4, CS_UTF8), routineName) (FB_BLOB, sqlText) @@ -427,7 +453,7 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status) statementMessage.clear(); constexpr auto cursorSql = R"""( - update or insert into plg$prof_cursors + update or insert into plg$profiler.plg$prof_cursors (profile_id, statement_id, cursor_id, name, line_num, column_num) values (?, ?, ?, ?, ?, ?) matching (profile_id, statement_id, cursor_id) @@ -444,7 +470,7 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status) cursorMessage.clear(); constexpr auto recSrcSql = R"""( - update or insert into plg$prof_record_sources + update or insert into plg$profiler.plg$prof_record_sources (profile_id, statement_id, cursor_id, record_source_id, parent_record_source_id, level, access_path) values (?, ?, ?, ?, ?, ?, ?) @@ -463,7 +489,7 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status) recSrcMessage.clear(); constexpr auto requestSql = R"""( - update or insert into plg$prof_requests + update or insert into plg$profiler.plg$prof_requests (profile_id, statement_id, request_id, caller_statement_id, caller_request_id, start_timestamp, finish_timestamp, total_elapsed_time) values (?, ?, ?, ?, ?, ?, ?, ?) @@ -484,24 +510,24 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status) constexpr auto recSrcStatSql = R"""( execute block ( - profile_id type of column plg$prof_record_source_stats.profile_id = ?, - statement_id type of column plg$prof_record_source_stats.statement_id = ?, - request_id type of column plg$prof_record_source_stats.request_id = ?, - cursor_id type of column plg$prof_record_source_stats.cursor_id = ?, - record_source_id type of column plg$prof_record_source_stats.record_source_id = ?, - open_counter type of column plg$prof_record_source_stats.open_counter = ?, - open_min_elapsed_time type of column plg$prof_record_source_stats.open_min_elapsed_time = ?, - open_max_elapsed_time type of column plg$prof_record_source_stats.open_max_elapsed_time = ?, - open_total_elapsed_time type of column plg$prof_record_source_stats.open_total_elapsed_time = ?, - fetch_counter type of column plg$prof_record_source_stats.fetch_counter = ?, - fetch_min_elapsed_time type of column plg$prof_record_source_stats.fetch_min_elapsed_time = ?, - fetch_max_elapsed_time type of column plg$prof_record_source_stats.fetch_max_elapsed_time = ?, - fetch_total_elapsed_time type of column plg$prof_record_source_stats.fetch_total_elapsed_time = ? + profile_id type of column plg$profiler.plg$prof_record_source_stats.profile_id = ?, + statement_id type of column plg$profiler.plg$prof_record_source_stats.statement_id = ?, + request_id type of column plg$profiler.plg$prof_record_source_stats.request_id = ?, + cursor_id type of column plg$profiler.plg$prof_record_source_stats.cursor_id = ?, + record_source_id type of column plg$profiler.plg$prof_record_source_stats.record_source_id = ?, + open_counter type of column plg$profiler.plg$prof_record_source_stats.open_counter = ?, + open_min_elapsed_time type of column plg$profiler.plg$prof_record_source_stats.open_min_elapsed_time = ?, + open_max_elapsed_time type of column plg$profiler.plg$prof_record_source_stats.open_max_elapsed_time = ?, + open_total_elapsed_time type of column plg$profiler.plg$prof_record_source_stats.open_total_elapsed_time = ?, + fetch_counter type of column plg$profiler.plg$prof_record_source_stats.fetch_counter = ?, + fetch_min_elapsed_time type of column plg$profiler.plg$prof_record_source_stats.fetch_min_elapsed_time = ?, + fetch_max_elapsed_time type of column plg$profiler.plg$prof_record_source_stats.fetch_max_elapsed_time = ?, + fetch_total_elapsed_time type of column plg$profiler.plg$prof_record_source_stats.fetch_total_elapsed_time = ? ) as begin - merge into plg$prof_record_source_stats - using rdb$database on + merge into plg$profiler.plg$prof_record_source_stats + using system.rdb$database on profile_id = :profile_id and statement_id = :statement_id and request_id = :request_id and @@ -546,20 +572,20 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status) constexpr auto psqlStatSql = R"""( execute block ( - profile_id type of column plg$prof_psql_stats.profile_id = ?, - statement_id type of column plg$prof_psql_stats.statement_id = ?, - request_id type of column plg$prof_psql_stats.request_id = ?, - line_num type of column plg$prof_psql_stats.line_num = ?, - column_num type of column plg$prof_psql_stats.column_num = ?, - counter type of column plg$prof_psql_stats.counter = ?, - min_elapsed_time type of column plg$prof_psql_stats.min_elapsed_time = ?, - max_elapsed_time type of column plg$prof_psql_stats.max_elapsed_time = ?, - total_elapsed_time type of column plg$prof_psql_stats.total_elapsed_time = ? + profile_id type of column plg$profiler.plg$prof_psql_stats.profile_id = ?, + statement_id type of column plg$profiler.plg$prof_psql_stats.statement_id = ?, + request_id type of column plg$profiler.plg$prof_psql_stats.request_id = ?, + line_num type of column plg$profiler.plg$prof_psql_stats.line_num = ?, + column_num type of column plg$profiler.plg$prof_psql_stats.column_num = ?, + counter type of column plg$profiler.plg$prof_psql_stats.counter = ?, + min_elapsed_time type of column plg$profiler.plg$prof_psql_stats.min_elapsed_time = ?, + max_elapsed_time type of column plg$profiler.plg$prof_psql_stats.max_elapsed_time = ?, + total_elapsed_time type of column plg$profiler.plg$prof_psql_stats.total_elapsed_time = ? ) as begin - merge into plg$prof_psql_stats - using rdb$database on + merge into plg$profiler.plg$prof_psql_stats + using system.rdb$database on profile_id = :profile_id and statement_id = :statement_id and request_id = :request_id and @@ -708,6 +734,9 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status) statementMessage->statementTypeNull = FB_FALSE; statementMessage->statementType.set(profileStatement.type.c_str()); + statementMessage->schemaNameNull = profileStatement.schemaName.isEmpty(); + statementMessage->schemaName.set(profileStatement.schemaName.c_str()); + statementMessage->packageNameNull = profileStatement.packageName.isEmpty(); statementMessage->packageName.set(profileStatement.packageName.c_str()); @@ -970,7 +999,7 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status) transaction.clear(); } -void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr attachment, +void ProfilerPlugin::createInitialMetadata(ThrowStatusExceptionWrapper* status, RefPtr attachment, RefPtr transaction) { constexpr const char* createSqlStaments[] = { @@ -978,12 +1007,16 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr< "grant default plg$profiler to public", - "create sequence plg$prof_profile_id", + "create schema plg$profiler default character set utf8", - "grant usage on sequence plg$prof_profile_id to plg$profiler", + "grant usage on schema plg$profiler to plg$profiler", + + "create sequence plg$profiler.plg$prof_profile_id", + + "grant usage on sequence plg$profiler.plg$prof_profile_id to plg$profiler", R"""( - create table plg$prof_sessions ( + create table plg$profiler.plg$prof_sessions ( profile_id bigint not null constraint plg$prof_sessions_pk primary key @@ -995,18 +1028,19 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr< finish_timestamp timestamp with time zone ))""", - "grant select, update, insert, delete on table plg$prof_sessions to plg$profiler", + "grant select, update, insert, delete on table plg$profiler.plg$prof_sessions to plg$profiler", R"""( - create table plg$prof_statements ( + create table plg$profiler.plg$prof_statements ( profile_id bigint not null constraint plg$prof_statements_session_fk - references plg$prof_sessions + references plg$profiler.plg$prof_sessions on delete cascade using index plg$prof_statements_profile, statement_id bigint not null, parent_statement_id bigint, statement_type varchar(20) character set utf8 not null, + schema_name char(63) character set utf8, package_name char(63) character set utf8, routine_name char(63) character set utf8, sql_text blob sub_type text character set utf8, @@ -1014,18 +1048,19 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr< primary key (profile_id, statement_id) using index plg$prof_statements_profile_statement, constraint plg$prof_statements_parent_statement_fk - foreign key (profile_id, parent_statement_id) references plg$prof_statements (profile_id, statement_id) + foreign key (profile_id, parent_statement_id) + references plg$profiler.plg$prof_statements (profile_id, statement_id) on delete cascade using index plg$prof_statements_parent_statement ))""", - "grant select, update, insert, delete on table plg$prof_statements to plg$profiler", + "grant select, update, insert, delete on table plg$profiler.plg$prof_statements to plg$profiler", R"""( - create table plg$prof_cursors ( + create table plg$profiler.plg$prof_cursors ( profile_id bigint not null constraint plg$prof_cursors_session_fk - references plg$prof_sessions + references plg$profiler.plg$prof_sessions on delete cascade using index plg$prof_cursors_profile, statement_id bigint not null, @@ -1037,18 +1072,18 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr< primary key (profile_id, statement_id, cursor_id) using index plg$prof_cursors_profile_statement_cursor, constraint plg$prof_cursors_statement_fk - foreign key (profile_id, statement_id) references plg$prof_statements + foreign key (profile_id, statement_id) references plg$profiler.plg$prof_statements on delete cascade using index plg$prof_cursors_profile_statement ))""", - "grant select, update, insert, delete on table plg$prof_cursors to plg$profiler", + "grant select, update, insert, delete on table plg$profiler.plg$prof_cursors to plg$profiler", R"""( - create table plg$prof_record_sources ( + create table plg$profiler.plg$prof_record_sources ( profile_id bigint not null constraint plg$prof_record_sources_session_fk - references plg$prof_sessions + references plg$profiler.plg$prof_sessions on delete cascade using index plg$prof_record_sources_profile, statement_id bigint not null, @@ -1061,27 +1096,27 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr< primary key (profile_id, statement_id, cursor_id, record_source_id) using index plg$prof_record_sources_profile_statement_cursor_recsource, constraint plg$prof_record_sources_statement_fk - foreign key (profile_id, statement_id) references plg$prof_statements + foreign key (profile_id, statement_id) references plg$profiler.plg$prof_statements on delete cascade using index plg$prof_record_sources_profile_statement, constraint plg$prof_record_sources_cursor_fk - foreign key (profile_id, statement_id, cursor_id) references plg$prof_cursors + foreign key (profile_id, statement_id, cursor_id) references plg$profiler.plg$prof_cursors on delete cascade using index plg$prof_record_sources_profile_statement_cursor, constraint plg$prof_record_sources_parent_record_source_fk foreign key (profile_id, statement_id, cursor_id, parent_record_source_id) - references plg$prof_record_sources (profile_id, statement_id, cursor_id, record_source_id) + references plg$profiler.plg$prof_record_sources (profile_id, statement_id, cursor_id, record_source_id) on delete cascade using index plg$prof_record_sources_profile_statement_cursor_parent_rec_src ))""", - "grant select, update, insert, delete on table plg$prof_record_sources to plg$profiler", + "grant select, update, insert, delete on table plg$profiler.plg$prof_record_sources to plg$profiler", R"""( - create table plg$prof_requests ( + create table plg$profiler.plg$prof_requests ( profile_id bigint not null constraint plg$prof_requests_session_fk - references plg$prof_sessions + references plg$profiler.plg$prof_sessions on delete cascade using index plg$prof_requests_profile, statement_id bigint not null, @@ -1095,27 +1130,27 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr< primary key (profile_id, statement_id, request_id) using index plg$prof_requests_profile_request_statement, constraint plg$prof_requests_statement_fk - foreign key (profile_id, statement_id) references plg$prof_statements + foreign key (profile_id, statement_id) references plg$profiler.plg$prof_statements on delete cascade using index plg$prof_requests_profile_statement, constraint plg$prof_requests_caller_statement_fk - foreign key (profile_id, caller_statement_id) references plg$prof_statements + foreign key (profile_id, caller_statement_id) references plg$profiler.plg$prof_statements on delete cascade using index plg$prof_requests_profile_caller_statement, constraint plg$prof_requests_caller_request_fk foreign key (profile_id, caller_statement_id, caller_request_id) - references plg$prof_requests (profile_id, statement_id, request_id) + references plg$profiler.plg$prof_requests (profile_id, statement_id, request_id) on delete cascade using index plg$prof_requests_profile_caller_statement_caller_request ))""", - "grant select, update, insert, delete on table plg$prof_requests to plg$profiler", + "grant select, update, insert, delete on table plg$profiler.plg$prof_requests to plg$profiler", R"""( - create table plg$prof_psql_stats ( + create table plg$profiler.plg$prof_psql_stats ( profile_id bigint not null constraint plg$prof_psql_stats_session_fk - references plg$prof_sessions + references plg$profiler.plg$prof_sessions on delete cascade using index plg$prof_psql_stats_profile, statement_id bigint not null, @@ -1130,22 +1165,22 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr< primary key (profile_id, statement_id, request_id, line_num, column_num) using index plg$prof_psql_stats_profile_statement_request_line_column, constraint plg$prof_psql_stats_request_fk - foreign key (profile_id, statement_id, request_id) references plg$prof_requests + foreign key (profile_id, statement_id, request_id) references plg$profiler.plg$prof_requests on delete cascade using index plg$prof_psql_stats_profile_request, constraint plg$prof_psql_stats_statement_fk - foreign key (profile_id, statement_id) references plg$prof_statements + foreign key (profile_id, statement_id) references plg$profiler.plg$prof_statements on delete cascade using index plg$prof_psql_stats_profile_statement ))""", - "grant select, update, insert, delete on table plg$prof_psql_stats to plg$profiler", + "grant select, update, insert, delete on table plg$profiler.plg$prof_psql_stats to plg$profiler", R"""( - create table plg$prof_record_source_stats ( + create table plg$profiler.plg$prof_record_source_stats ( profile_id bigint not null constraint plg$prof_record_source_stats_session_fk - references plg$prof_sessions + references plg$profiler.plg$prof_sessions on delete cascade using index plg$prof_record_source_stats_profile_id, statement_id bigint not null, @@ -1164,38 +1199,84 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr< primary key (profile_id, statement_id, request_id, cursor_id, record_source_id) using index plg$prof_record_source_stats_profile_stat_req_cur_recsource, constraint plg$prof_record_source_stats_request_fk - foreign key (profile_id, statement_id, request_id) references plg$prof_requests + foreign key (profile_id, statement_id, request_id) references plg$profiler.plg$prof_requests on delete cascade using index plg$prof_record_source_stats_profile_request, constraint plg$prof_record_source_stats_statement_fk - foreign key (profile_id, statement_id) references plg$prof_statements + foreign key (profile_id, statement_id) references plg$profiler.plg$prof_statements on delete cascade using index plg$prof_record_source_stats_profile_statement, constraint plg$prof_record_source_stats_cursor_fk - foreign key (profile_id, statement_id, cursor_id) references plg$prof_cursors + foreign key (profile_id, statement_id, cursor_id) references plg$profiler.plg$prof_cursors on delete cascade using index plg$prof_record_source_stats_statement_cursor, constraint plg$prof_record_source_stats_record_source_fk - foreign key (profile_id, statement_id, cursor_id, record_source_id) references plg$prof_record_sources + foreign key (profile_id, statement_id, cursor_id, record_source_id) + references plg$profiler.plg$prof_record_sources on delete cascade using index plg$prof_record_source_stats_statement_cursor_record_source ))""", - "grant select, update, insert, delete on table plg$prof_record_source_stats to plg$profiler", + "grant select, update, insert, delete on table plg$profiler.plg$prof_record_source_stats to plg$profiler" + }; + + for (const auto createSql : createSqlStaments) + { + attachment->execute(status, transaction, 0, createSql, SQL_DIALECT_CURRENT, + nullptr, nullptr, nullptr, nullptr); + } + + recreateViews(status, attachment, transaction); + + transaction->commit(status); + transaction.clear(); +} + +void ProfilerPlugin::upgradeMetadataWithSchemaName(ThrowStatusExceptionWrapper* status, RefPtr attachment, + RefPtr transaction) +{ + constexpr const char* sqlStaments[] = { + R"""( + alter table plg$profiler.plg$prof_statements + add schema_name char(63) character set utf8 + )""", R"""( - create view plg$prof_statement_stats_view + alter table plg$profiler.plg$prof_statements + alter schema_name position 5 + )""" + }; + + for (const auto sqlStatement : sqlStaments) + { + attachment->execute(status, transaction, 0, sqlStatement, SQL_DIALECT_CURRENT, + nullptr, nullptr, nullptr, nullptr); + } + + recreateViews(status, attachment, transaction); + + transaction->commit(status); + transaction.clear(); +} + +void ProfilerPlugin::recreateViews(ThrowStatusExceptionWrapper* status, RefPtr attachment, + RefPtr transaction) +{ + constexpr const char* sqlStaments[] = { + R"""( + recreate view plg$profiler.plg$prof_statement_stats_view as select req.profile_id, req.statement_id, sta.statement_type, + sta.schema_name, sta.package_name, sta.routine_name, sta.parent_statement_id, sta_parent.statement_type parent_statement_type, sta_parent.routine_name parent_routine_name, (select sql_text - from plg$prof_statements + from plg$profiler.plg$prof_statements where profile_id = req.profile_id and statement_id = coalesce(sta.parent_statement_id, req.statement_id) ) sql_text, @@ -1204,16 +1285,17 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr< max(req.total_elapsed_time) max_elapsed_time, cast(sum(req.total_elapsed_time) as bigint) total_elapsed_time, cast(sum(req.total_elapsed_time) / count(*) as bigint) avg_elapsed_time - from plg$prof_requests req - join plg$prof_statements sta + from plg$profiler.plg$prof_requests req + join plg$profiler.plg$prof_statements sta on sta.profile_id = req.profile_id and sta.statement_id = req.statement_id - left join plg$prof_statements sta_parent + left join plg$profiler.plg$prof_statements sta_parent on sta_parent.profile_id = sta.profile_id and sta_parent.statement_id = sta.parent_statement_id group by req.profile_id, req.statement_id, sta.statement_type, + sta.schema_name, sta.package_name, sta.routine_name, sta.parent_statement_id, @@ -1222,21 +1304,22 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr< order by sum(req.total_elapsed_time) desc )""", - "grant select on table plg$prof_statement_stats_view to plg$profiler", + "grant select on table plg$profiler.plg$prof_statement_stats_view to plg$profiler", R"""( - create view plg$prof_psql_stats_view + recreate view plg$profiler.plg$prof_psql_stats_view as select pstat.profile_id, pstat.statement_id, sta.statement_type, + sta.schema_name, sta.package_name, sta.routine_name, sta.parent_statement_id, sta_parent.statement_type parent_statement_type, sta_parent.routine_name parent_routine_name, (select sql_text - from plg$prof_statements + from plg$profiler.plg$prof_statements where profile_id = pstat.profile_id and statement_id = coalesce(sta.parent_statement_id, pstat.statement_id) ) sql_text, @@ -1247,16 +1330,17 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr< max(pstat.max_elapsed_time) max_elapsed_time, cast(sum(pstat.total_elapsed_time) as bigint) total_elapsed_time, cast(sum(pstat.total_elapsed_time) / nullif(sum(pstat.counter), 0) as bigint) avg_elapsed_time - from plg$prof_psql_stats pstat - join plg$prof_statements sta + from plg$profiler.plg$prof_psql_stats pstat + join plg$profiler.plg$prof_statements sta on sta.profile_id = pstat.profile_id and sta.statement_id = pstat.statement_id - left join plg$prof_statements sta_parent + left join plg$profiler.plg$prof_statements sta_parent on sta_parent.profile_id = sta.profile_id and sta_parent.statement_id = sta.parent_statement_id group by pstat.profile_id, pstat.statement_id, sta.statement_type, + sta.schema_name, sta.package_name, sta.routine_name, sta.parent_statement_id, @@ -1267,21 +1351,22 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr< order by sum(pstat.total_elapsed_time) desc )""", - "grant select on table plg$prof_psql_stats_view to plg$profiler", + "grant select on table plg$profiler.plg$prof_psql_stats_view to plg$profiler", R"""( - create view plg$prof_record_source_stats_view + recreate view plg$profiler.plg$prof_record_source_stats_view as select rstat.profile_id, rstat.statement_id, sta.statement_type, + sta.schema_name, sta.package_name, sta.routine_name, sta.parent_statement_id, sta_parent.statement_type parent_statement_type, sta_parent.routine_name parent_routine_name, (select sql_text - from plg$prof_statements + from plg$profiler.plg$prof_statements where profile_id = rstat.profile_id and statement_id = coalesce(sta.parent_statement_id, rstat.statement_id) ) sql_text, @@ -1304,25 +1389,26 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr< cast(sum(rstat.fetch_total_elapsed_time) as bigint) fetch_total_elapsed_time, cast(sum(rstat.fetch_total_elapsed_time) / nullif(sum(rstat.fetch_counter), 0) as bigint) fetch_avg_elapsed_time, cast(coalesce(sum(rstat.open_total_elapsed_time), 0) + coalesce(sum(rstat.fetch_total_elapsed_time), 0) as bigint) open_fetch_total_elapsed_time - from plg$prof_record_source_stats rstat - join plg$prof_cursors cur + from plg$profiler.plg$prof_record_source_stats rstat + join plg$profiler.plg$prof_cursors cur on cur.profile_id = rstat.profile_id and cur.statement_id = rstat.statement_id and cur.cursor_id = rstat.cursor_id - join plg$prof_record_sources recsrc + join plg$profiler.plg$prof_record_sources recsrc on recsrc.profile_id = rstat.profile_id and recsrc.statement_id = rstat.statement_id and recsrc.cursor_id = rstat.cursor_id and recsrc.record_source_id = rstat.record_source_id - join plg$prof_statements sta + join plg$profiler.plg$prof_statements sta on sta.profile_id = rstat.profile_id and sta.statement_id = rstat.statement_id - left join plg$prof_statements sta_parent + left join plg$profiler.plg$prof_statements sta_parent on sta_parent.profile_id = sta.profile_id and sta_parent.statement_id = sta.parent_statement_id group by rstat.profile_id, rstat.statement_id, sta.statement_type, + sta.schema_name, sta.package_name, sta.routine_name, sta.parent_statement_id, @@ -1339,17 +1425,14 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr< order by coalesce(sum(rstat.open_total_elapsed_time), 0) + coalesce(sum(rstat.fetch_total_elapsed_time), 0) desc )""", - "grant select on table plg$prof_record_source_stats_view to plg$profiler" + "grant select on table plg$profiler.plg$prof_record_source_stats_view to plg$profiler" }; - for (const auto createSql : createSqlStaments) + for (const auto sqlStatement : sqlStaments) { - attachment->execute(status, transaction, 0, createSql, SQL_DIALECT_CURRENT, + attachment->execute(status, transaction, 0, sqlStatement, SQL_DIALECT_CURRENT, nullptr, nullptr, nullptr, nullptr); } - - transaction->commit(status); - transaction.clear(); } // Load objects in engine caches so they can be used in the user's transaction. @@ -1358,13 +1441,13 @@ void ProfilerPlugin::loadMetadata(ThrowStatusExceptionWrapper* status) constexpr auto loadObjectsSql = R"""( select * - from plg$prof_sessions - cross join plg$prof_statements - cross join plg$prof_record_sources - cross join plg$prof_requests - cross join plg$prof_psql_stats - cross join plg$prof_record_source_stats - where next value for plg$prof_profile_id = 0 + from plg$profiler.plg$prof_sessions + cross join plg$profiler.plg$prof_statements + cross join plg$profiler.plg$prof_record_sources + cross join plg$profiler.plg$prof_requests + cross join plg$profiler.plg$prof_psql_stats + cross join plg$profiler.plg$prof_record_source_stats + where next value for plg$profiler.plg$prof_profile_id = 0 )"""; auto transaction = makeNoIncRef(userAttachment->startTransaction(status, 0, nullptr)); @@ -1388,7 +1471,7 @@ Session::Session(ThrowStatusExceptionWrapper* status, ProfilerPlugin* aPlugin, ) sequenceMessage(status, MasterInterfacePtr()); sequenceMessage.clear(); - constexpr auto sequenceSql = "select next value for plg$prof_profile_id from rdb$database"; + constexpr auto sequenceSql = "select next value for plg$profiler.plg$prof_profile_id from system.rdb$database"; auto transaction = makeNoIncRef(plugin->userAttachment->startTransaction(status, 0, nullptr)); @@ -1427,8 +1510,8 @@ void Session::finish(ThrowStatusExceptionWrapper* status, ISC_TIMESTAMP_TZ times finishTimestamp = timestamp; } -void Session::defineStatement(ThrowStatusExceptionWrapper* status, SINT64 statementId, SINT64 parentStatementId, - const char* type, const char* packageName, const char* routineName, const char* sqlText) +void Session::defineStatement2(ThrowStatusExceptionWrapper* status, SINT64 statementId, SINT64 parentStatementId, + const char* type, const char* schemaName, const char* packageName, const char* routineName, const char* sqlText) { const auto statement = statements.put(statementId); fb_assert(statement); @@ -1437,6 +1520,7 @@ void Session::defineStatement(ThrowStatusExceptionWrapper* status, SINT64 statem return; statement->type = type; + statement->schemaName = schemaName; statement->packageName = packageName; statement->routineName = routineName; statement->parentStatementId = parentStatementId; diff --git a/src/remote/server/ReplServer.cpp b/src/remote/server/ReplServer.cpp index 3b12feee39..b985fc9cff 100644 --- a/src/remote/server/ReplServer.cpp +++ b/src/remote/server/ReplServer.cpp @@ -373,6 +373,9 @@ namespace dpb.insertString(isc_dpb_user_name, DBA_USER_NAME); dpb.insertString(isc_dpb_config, ParsedList::getNonLoopbackProviders(m_config->dbName)); + if (m_config->schemaSearchPath.hasData()) + dpb.insertString(isc_dpb_search_path, m_config->schemaSearchPath.c_str()); + #ifndef NO_DATABASE DispatcherPtr provider; FbLocalStatus localStatus; @@ -394,7 +397,7 @@ namespace localStatus.check(); const char* sql = - "select rdb$get_context('SYSTEM', 'REPLICATION_SEQUENCE') from rdb$database"; + "select rdb$get_context('SYSTEM', 'REPLICATION_SEQUENCE') from system.rdb$database"; FB_MESSAGE(Result, CheckStatusWrapper, (FB_BIGINT, sequence) diff --git a/src/utilities/fbsvcmgr/fbsvcmgr.cpp b/src/utilities/fbsvcmgr/fbsvcmgr.cpp index 08f56211a2..e3c06b1b16 100644 --- a/src/utilities/fbsvcmgr/fbsvcmgr.cpp +++ b/src/utilities/fbsvcmgr/fbsvcmgr.cpp @@ -598,6 +598,8 @@ const SvcSwitches traceChgStateOptions[] = const SvcSwitches validateOptions[] = { {"dbname", putStringArgument, 0, isc_spb_dbname, 0}, + {"val_sch_incl", putStringArgument, 0, isc_spb_val_sch_incl, 0}, + {"val_sch_excl", putStringArgument, 0, isc_spb_val_sch_excl, 0}, {"val_tab_incl", putStringArgument, 0, isc_spb_val_tab_incl, 0}, {"val_tab_excl", putStringArgument, 0, isc_spb_val_tab_excl, 0}, {"val_idx_incl", putStringArgument, 0, isc_spb_val_idx_incl, 0}, diff --git a/src/utilities/gstat/dba.epp b/src/utilities/gstat/dba.epp index 5bf89a5d4b..b529cb4abf 100644 --- a/src/utilities/gstat/dba.epp +++ b/src/utilities/gstat/dba.epp @@ -752,6 +752,8 @@ int gstat(Firebird::UtilSvc* uSvc) if (*role) dpb.insertString(isc_dpb_sql_role_name, role, fb_strlen(role)); + dpb.insertString(isc_dpb_search_path, SYSTEM_SCHEMA, fb_strlen(SYSTEM_SCHEMA)); + isc_attach_database(status_vector, 0, connName.c_str(), &DB, dpb.getBufferLength(), reinterpret_cast(dpb.getBuffer())); if (status_vector[1]) diff --git a/src/utilities/gstat/dbaswi.h b/src/utilities/gstat/dbaswi.h index fee77236a5..fe18dd79aa 100644 --- a/src/utilities/gstat/dbaswi.h +++ b/src/utilities/gstat/dbaswi.h @@ -65,7 +65,7 @@ const static struct Switches::in_sw_tab_t dba_in_sw_table[] = {IN_SW_DBA_PASSWORD, 0, "PASSWORD", 0,0,0, false, false, 33, 1, NULL}, // msg 33: -p password {IN_SW_DBA_FETCH_PASS, 0, "FETCH_PASSWORD", 0,0,0, false, false, 37, 2, NULL}, // msg 37: -fetch fetch password from file {IN_SW_DBA_RECORD, isc_spb_sts_record_versions,"RECORD", 0,0,0, false, true, 34, 1, NULL}, // msg 34: -r analyze average record and version length - {IN_SW_DBA_RELATION, isc_spb_sts_table, "TABLE", 0,0,0, false, false, 35, 1, NULL}, // msg 35: -t tablename + {IN_SW_DBA_RELATION, isc_spb_sts_table, "TABLE", 0,0,0, false, false, 35, 1, NULL}, // msg 35: -t tablename // FIXME: schema {IN_SW_DBA_RELATION, isc_spb_sts_table, "TABLE", 0,0,0, false, true, 0, 1, NULL}, // no msg: let run old buggy code {IN_SW_DBA_ROLE, 0, "ROLE", 0,0,0, false, false, 57, 1, NULL}, // msg 57: -role SQL role name // special switch to avoid including creation date, only for tests (no message) diff --git a/src/utilities/ntrace/paramtable.h b/src/utilities/ntrace/paramtable.h index 29e4d84fe7..827056dbbb 100644 --- a/src/utilities/ntrace/paramtable.h +++ b/src/utilities/ntrace/paramtable.h @@ -32,6 +32,8 @@ // DATABASE_PARAMS, SERVICE_PARAMS +STR_PARAMETER(include_schema_filter, "") +STR_PARAMETER(exclude_schema_filter, "") STR_PARAMETER(include_filter, "") STR_PARAMETER(exclude_filter, "") PATH_PARAMETER(log_filename, "") diff --git a/src/yvalve/YObjects.h b/src/yvalve/YObjects.h index c2ea484350..087a2011f3 100644 --- a/src/yvalve/YObjects.h +++ b/src/yvalve/YObjects.h @@ -518,6 +518,7 @@ public: void destroy(unsigned dstrFlags); void shutdown(); isc_db_handle& getHandle(); + void getOdsVersion(USHORT* majorVersion, USHORT* minorVersion); // IAttachment implementation void getInfo(Firebird::CheckStatusWrapper* status, unsigned int itemsLength, @@ -590,6 +591,10 @@ public: HandleArray childTransactions; Firebird::Array cleanupHandlers; Firebird::StatusHolder savedStatus; // Do not use raise() method of this class in yValve. + +private: + USHORT cachedOdsMajorVersion = 0; + USHORT cachedOdsMinorVersion = 0; }; class YService final : @@ -679,9 +684,20 @@ public: Firebird::ITransaction* tra, const char* file, FB_BOOLEAN txt); void getPerfCounters(Firebird::CheckStatusWrapper* status, Firebird::IAttachment* att, const char* countersSet, ISC_INT64* counters); // in perf.cpp + YAttachment* executeCreateDatabase(Firebird::CheckStatusWrapper* status, unsigned stmtLength, const char* creatDBstatement, unsigned dialect, - FB_BOOLEAN* stmtIsCreateDb = NULL); + FB_BOOLEAN* stmtIsCreateDb = nullptr) + { + return executeCreateDatabase2(status, stmtLength, creatDBstatement, dialect, + 0, nullptr, stmtIsCreateDb); + } + + YAttachment* executeCreateDatabase2(Firebird::CheckStatusWrapper* status, + unsigned stmtLength, const char* creatDBstatement, unsigned dialect, + unsigned dpbLength, const unsigned char* dpb, + FB_BOOLEAN* stmtIsCreateDb = nullptr); + void decodeDate(ISC_DATE date, unsigned* year, unsigned* month, unsigned* day); void decodeTime(ISC_TIME time, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions); diff --git a/src/yvalve/array.cpp b/src/yvalve/array.cpp index 6f2ca65677..df0e13613b 100644 --- a/src/yvalve/array.cpp +++ b/src/yvalve/array.cpp @@ -153,7 +153,27 @@ void iscArrayLookupBoundsImpl(Why::YAttachment* attachment, ISC_ARRAY_BOUND* tail = desc->array_desc_bounds; - constexpr auto sql = R"""( + USHORT majorOdsVersion = 0; + USHORT minorOdsVersion = 0; + attachment->getOdsVersion(&majorOdsVersion, &minorOdsVersion); + + constexpr auto sqlSchemas = R"""( + with search_path as ( + select row_number() over () rn, + name + from system.rdb$sql.parse_unqualified_names(rdb$get_context('SYSTEM', 'SEARCH_PATH')) + ) + select fd.rdb$lower_bound, + fd.rdb$upper_bound + from search_path sp + join system.rdb$field_dimensions fd + on fd.rdb$schema_name = sp.name + where fd.rdb$field_name = ? + order by sp.rn + rows 1 + )"""; + + constexpr auto sqlNoSchemas = R"""( select fd.rdb$lower_bound, fd.rdb$upper_bound from rdb$field_dimensions fd @@ -161,6 +181,8 @@ void iscArrayLookupBoundsImpl(Why::YAttachment* attachment, order by fd.rdb$dimension )"""; + const auto sql = majorOdsVersion >= ODS_VERSION14 ? sqlSchemas : sqlNoSchemas; + FB_MESSAGE(InputMessage, CheckStatusWrapper, (FB_VARCHAR(MAX_SQL_IDENTIFIER_LEN), fieldName) ) inputMessage(&statusWrapper, MasterInterfacePtr()); @@ -202,7 +224,34 @@ void iscArrayLookupDescImpl(Why::YAttachment* attachment, desc->array_desc_flags = 0; - constexpr auto sql = R"""( + USHORT majorOdsVersion = 0; + USHORT minorOdsVersion = 0; + attachment->getOdsVersion(&majorOdsVersion, &minorOdsVersion); + + constexpr auto sqlSchemas = R"""( + with search_path as ( + select row_number() over () rn, + name + from system.rdb$sql.parse_unqualified_names(rdb$get_context('SYSTEM', 'SEARCH_PATH')) + ) + select f.rdb$field_name, + f.rdb$field_type, + f.rdb$field_scale, + f.rdb$field_length, + f.rdb$dimensions + from search_path sp + join system.rdb$relation_fields rf + on rf.rdb$schema_name = sp.name + join system.rdb$fields f + on f.rdb$schema_name = rf.rdb$field_source_schema_name and + f.rdb$field_name = rf.rdb$field_source + where rf.rdb$relation_name = ? and + rf.rdb$field_name = ? + order by sp.rn + rows 1 + )"""; + + constexpr auto sqlNoSchemas = R"""( select f.rdb$field_name, f.rdb$field_type, f.rdb$field_scale, @@ -215,6 +264,8 @@ void iscArrayLookupDescImpl(Why::YAttachment* attachment, rf.rdb$field_name = ? )"""; + const auto sql = majorOdsVersion >= ODS_VERSION14 ? sqlSchemas : sqlNoSchemas; + FB_MESSAGE(InputMessage, CheckStatusWrapper, (FB_VARCHAR(MAX_SQL_IDENTIFIER_LEN), relationName) (FB_VARCHAR(MAX_SQL_IDENTIFIER_LEN), fieldName) diff --git a/src/yvalve/blob.cpp b/src/yvalve/blob.cpp index 6449e27be8..4689ddfffd 100644 --- a/src/yvalve/blob.cpp +++ b/src/yvalve/blob.cpp @@ -141,8 +141,33 @@ void iscBlobLookupDescImpl(Why::YAttachment* attachment, Why::YTransaction* tran (FB_INTEGER, characterSetId) ) outputMessage(&statusWrapper, MasterInterfacePtr()); + USHORT majorOdsVersion = 0; + USHORT minorOdsVersion = 0; + attachment->getOdsVersion(&majorOdsVersion, &minorOdsVersion); + { // scope - constexpr auto sql = R"""( + constexpr auto sqlSchemas = R"""( + with search_path as ( + select row_number() over () rn, + name + from system.rdb$sql.parse_unqualified_names(rdb$get_context('SYSTEM', 'SEARCH_PATH')) + ) + select f.rdb$field_sub_type, + f.rdb$segment_length, + f.rdb$character_set_id + from search_path sp + join system.rdb$relation_fields rf + on rf.rdb$schema_name = sp.name + join system.rdb$fields f + on f.rdb$schema_name = rf.rdb$field_source_schema_name and + f.rdb$field_name = rf.rdb$field_source + where rf.rdb$relation_name = ? and + rf.rdb$field_name = ? + order by sp.rn + rows 1 + )"""; + + constexpr auto sqlNoSchemas = R"""( select f.rdb$field_sub_type, f.rdb$segment_length, f.rdb$character_set_id @@ -153,6 +178,8 @@ void iscBlobLookupDescImpl(Why::YAttachment* attachment, Why::YTransaction* tran rf.rdb$field_name = ? )"""; + const auto sql = majorOdsVersion >= ODS_VERSION14 ? sqlSchemas : sqlNoSchemas; + FB_MESSAGE(InputMessage, CheckStatusWrapper, (FB_VARCHAR(MAX_SQL_IDENTIFIER_LEN), relationName) (FB_VARCHAR(MAX_SQL_IDENTIFIER_LEN), fieldName) @@ -184,7 +211,29 @@ void iscBlobLookupDescImpl(Why::YAttachment* attachment, Why::YTransaction* tran if (!flag) { - constexpr auto sql = R"""( + constexpr auto sqlSchemas = R"""( + with search_path as ( + select row_number() over () rn, + name + from system.rdb$sql.parse_unqualified_names(rdb$get_context('SYSTEM', 'SEARCH_PATH')) + ) + select f.rdb$field_sub_type, + f.rdb$segment_length, + f.rdb$character_set_id + from search_path sp + join system.rdb$procedure_parameters pp + on pp.rdb$schema_name = sp.name + join system.rdb$fields f + on f.rdb$schema_name = pp.rdb$field_source_schema_name and + f.rdb$field_name = pp.rdb$field_source + where pp.rdb$procedure_name = ? and + pp.rdb$parameter_name = ? and + pp.rdb$package_name is null + order by sp.rn + rows 1 + )"""; + + constexpr auto sqlNoSchemas = R"""( select f.rdb$field_sub_type, f.rdb$segment_length, f.rdb$character_set_id @@ -196,6 +245,8 @@ void iscBlobLookupDescImpl(Why::YAttachment* attachment, Why::YTransaction* tran pp.rdb$package_name is null )"""; + const auto sql = majorOdsVersion >= ODS_VERSION14 ? sqlSchemas : sqlNoSchemas; + FB_MESSAGE(InputMessage, CheckStatusWrapper, (FB_VARCHAR(MAX_SQL_IDENTIFIER_LEN), procedureName) (FB_VARCHAR(MAX_SQL_IDENTIFIER_LEN), fieldName) diff --git a/src/yvalve/gds.cpp b/src/yvalve/gds.cpp index 7071c8cec2..0d04ba2b09 100644 --- a/src/yvalve/gds.cpp +++ b/src/yvalve/gds.cpp @@ -353,6 +353,10 @@ static const UCHAR relation[] = { op_byte, op_literal, op_pad, op_byte, op_line, 0}, relation2[] = { op_byte, op_literal, op_line, op_indent, op_byte, op_literal, op_pad, op_byte, op_line, 0}, + relation3[] = { op_line, op_indent, op_byte, op_literal, + op_line, op_indent, op_byte, op_literal, + op_line, op_indent, op_byte, op_literal, + op_line, op_indent, op_byte, op_line, 0}, aggregate[] = { op_byte, op_line, op_verb, op_verb, op_verb, 0}, rid[] = { op_word, op_byte, op_line, 0}, rid2[] = { op_word, op_byte, op_literal, op_pad, op_byte, op_line, 0}, @@ -363,6 +367,8 @@ static const UCHAR op_args, 0}, gen_id[] = { op_byte, op_literal, op_line, op_verb, 0}, gen_id2[] = { op_byte, op_literal, op_line, 0}, + gen_id3[] = { op_line, op_indent, op_byte, op_literal, op_line, op_indent, op_byte, op_literal, + op_line, op_indent, op_byte_opt_verb, 0}, declare[] = { op_word, op_dtype, op_line, 0}, one_word[] = { op_word, op_line, 0}, indx[] = { op_line, op_verb, op_indent, op_byte, op_line, op_args, 0}, @@ -420,7 +426,11 @@ static const UCHAR in_list[] = { op_line, op_verb, op_indent, op_word, op_line, op_args, 0}, invoke_function[] = { op_invoke_function, 0 }, invsel_procedure[] = { op_invsel_procedure, 0 }, - cast_format[] = { op_line, op_indent, op_byte, op_literal, op_line, op_indent, op_dtype, op_line, op_verb, 0 }; + cast_format[] = { op_line, op_indent, op_byte, op_literal, op_line, op_indent, op_dtype, op_line, op_verb, 0 }, + default2[] = { op_line, op_indent, op_byte, op_literal, + op_line, op_indent, op_byte, op_literal, + op_line, op_indent, op_byte, op_literal, + op_pad, op_line, 0}; #include "../jrd/blp.h" @@ -2168,6 +2178,57 @@ int API_ROUTINE fb_print_blr(const UCHAR* blr, ULONG blr_length, SSHORT level = 0; SLONG offset = 0; blr_print_line(control, (SSHORT) offset); + + if (control->ctl_blr_reader.getByte() == blr_flags) + { + blr_format(control, "blr_flags,"); + ++level; + + static const char* subCodes[] = + { + nullptr, + "search_system_schema" + }; + + UCHAR code; + + while ((code = control->ctl_blr_reader.getByte()) != blr_end) + { + offset = blr_print_line(control, offset); + blr_indent(control, level); + + if (code == 0 || code >= FB_NELEM(subCodes)) + { + control->ctl_blr_reader.seekBackward(1); + blr_print_byte(control); + } + else + blr_format(control, "blr_flags_%s, ", subCodes[code]); + + auto len = blr_print_word(control); + + if (len > 0) + { + offset = blr_print_line(control, offset); + blr_indent(control, level + 1); + + while (len > 0) + { + blr_print_byte(control); + --len; + } + } + } + + // print blr_end + offset = blr_print_line(control, offset); + control->ctl_blr_reader.seekBackward(1); + blr_print_verb(control, level); + --level; + } + else + control->ctl_blr_reader.seekBackward(1); + blr_print_verb(control, level); offset = control->ctl_blr_reader.getOffset(); @@ -3010,6 +3071,46 @@ static void blr_print_cond(gds_ctl* control, SSHORT level) blr_print_char(control); break; + case blr_exception2: + blr_format(control, "blr_exception2, "); + blr_print_line(control, (SSHORT) offset); + blr_indent(control, level); + n = blr_print_byte(control); + while (--n >= 0) + blr_print_char(control); + blr_print_line(control, (SSHORT) offset); + blr_indent(control, level); + n = blr_print_byte(control); + while (--n >= 0) + blr_print_char(control); + break; + + case blr_exception3: + blr_format(control, "blr_exception3, "); + blr_print_line(control, (SSHORT) offset); + blr_indent(control, level); + n = blr_print_byte(control); + while (--n >= 0) + blr_print_char(control); + blr_print_line(control, (SSHORT) offset); + blr_indent(control, level); + n = blr_print_byte(control); + while (--n >= 0) + blr_print_char(control); + blr_print_line(control, (SSHORT) offset); + blr_indent(control, level); + n = blr_print_byte(control); + if (n == 0) + blr_print_line(control, (SSHORT) offset); + else + blr_print_verb(control, 0); + blr_indent(control, level); + n = blr_print_word(control); + blr_print_line(control, (SSHORT) offset); + while (--n >= 0) + blr_print_verb(control, level); + break; + case blr_exception_msg: blr_format(control, "blr_exception_msg, "); n = blr_print_byte(control); @@ -3205,6 +3306,13 @@ static int blr_print_dtype(gds_ctl* control) length = 0; break; + case blr_domain_name3: + string = "domain_name3"; + // Don't bother with this length. + // It will not be used for blr_domain_name3. + length = 0; + break; + case blr_column_name: string = "column_name"; // Don't bother with this length. @@ -3219,6 +3327,13 @@ static int blr_print_dtype(gds_ctl* control) length = 0; break; + case blr_column_name3: + string = "column_name3"; + // Don't bother with this length. + // It will not be used for blr_column_name3. + length = 0; + break; + case blr_not_nullable: string = "not_nullable"; break; @@ -3278,13 +3393,23 @@ static int blr_print_dtype(gds_ctl* control) case blr_domain_name: case blr_domain_name2: + case blr_domain_name3: case blr_column_name: case blr_column_name2: + case blr_column_name3: { // 0 = blr_domain_type_of; 1 = blr_domain_full blr_print_byte(control); - if (dtype == blr_column_name || dtype == blr_column_name2) + if (dtype == blr_domain_name3 || dtype == blr_column_name3) + { + for (UCHAR n = blr_print_byte(control); n > 0; --n) + blr_print_char(control); + + blr_format(control, " "); + } + + if (dtype == blr_column_name || dtype == blr_column_name2 || dtype == blr_column_name3) { for (UCHAR n = blr_print_byte(control); n > 0; --n) blr_print_char(control); @@ -3295,7 +3420,12 @@ static int blr_print_dtype(gds_ctl* control) for (UCHAR n = blr_print_byte(control); n > 0; --n) blr_print_char(control); - if (dtype == blr_domain_name2 || dtype == blr_column_name2) + bool hasTextType = dtype == blr_domain_name2 || dtype == blr_column_name2; + + if (dtype == blr_domain_name3 || dtype == blr_column_name3) + hasTextType = blr_print_byte(control) != 0; + + if (hasTextType) blr_print_word(control); break; @@ -3530,6 +3660,7 @@ static void blr_print_verb(gds_ctl* control, SSHORT level) } break; + // FIXME: blr_relation3 case op_relation: blr_operator = control->ctl_blr_reader.getByte(); blr_print_blr(control, blr_operator); @@ -4003,11 +4134,12 @@ static void blr_print_verb(gds_ctl* control, SSHORT level) "args" }; - static const char* typeSubCodes[] = + static const char* idSubCodes[] = { nullptr, - "standalone", - "packaged", + "schema", + "package", + "name", "sub" }; @@ -4022,26 +4154,28 @@ static void blr_print_verb(gds_ctl* control, SSHORT level) switch (blr_operator) { - case blr_invoke_function_type: - n = control->ctl_blr_reader.getByte(); + case blr_invoke_function_id: + ++level; - if (n == 0 || n >= static_cast(FB_NELEM(typeSubCodes))) - blr_error(control, "*** invalid blr_invoke_function_type sub code ***"); - - blr_format(control, "blr_invoke_function_type_%s,", typeSubCodes[n]); - offset = blr_print_line(control, (SSHORT) offset); - - blr_indent(control, level + 1); - blr_print_name(control); - offset = blr_print_line(control, (SSHORT) offset); - - if (n == blr_invoke_function_type_packaged) + while ((n = control->ctl_blr_reader.getByte()) != blr_end) { - blr_indent(control, level + 1); - blr_print_name(control); + if (n == 0 || n >= static_cast(FB_NELEM(idSubCodes))) + blr_error(control, "*** invalid blr_invoke_function_id sub code ***"); + offset = blr_print_line(control, (SSHORT) offset); + blr_indent(control, level + 1); + blr_format(control, "blr_invoke_function_id_%s, ", idSubCodes[n]); + + if (n == blr_invoke_function_id_schema || + n == blr_invoke_function_id_package || + n == blr_invoke_function_id_name) + { + blr_print_name(control); + } } + offset = blr_print_line(control, (SSHORT) offset); + --level; break; case blr_invoke_function_arg_names: @@ -4090,7 +4224,7 @@ static void blr_print_verb(gds_ctl* control, SSHORT level) static const char* subCodes[] = { nullptr, - "type", + "id", "in_arg_names", "in_args", "out_arg_names", @@ -4101,11 +4235,12 @@ static void blr_print_verb(gds_ctl* control, SSHORT level) "alias" }; - static const char* typeSubCodes[] = + static const char* idSubCodes[] = { nullptr, - "standalone", - "packaged", + "schema", + "package", + "name", "sub" }; @@ -4120,26 +4255,28 @@ static void blr_print_verb(gds_ctl* control, SSHORT level) switch (blr_operator) { - case blr_invsel_procedure_type: - n = control->ctl_blr_reader.getByte(); + case blr_invsel_procedure_id: + ++level; - if (n == 0 || n >= static_cast(FB_NELEM(typeSubCodes))) - blr_error(control, "*** invalid blr_invsel_procedure_type sub code ***"); - - blr_format(control, "blr_invsel_procedure_type_%s,", typeSubCodes[n]); - offset = blr_print_line(control, (SSHORT) offset); - - blr_indent(control, level + 1); - blr_print_name(control); - offset = blr_print_line(control, (SSHORT) offset); - - if (n == blr_invsel_procedure_type_packaged) + while ((n = control->ctl_blr_reader.getByte()) != blr_end) { - blr_indent(control, level + 1); - blr_print_name(control); + if (n == 0 || n >= static_cast(FB_NELEM(idSubCodes))) + blr_error(control, "*** invalid blr_invsel_procedure_id sub code ***"); + offset = blr_print_line(control, (SSHORT) offset); + blr_indent(control, level + 1); + blr_format(control, "blr_invsel_procedure_id_%s, ", idSubCodes[n]); + + if (n == blr_invsel_procedure_id_schema || + n == blr_invsel_procedure_id_package || + n == blr_invsel_procedure_id_name) + { + blr_print_name(control); + } } + offset = blr_print_line(control, (SSHORT) offset); + --level; break; case blr_invsel_procedure_in_arg_names: diff --git a/src/yvalve/prepa_proto.h b/src/yvalve/prepa_proto.h index 3002368692..32fbc7e771 100644 --- a/src/yvalve/prepa_proto.h +++ b/src/yvalve/prepa_proto.h @@ -31,6 +31,7 @@ namespace Why { class YAttachment; } -bool PREPARSE_execute(Firebird::CheckStatusWrapper*, Why::YAttachment**, Firebird::string&, bool*, USHORT); +bool PREPARSE_execute(Firebird::CheckStatusWrapper*, Why::YAttachment**, Firebird::string&, bool*, USHORT, + unsigned dpbLength, const unsigned char* dpb); #endif // DSQL_PREPA_PROTO_H diff --git a/src/yvalve/preparse.cpp b/src/yvalve/preparse.cpp index 3e133f325a..9f7129acae 100644 --- a/src/yvalve/preparse.cpp +++ b/src/yvalve/preparse.cpp @@ -36,19 +36,18 @@ enum pp_vals { PP_CREATE = 0, - PP_DATABASE = 1, - PP_SCHEMA = 2, - PP_PAGE_SIZE = 3, - PP_USER = 4, - PP_PASSWORD = 5, - PP_PAGESIZE = 6, - PP_LENGTH = 7, - PP_PAGES = 8, - PP_PAGE = 9, - PP_SET = 10, - PP_NAMES = 11, - PP_ROLE = 12, - PP_OWNER = 13 + PP_DATABASE, + PP_PAGE_SIZE, + PP_USER, + PP_PASSWORD, + PP_PAGESIZE, + PP_LENGTH, + PP_PAGES, + PP_PAGE, + PP_SET, + PP_NAMES, + PP_ROLE, + PP_OWNER }; @@ -61,12 +60,10 @@ struct pp_table }; // This should be kept in sync with the rule db_initial_desc of parse.y for CREATE DATABASE. -// Should delete SCHEMA in the future. static const pp_table pp_symbols[] = { {"CREATE", PP_CREATE}, {"DATABASE", PP_DATABASE}, - {"SCHEMA", PP_SCHEMA}, {"PAGE_SIZE", PP_PAGE_SIZE}, {"USER", PP_USER}, {"PASSWORD", PP_PASSWORD}, @@ -158,7 +155,7 @@ static NoCaseString getToken(unsigned& pos, const Tokens& toks, int symbol = SYM **/ bool PREPARSE_execute(CheckStatusWrapper* status, Why::YAttachment** ptrAtt, - string& stmt, bool* stmt_eaten, USHORT dialect) + string& stmt, bool* stmt_eaten, USHORT dialect, unsigned dpbLength, const unsigned char* dpb) { // no use creating separate pool for a couple of strings ContextPoolHolder context(getDefaultMemoryPool()); @@ -219,17 +216,15 @@ bool PREPARSE_execute(CheckStatusWrapper* status, Why::YAttachment** ptrAtt, } NoCaseString token(getToken(pos, tks)); - if (token != pp_symbols[PP_DATABASE].symbol && token != pp_symbols[PP_SCHEMA].symbol) - { + if (token != pp_symbols[PP_DATABASE].symbol) return false; - } PathName file_name(getToken(pos, tks, STRING).ToPathName()); *stmt_eaten = false; - ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE); + ClumpletWriter dpbWriter(ClumpletReader::dpbList, MAX_DPB_SIZE, dpb, dpbLength); - dpb.insertByte(isc_dpb_overwrite, 0); - dpb.insertInt(isc_dpb_sql_dialect, dialect); + dpbWriter.insertByte(isc_dpb_overwrite, 0); + dpbWriter.insertInt(isc_dpb_sql_dialect, dialect); SLONG page_size = 0; bool matched; @@ -263,14 +258,14 @@ bool PREPARSE_execute(CheckStatusWrapper* status, Why::YAttachment** ptrAtt, token = getToken(pos, tks, NUMERIC); page_size = token.length() > 8 ? 100000000 : atol(token.c_str()); - dpb.insertInt(isc_dpb_page_size, page_size); + dpbWriter.insertInt(isc_dpb_page_size, page_size); matched = true; break; case PP_USER: token = getToken(pos, tks, qStrip ? STRING : SYMBOL); - dpb.insertString(isc_dpb_user_name, token.ToString()); + dpbWriter.insertString(isc_dpb_user_name, token.ToString()); matched = true; hasUser = true; break; @@ -278,14 +273,14 @@ bool PREPARSE_execute(CheckStatusWrapper* status, Why::YAttachment** ptrAtt, case PP_PASSWORD: token = getToken(pos, tks, STRING); - dpb.insertString(isc_dpb_password, token.ToString()); + dpbWriter.insertString(isc_dpb_password, token.ToString()); matched = true; break; case PP_ROLE: token = getToken(pos, tks); - dpb.insertString(isc_dpb_sql_role_name, token.ToString()); + dpbWriter.insertString(isc_dpb_sql_role_name, token.ToString()); matched = true; break; @@ -295,7 +290,7 @@ bool PREPARSE_execute(CheckStatusWrapper* status, Why::YAttachment** ptrAtt, generate_error(token, UNEXPECTED_TOKEN); token = getToken(pos, tks, STRING); - dpb.insertString(isc_dpb_lc_ctype, token.ToString()); + dpbWriter.insertString(isc_dpb_lc_ctype, token.ToString()); matched = true; break; @@ -316,7 +311,7 @@ bool PREPARSE_execute(CheckStatusWrapper* status, Why::YAttachment** ptrAtt, case PP_OWNER: token = getToken(pos, tks); - dpb.insertString(isc_dpb_owner, token); + dpbWriter.insertString(isc_dpb_owner, token); matched = true; break; } // switch @@ -326,7 +321,7 @@ bool PREPARSE_execute(CheckStatusWrapper* status, Why::YAttachment** ptrAtt, RefPtr dispatcher(FB_NEW Why::Dispatcher); *ptrAtt = dispatcher->createDatabase(status, file_name.c_str(), - dpb.getBufferLength(), dpb.getBuffer()); + dpbWriter.getBufferLength(), dpbWriter.getBuffer()); if ((!hasUser) || ((status->getState() & IStatus::STATE_ERRORS) == 0) || (status->getErrors()[1] != isc_login)) diff --git a/src/yvalve/utl.cpp b/src/yvalve/utl.cpp index c2946a7eb7..06245e7ead 100644 --- a/src/yvalve/utl.cpp +++ b/src/yvalve/utl.cpp @@ -117,7 +117,6 @@ const int BSTR_input = 0; const int BSTR_output = 1; const int BSTR_alloc = 2; -static void get_ods_version(CheckStatusWrapper*, IAttachment*, USHORT*, USHORT*); static void isc_expand_dpb_internal(const UCHAR** dpb, SSHORT* dpb_size, ...); @@ -556,7 +555,7 @@ void UtilInterface::getFbVersion(CheckStatusWrapper* status, IAttachment* att, } USHORT ods_version, ods_minor_version; - get_ods_version(status, att, &ods_version, &ods_minor_version); + UTL_get_ods_version(status, att, &ods_version, &ods_minor_version); if (status->getState() & Firebird::IStatus::STATE_ERRORS) return; @@ -569,9 +568,9 @@ void UtilInterface::getFbVersion(CheckStatusWrapper* status, IAttachment* att, } } -YAttachment* UtilInterface::executeCreateDatabase( +YAttachment* UtilInterface::executeCreateDatabase2( Firebird::CheckStatusWrapper* status, unsigned stmtLength, const char* creatDBstatement, - unsigned dialect, FB_BOOLEAN* stmtIsCreateDb) + unsigned dialect, unsigned dpbLength, const unsigned char* dpb, FB_BOOLEAN* stmtIsCreateDb) { try { @@ -584,7 +583,7 @@ YAttachment* UtilInterface::executeCreateDatabase( string statement(creatDBstatement, (stmtLength == 0 && creatDBstatement ? strlen(creatDBstatement) : stmtLength)); - if (!PREPARSE_execute(status, &att, statement, &stmtEaten, dialect)) + if (!PREPARSE_execute(status, &att, statement, &stmtEaten, dialect, dpbLength, dpb)) return NULL; if (stmtIsCreateDb) @@ -2947,7 +2946,7 @@ int API_ROUTINE gds__thread_start(FPTR_INT_VOID_PTR* entrypoint, #endif -static void get_ods_version(CheckStatusWrapper* status, IAttachment* att, +void UTL_get_ods_version(CheckStatusWrapper* status, IAttachment* att, USHORT* ods_version, USHORT* ods_minor_version) { /************************************** diff --git a/src/yvalve/utl_proto.h b/src/yvalve/utl_proto.h index e9600f45d4..789e3711cd 100644 --- a/src/yvalve/utl_proto.h +++ b/src/yvalve/utl_proto.h @@ -84,6 +84,9 @@ void setLogin(Firebird::ClumpletWriter& dpb, bool spbFlag); // Put status vector strings into strings circular buffer void makePermanentVector(ISC_STATUS* v) noexcept; +void UTL_get_ods_version(Firebird::CheckStatusWrapper* status, Firebird::IAttachment* att, + USHORT* ods_version, USHORT* ods_minor_version); + namespace Why { void threadCleanup(); diff --git a/src/yvalve/why.cpp b/src/yvalve/why.cpp index 2aff649f03..c750a2700c 100644 --- a/src/yvalve/why.cpp +++ b/src/yvalve/why.cpp @@ -150,6 +150,7 @@ public: unsigned getCount(CheckStatusWrapper* status); const char* getField(CheckStatusWrapper* status, unsigned index); + const char* getSchema(CheckStatusWrapper* status, unsigned index); const char* getRelation(CheckStatusWrapper* status, unsigned index); const char* getOwner(CheckStatusWrapper* status, unsigned index); const char* getAlias(CheckStatusWrapper* status, unsigned index); @@ -269,6 +270,11 @@ const char* SQLDAMetadata::getField(CheckStatusWrapper* status, unsigned index) return ""; // Old conversion sqlda->BLR->metadata dropped them anyway } +const char* SQLDAMetadata::getSchema(CheckStatusWrapper* status, unsigned index) +{ + return ""; +} + const char* SQLDAMetadata::getRelation(CheckStatusWrapper* status, unsigned index) { if (sqlda) @@ -5549,6 +5555,22 @@ isc_db_handle& YAttachment::getHandle() return handle; } +void YAttachment::getOdsVersion(USHORT* majorVersion, USHORT* minorVersion) +{ + if (cachedOdsMajorVersion == 0) + { + FbLocalStatus status; + return UTL_get_ods_version(&status, this, &cachedOdsMajorVersion, &cachedOdsMinorVersion); + status.check(); + } + + if (majorVersion) + *majorVersion = cachedOdsMajorVersion; + + if (minorVersion) + *minorVersion = cachedOdsMinorVersion; +} + YAttachment::~YAttachment() { if (provider)