diff --git a/builds/install/misc/replication.conf b/builds/install/misc/replication.conf
index f04a65bf6b3..571b2609f39 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 18c9bbba9d1..73eb3cbb942 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 b0e5eebb49a..9722a400104 100644
--- a/builds/win32/msvc15/common.vcxproj.filters
+++ b/builds/win32/msvc15/common.vcxproj.filters
@@ -449,9 +449,6 @@
headers
-
- headers
-
headers
@@ -611,6 +608,9 @@
headers
+
+ headers
+
headers
diff --git a/builds/win32/msvc15/common_test.vcxproj b/builds/win32/msvc15/common_test.vcxproj
index 8ba6d3fc3e5..85d411e9946 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 3e8ce6deae8..cf423d69fd9 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 4d7ee049960..3fc48f6d135 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.txt b/doc/sql.extensions/README.ddl.txt
index 19ca28c3c84..6bbbbdffb0a 100644
--- a/doc/sql.extensions/README.ddl.txt
+++ b/doc/sql.extensions/README.ddl.txt
@@ -569,7 +569,7 @@ With support for various system privileges in engine it's getting very convenien
rights to users already having specific system privilege. Therefore appropriate grantee type is
suppoprted now. Example:
-GRANT ALL ON PLG$SRP_VIEW TO SYSTEM PRIVILEGE USER_MANAGEMENT
+GRANT ALL ON PLG$SRP.PLG$SRP_VIEW TO SYSTEM PRIVILEGE USER_MANAGEMENT
Grants all rights to view (used in SRP management plugin) to users having USER_MANAGEMENT privilege.
@@ -715,6 +715,6 @@ ALTER TABLE
ADD CONSTRAINT [IF NOT EXISTS] ...
CREATE [UNIQUE] [ASC[ENDING] | DESC[ENDING]]
INDEX indexname [{ACTIVE | INACTIVE}]
ON tablename {(col [, col ...]) | COMPUTED BY ()}
- [WHERE ]
+ [WHERE ]
'isql -x' generates script accordingly.
diff --git a/doc/sql.extensions/README.ddl_triggers.txt b/doc/sql.extensions/README.ddl_triggers.txt
index 1ddcd8c1ba9..a146f94a333 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.name_resolution.md b/doc/sql.extensions/README.name_resolution.md
new file mode 100644
index 00000000000..509a5d2528d
--- /dev/null
+++ b/doc/sql.extensions/README.name_resolution.md
@@ -0,0 +1,68 @@
+# Name resolution (FB 6.0)
+
+With the introduction of schemas in Firebird 6.0, the syntax `.` - used for tables, views, procedures,
+and functions (both standalone and packaged) - introduces ambiguity when resolving object names using the schema
+search path. The ambiguity arises between:
+
+- `.` (a schema and its object)
+- `.` (a package and its object)
+
+This document focuses on name resolution rules for tables, views, procedures, and functions within queries and
+code blocks.
+
+## Scope specifier (`%`)
+
+To resolve these ambiguities, Firebird introduces a **scope specifier**, represented by the `%` symbol. This
+allows unambiguous referencing of objects.
+
+### Syntax
+
+```sql
+ % { SCHEMA | PACKAGE } .
+```
+
+### Examples
+
+```sql
+select *
+ from plg$profiler%schema.plg$prof_sessions;
+
+execute procedure rdb$profiler%package.pause_session;
+
+call rdb$profiler%package.pause_session();
+
+select rdb$time_zone_util%package.database_version()
+ from system%schema.rdb$database;
+
+select *
+ from rdb$time_zone_util%package.transitions('America/Sao_Paulo', timestamp '2017-01-01', timestamp '2019-01-01');
+```
+
+## Detailed name resolution rules
+
+Firebird resolves object names following a structured sequence of rules. Once an object is located, the resolution
+process halts, ensuring no ambiguity errors occur.
+
+- **`name1.name2.name3`**
+ 1. Look for routine `name3` inside package `name2`, inside schema `name1`.
+
+- **`name1%schema.name2`**
+ 1. Look for object `name2` inside schema `name1`.
+
+- **`name1%package.name2`**
+ 1. Look for object `name2` inside a package `name1` using the schema search path.
+
+- **`name1.name2`**
+ 1. If inside a package named `name1`, look for routine `name2` in the same package.
+ 2. Look in schema `name1` for object `name2`.
+ 3. Look for object `name2` inside a package `name1` using the schema search path.
+
+- **`name`**
+ 1. Look for subroutine `name`.
+ 2. If inside a package, look for routine `name` in the same package.
+ 3. Look for object `name` using the schema search path.
+
+> **_Note:_** Object resolution also depends on the context in which they are used. For example, in
+`select * from name1.name2`, `name2` could be a table, view, or procedure. However, in
+`execute procedure name1.name2`, `name2` must be a procedure. This distinction means that an `execute procedure`
+command versus a `select` command can resolve to different objects.
diff --git a/doc/sql.extensions/README.profiler.md b/doc/sql.extensions/README.profiler.md
index 3d74055442e..e7eca439744 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.
@@ -265,6 +269,7 @@ Below is the list of tables that stores profile data.
- `STATEMENT_ID` type `BIGINT` - Statement ID
- `PARENT_STATEMENT_ID` type `BIGINT` - Parent statement ID - related to sub routines
- `STATEMENT_TYPE` type `VARCHAR(20) CHARACTER SET UTF8` - BLOCK, FUNCTION, PROCEDURE or TRIGGER
+ - `SCHEMA_NAME` type `CHAR(63) CHARACTER SET UTF8` - Schema name of FUNCTION, PROCEDURE or TRIGGER
- `PACKAGE_NAME` type `CHAR(63) CHARACTER SET UTF8` - Package of FUNCTION or PROCEDURE
- `ROUTINE_NAME` type `CHAR(63) CHARACTER SET UTF8` - Routine name of FUNCTION, PROCEDURE or TRIGGER
- `SQL_TEXT` type `BLOB subtype TEXT CHARACTER SET UTF8` - SQL text for BLOCK
@@ -346,6 +351,7 @@ After hotspots are found, one can drill down in the data at the request level th
select req.profile_id,
req.statement_id,
sta.statement_type,
+ sta.schema_name,
sta.package_name,
sta.routine_name,
sta.parent_statement_id,
@@ -371,6 +377,7 @@ select req.profile_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,
@@ -384,6 +391,7 @@ select req.profile_id,
select pstat.profile_id,
pstat.statement_id,
sta.statement_type,
+ sta.schema_name,
sta.package_name,
sta.routine_name,
sta.parent_statement_id,
@@ -411,6 +419,7 @@ select pstat.profile_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,
@@ -426,6 +435,7 @@ select pstat.profile_id,
select rstat.profile_id,
rstat.statement_id,
sta.statement_type,
+ sta.schema_name,
sta.package_name,
sta.routine_name,
sta.parent_statement_id,
@@ -474,6 +484,7 @@ select rstat.profile_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,
diff --git a/doc/sql.extensions/README.schemas.md b/doc/sql.extensions/README.schemas.md
new file mode 100644
index 00000000000..af168d7340e
--- /dev/null
+++ b/doc/sql.extensions/README.schemas.md
@@ -0,0 +1,645 @@
+# Schemas (FB 6.0)
+
+Firebird 6.0 introduces support for schemas in the database. Schemas are not an optional feature, so every Firebird 6
+database has at least a `SYSTEM` schema, reserved for Firebird system objects (`RDB$*` and `MON$*`).
+
+User objects live in different schemas, which may be the automatically created `PUBLIC` schema or user-defined ones. It
+is not allowed (except for indexes) to create or modify objects in the `SYSTEM` schema.
+
+This documentation explains how schemas work in Firebird, how to use them, and what may differ when migrating a
+database from previous versions to Firebird 6.
+
+## Why schemas?
+
+Schemas allow the logical grouping of database objects (such as tables, views, and indexes), providing a clear
+structure to the database. They are primarily used for two purposes.
+
+### Schemas for database object organization
+
+Schemas help in organizing database objects modularly, making the database easier to manage and maintain. By dividing
+the database into different schemas, developers and administrators can focus on specific areas, improving team
+scalability and reducing complexity.
+
+For example, the `SYSTEM` schema separates objects created by two distinct groups (the Firebird DBMS core team and the
+Firebird users). Firebird users can organize objects in custom schemas like `FINANCE` and `MARKETPLACE`.
+
+### Schemas for data isolation
+
+In multi-tenant applications, schemas can provide data isolation for different clients or tenants. By assigning a
+unique schema to each tenant, tables and other objects can share the same names in different schemas, reducing data
+leakage risks and sometimes improving performance. Applications can set the schema search path for the current selected
+customer.
+
+This approach simplifies database management and scaling since each tenant's data is isolated, making maintenance,
+updates, and backups straightforward. Example schema names could be `CUSTOMER_1` and `CUSTOMER_2`.
+
+## Schema-less and schema-bound objects
+
+Database objects fall into two categories: schema-less and schema-bound.
+
+### Schema-less objects
+
+These objects exist outside schemas and function as before:
+- Users
+- Roles
+- Blob filters
+- Schemas
+
+### Schema-bound objects
+
+These objects are always contained within a schema:
+- Tables
+- Views
+- Triggers
+- Procedures
+- Exceptions
+- Domains
+- Indexes
+- Character sets
+- Sequences / Generators
+- Functions
+- Collations
+- Packages
+
+Some objects are highly dependent on their parents, like table-based triggers and indexes depending on the table.
+In this case the child object always resides in the same schema of its parent.
+
+## Search Path
+
+A Firebird session is started with an initial search path, a list of schemas used to resolve unqualified object names.
+By default, this path is set to `PUBLIC, SYSTEM`, but it can be customized using the `isc_dpb_search_path` parameter
+in the API.
+
+The initial search path serves as the basis for the current search path, which is actively used during object
+resolution. The current search path can be dynamically updated using the `SET SEARCH_PATH TO` statement. If needed,
+you can reset the current search path to its initial configuration with the `ALTER SESSION RESET` statement.
+
+Nonexistent schemas can be included in the search path but are ignored during name resolution.
+
+The first existing schema in the search path is referred to as the **current schema** and is exclusively used in some
+operations.
+
+Binding unqualified objects to a schema typically occurs at **statement preparation time**. An exception to this is
+the `MAKE_DBKEY` function when its first argument is an expression (not a simple literal), in which case the table
+resolution happens at **execution time**.
+
+Object names can now be explicitly qualified with their schema, such as `SCHEMA_NAME.TABLE_NAME`,
+`SCHEMA_NAME.TABLE_NAME.COLUMN_NAME`, or `SCHEMA_NAME.PACKAGE_NAME.PROCEDURE_NAME`. However, the schema qualifier is
+optional. When omitted, the search path is used to resolve unqualified names, and the behavior depends on the context
+in which the name appears.
+
+For `CREATE`, `CREATE OR ALTER`, and `RECREATE` statements, the system searches only the **current schema** (the first
+valid schema in the search path) for an existing object, and the new object is created in this same schema.
+This rule also applies to `GRANT` and `REVOKE` statements for DDL operations without the `ON SCHEMA` subclause. If no
+**current schema** is available (i.e., no valid schema exists in the search path), an error is raised.
+
+Examples using this rule:
+
+```sql
+create table TABLE1 (ID integer);
+recreate table TABLE1 (ID integer);
+create or alter function F1 returns integer as begin end;
+grant create table to user USER1;
+```
+
+For `ALTER`, `DROP`, and others statements, the system searches for the specified object across all schemas in the
+search path. The reference is bound to the first matching object found. If no matching object exists in any schema, an
+error is raised.
+
+Examples using this rule:
+
+```sql
+alter table TABLE1 add X integer;
+alter function FUNCTION1 returns integer as begin end;
+select * from TABLE1;
+```
+
+The behavior of search paths differs between DML and DDL statements.
+
+For DML statements, the search path is used to locate all referenced unqualified objects. For example:
+
+```sql
+insert into TABLE1 values (1);
+
+execute block returns (out DOMAIN1)
+as
+begin
+ select val from TABLE2 into out;
+end;
+```
+
+In this case, the search path is used to locate `TABLE1`, `DOMAIN1`, and `TABLE2`.
+
+For DDL statements, the search path operates similarly, but with a subtle difference. Once the object being created or
+modified is bound to a schema during statement preparation, the search path is implicitly and temporarily modified.
+This adjustment sets the search path to the schema of the object. Additionally, if the `SYSTEM` schema was already
+present in the search path, it is appended as the last schema.
+
+```sql
+create schema SCHEMA1;
+create schema SCHEMA2;
+
+create domain SCHEMA1.DOMAIN1 integer;
+
+-- DOMAIN1 is bound to SCHEMA1 even without it being in the search path, as the table being created is bound to SCHEMA1
+create table SCHEMA1.TABLE1 (id DOMAIN1);
+
+set search_path to SCHEMA2, SCHEMA1;
+-- Error: even if SCHEMA1 is in the search path, TABLE2 is bound to SCHEMA2,
+-- so DOMAIN1 is searched only in SCHEMA2 schema
+create table TABLE2 (id DOMAIN1);
+
+set search_path to SYSTEM;
+
+create procedure SCHEMA1.PROC1
+as
+begin
+ -- TABLE1 is bound to SCHEMA1 as PROC1
+ insert into TABLE1 values (1);
+end;
+```
+
+### Resolving between `PACKAGE.OBJECT` and `SCHEMA.OBJECT`
+
+The syntax `.` introduces ambiguity between `.` and `.` when referring to
+procedures and functions. See [name resolution](README.name_resolution.md) for details.
+
+## Permissions
+
+Permissions for managing and using schema-bound objects are now influenced by the permissions assigned to schemas.
+
+A schema, like other database objects, has an owner. The schema owner can manage and use any object within the schema,
+including objects created by other users in that schema.
+
+To manipulate objects within a schema owned by another user, specific DDL permissions are required. While DDL
+permissions existed in previous versions, they are now more granular. For example:
+
+```sql
+grant create table on schema SCHEMA1 to user USER1;
+grant alter any procedure on schema SCHEMA1 to PUBLIC;
+```
+
+The `ON SCHEMA ` clause is optional. If omitted, the **current schema** is implicitly assumed.
+
+Previously, using an object required having specific permissions, such as `EXECUTE` or `USAGE`, granted for the object.
+Now, in addition to these object-level permissions, the `USAGE` permission must also be granted for the schema
+containing the object. For example:
+
+```sql
+-- Connected as USER1
+create schema SCHEMA1;
+create table SCHEMA1.TABLE1 (ID integer);
+
+grant usage on schema SCHEMA1 to user USER2;
+grant select on table SCHEMA1.TABLE1 to user USER2;
+```
+
+## The SYSTEM schema
+
+All system schema-bound objects (e.g., `RDB$*` and `MON$*`) are now created in a dedicated schema called `SYSTEM`.
+The `SYSTEM` schema has a default `USAGE` permission granted to `PUBLIC` and is included in the default search path.
+This ensures backward compatibility with previous Firebird versions.
+
+While the `SYSTEM` schema allows operations like index creation and manipulation of those indexes, it is otherwise
+locked for DDL changes. Modifying objects within the `SYSTEM` schema through DDL operations is strongly discouraged.
+
+## The PUBLIC schema
+
+A schema named `PUBLIC` is automatically created in new databases, with a default `USAGE` permission granted to
+`PUBLIC`. However, only the database or schema owner has default permissions to manipulate objects within this schema.
+
+Unlike the `SYSTEM` schema, the `PUBLIC` schema is not a system object and can be dropped by the database owner
+or by a user with `DROP ANY SCHEMA` permission. If restoring a Firebird 6 or later backup using `gbak`, and the
+`PUBLIC` schema was not present in the original database, the restored database will also exclude it.
+
+## New statements and expressions
+
+### CREATE SCHEMA
+
+```sql
+{CREATE [IF NOT EXISTS] | CREATE OR ALTER | RECREATE} SCHEMA
+ [DEFAULT CHARACTER SET ]
+ [DEFAULT SQL SECURITY {DEFINER | INVOKER}]
+```
+
+Schemas may have an optional default character set and SQL security setting, which serve as the defaults for objects
+contained within them. When these defaults are not specified or are dropped, the database's default character set and
+SQL security settings are used, as in previous versions.
+
+Unlike the automatically created `PUBLIC` schema, newly created schemas grant `USAGE` permission only to their owners
+and not to `PUBLIC`.
+
+Schema names `INFORMATION_SCHEMA` and `DEFINITION_SCHEMA` are reserved and cannot be used for new schemas.
+
+### ALTER SCHEMA
+
+```sql
+ALTER SCHEMA
+ ...
+
+ ::=
+ SET DEFAULT CHARACTER SET |
+ SET DEFAULT SQL SECURITY {DEFINER | INVOKER} |
+ DROP DEFAULT CHARACTER SET |
+ DROP DEFAULT SQL SECURITY
+```
+
+### DROP SCHEMA
+
+```sql
+DROP SCHEMA [IF EXISTS]
+```
+
+Currently, only empty schemas can be dropped. In the future, a `CASCADE` sub-clause will be introduced, allowing
+schemas to be dropped along with all their contained objects.
+
+### CURRENT_SCHEMA
+
+`CURRENT_SCHEMA` returns the name of the first valid schema in the search path of the current session. If no valid
+schema exists, it returns `NULL`.
+
+### SET SEARCH_PATH TO
+
+```sql
+SET SEARCH_PATH TO [, ]...
+```
+
+### RDB$GET_CONTEXT
+
+#### CURRENT_SCHEMA (SYSTEM)
+
+`RDB$GET_CONTEXT('SYSTEM', 'CURRENT_SCHEMA')` returns the same value as the `CURRENT_SCHEMA` expression.
+
+#### SEARCH_PATH (SYSTEM)
+
+`RDB$GET_CONTEXT('SYSTEM', 'SEARCH_PATH')` returns the current session search path, including invalid schemas in the
+list. To get separate records for each entry, you can use:
+
+```sql
+select NAME
+ from SYSTEM.RDB$SQL.PARSE_UNQUALIFIED_NAMES(RDB$GET_CONTEXT('SYSTEM', 'SEARCH_PATH'))
+```
+
+#### SCHEMA_NAME (DDL_TRIGGER)
+
+`RDB$GET_CONTEXT('DDL_TRIGGER', 'SCHEMA_NAME')` returns the schema name of the affected object within a DDL trigger.
+
+## Monitoring
+
+The monitoring tables now include schema-related information:
+
+`MON$ATTACHMENTS`
+- `MON$SEARCH_PATH`: search path of the attachment
+
+`MON$TABLE_STATS`
+- `MON$SCHEMA_NAME`: schema of the table
+
+`MON$CALL_STACK`
+- `MON$SCHEMA_NAME`: schema of the routine
+
+`MON$COMPILED_STATEMENTS`
+- `MON$SCHEMA_NAME`: schema of the routine
+
+## Queries
+
+Field names can now be qualified with the schema, in addition to aliases or table names. This includes cases where the
+schema is implicitly determined by the search path. It is also possible to qualify the table name with the schema and
+refer to the field using just the table name. For example:
+
+```sql
+create schema SCHEMA1;
+
+create table SCHEMA1.TABLE1 (ID integer);
+
+set search_path to SCHEMA1;
+
+select TABLE1.ID from SCHEMA1.TABLE1;
+select SCHEMA1.TABLE1.ID from TABLE1;
+select SCHEMA1.TABLE1.ID from SCHEMA1.TABLE1;
+```
+
+If the same table name exists in multiple schemas, fields must be qualified with schema names or table aliases to
+avoid ambiguity. For example:
+
+```sql
+create schema SCHEMA1;
+create schema SCHEMA2;
+
+create table SCHEMA1.TABLE1 (ID integer);
+create table SCHEMA2.TABLE1 (ID integer);
+
+select SCHEMA1.TABLE1.ID, SCHEMA2.TABLE1.ID from SCHEMA1.TABLE1, SCHEMA2.TABLE1;
+select S1.ID, S2.ID from SCHEMA1.TABLE1 S1, SCHEMA2.TABLE1 S2;
+```
+
+### Plans
+
+Plans (both legacy and detailed) now include schema names in their reports, resulting in slight changes to their format.
+
+For example, the query below:
+```sql
+with q1 as (
+ select *
+ from t1
+),
+q2 as (
+ select *
+ from q1
+)
+select *
+ from q2 x;
+```
+
+Previously produced the following plan:
+```
+PLAN (X Q1 T1 NATURAL)
+
+Select Expression
+ -> Table "T1" as "X Q1 T1" Full Scan
+```
+
+Now, the plan explicitly includes the schema, and each name is quoted separately:
+```
+PLAN ("X" "Q1" "PUBLIC"."T1" NATURAL)
+
+Select Expression
+ -> Table "PUBLIC"."T1" as "X" "Q1" "PUBLIC"."T1" Full Scan
+```
+
+## New DPB items
+
+### `isc_dpb_search_path`
+
+`isc_dpb_search_path` is a string DPB parameter, similar to `isc_dpb_user_name`, used to set the initial schema search
+path for a session.
+
+## New TPB items
+
+### `isc_tpb_lock_table_schema`
+
+`isc_tpb_lock_table_schema` could be used with `isc_tpb_lock_read` and `isc_tpb_lock_write`, after the table name and
+before `isc_tpb_shared`, `isc_tpb_protected` or `isc_tpb_exclusive`. The format of `isc_tpb_lock_table_schema` is
+a single byte length followed by the schema name.
+
+## Array support
+
+### `isc_sdl_schema`
+
+When working with arrays using SDL (Slice Description Language), the `isc_sdl_schema` parameter can now be used to
+explicitly qualify the schema. Its format is equivalent to `isc_sdl_relation`.
+
+## Utilities
+
+### isql
+
+#### Option `-(SE)ARCH_PATH`
+
+This option enables ISQL to pass the search path argument as `isc_dpb_search_path` with every established attachment.
+
+```
+isql -search_path x,y test.fdb
+select RDB$GET_CONTEXT('SYSTEM', 'SEARCH_PATH') from system.rdb$database;
+-- Result: "X", "Y"
+set search_path to y;
+select RDB$GET_CONTEXT('SYSTEM', 'SEARCH_PATH') from system.rdb$database;
+-- Result: "Y"
+
+connect 't2.fdb';
+select RDB$GET_CONTEXT('SYSTEM', 'SEARCH_PATH') from system.rdb$database;
+-- Result: "X", "Y"
+```
+
+```
+isql -search_path '"x", "y"' test.fdb
+select RDB$GET_CONTEXT('SYSTEM', 'SEARCH_PATH') from system.rdb$database;
+-- Result: "x", "y"
+```
+
+Special names with double quotes require different handling depending on the operating system and, specifically, the
+shell interpreter. On Linux with `bash`, double quotes must be escaped using the backslash (`\`) character. On Windows
+with `cmd`, double quotes need to be duplicated. The example below demonstrates how to use the same search path on both
+platforms.
+
+Linux / bash:
+```
+isql -search_path "x, \"y\", z, \"q a\", system" test.fdb
+
+select rdb$get_context('SYSTEM', 'SEARCH_PATH') from system.rdb$database;
+-- Result: "X", "y", "Z", "q a", "SYSTEM"
+```
+
+Windows / cmd:
+```
+isql -search_path "x, ""y"", z, ""q a"", system" test.fdb
+
+select rdb$get_context('SYSTEM', 'SEARCH_PATH') from system.rdb$database;
+-- Result: "X", "y", "Z", "q a", "SYSTEM"
+```
+
+### gbak
+
+To use databases created in earlier Firebird versions with Firebird 6, you must restore a backup using the Firebird 6
+`gbak` utility. In the restored database, all user objects will be placed in the `PUBLIC` schema.
+
+Firebird includes several built-in plugins that create database objects. Prior to Firebird 6, schemas did not exist,
+so these objects were only distinguished by their `PLG$` prefix. When restoring a pre-Firebird 6 backup, `gbak`
+automatically attempts to recreate these objects (and their data) in specific schemas — `PLG$PROFILER`, `PLG$SRP`, and
+`PLG$LEGACY_SEC` — while removing those located in the `PUBLIC` schema. This process may fail if user-defined objects
+reference these plugin objects. In that case, `gbak` will display a warning and halt the plugin schema migration
+process.
+
+#### Options
+
+`gbak` now includes the `-INCLUDE_SCHEMA_D(ATA)` and `-SKIP_SCHEMA_D(ATA)` switches, which complement the previously
+existing `-INCLUDE_DATA` and `-SKIP_DATA` options. If `-INCLUDE_SCHEMA_D(ATA)` is not specified, all schemas are
+included by default. Likewise, if `-SKIP_SCHEMA_D(ATA)` is not provided, no schemas are skipped.
+
+Example:
+```shell
+# Include data only from tables of the schema S1
+gbak -c -include_schema_data S1 database.fbk database.fdb
+
+# Include data only from tables named T1 from any schema
+gbak -c -include_data T1 database.fbk database.fdb
+
+# Include data only from table T1 of the schema S1
+gbak -c -include_schema_data S1 -include_data T1 database.fbk database.fdb
+
+# Include data from tables of all schemas except S1
+gbak -c -skip_schema_data S1 database.fbk database.fdb
+```
+
+### gstat
+
+`gstat` now includes the `-sch ` option, which complement the previously existing `-t `.
+If `-sch` is not specified, all schemas are analyzed by default.
+
+### fbsvcmgr
+
+`fbsvcmgr` now include some options forwarded to their equivalent services/utilities. This table shows the options and
+their equivalents:
+
+| Option | Equivalent |
+|-------------------------|--------------------------------------------------|
+| bkp_skip_schema_data | `gbak -skip_schema_data` when backing up |
+| bkp_include_schema_data | `gbak -include_schema_data` when backing up |
+| res_skip_schema_data | `gbak -skip_schema_data` when restoring |
+| res_include_schema_data | `gbak -include_schema_data` when restoring |
+| sts_schema | `gstat -sch` |
+| val_sch_incl | analogous to `fbsvcmgr -val_tab_incl` for schema |
+| val_sch_excl | analogous to `fbsvcmgr -val_tab_excl` for schema |
+
+## System metadata changes
+
+The following fields have been added to system tables. It is essential for applications and tools that read metadata
+to utilize these fields where appropriate. For example, consider using `RDB$SCHEMA_NAME` when joining tables.
+
+| Table | Column |
+|--------------------------|---------------------------------|
+| MON$ATTACHMENTS | MON$SEARCH_PATH |
+| MON$CALL_STACK | MON$SCHEMA_NAME |
+| MON$COMPILED_STATEMENTS | MON$SCHEMA_NAME |
+| MON$TABLE_STATS | MON$SCHEMA_NAME |
+| RDB$CHARACTER_SETS | RDB$DEFAULT_COLLATE_SCHEMA_NAME |
+| RDB$CHARACTER_SETS | RDB$SCHEMA_NAME |
+| RDB$CHECK_CONSTRAINTS | RDB$SCHEMA_NAME |
+| RDB$COLLATIONS | RDB$SCHEMA_NAME |
+| RDB$DATABASE | RDB$CHARACTER_SET_SCHEMA_NAME |
+| RDB$DEPENDENCIES | RDB$DEPENDED_ON_SCHEMA_NAME |
+| RDB$DEPENDENCIES | RDB$DEPENDENT_SCHEMA_NAME |
+| RDB$EXCEPTIONS | RDB$SCHEMA_NAME |
+| RDB$FIELDS | RDB$SCHEMA_NAME |
+| RDB$FIELD_DIMENSIONS | RDB$SCHEMA_NAME |
+| RDB$FUNCTIONS | RDB$SCHEMA_NAME |
+| RDB$FUNCTION_ARGUMENTS | RDB$FIELD_SOURCE_SCHEMA_NAME |
+| RDB$FUNCTION_ARGUMENTS | RDB$RELATION_SCHEMA_NAME |
+| RDB$FUNCTION_ARGUMENTS | RDB$SCHEMA_NAME |
+| RDB$GENERATORS | RDB$SCHEMA_NAME |
+| RDB$INDEX_SEGMENTS | RDB$SCHEMA_NAME |
+| RDB$INDICES | RDB$FOREIGN_KEY_SCHEMA_NAME |
+| RDB$INDICES | RDB$SCHEMA_NAME |
+| RDB$PACKAGES | RDB$SCHEMA_NAME |
+| RDB$PROCEDURES | RDB$SCHEMA_NAME |
+| RDB$PROCEDURE_PARAMETERS | RDB$FIELD_SOURCE_SCHEMA_NAME |
+| RDB$PROCEDURE_PARAMETERS | RDB$RELATION_SCHEMA_NAME |
+| RDB$PROCEDURE_PARAMETERS | RDB$SCHEMA_NAME |
+| RDB$PUBLICATION_TABLES | RDB$TABLE_SCHEMA_NAME |
+| RDB$REF_CONSTRAINTS | RDB$CONST_SCHEMA_NAME_UQ |
+| RDB$REF_CONSTRAINTS | RDB$SCHEMA_NAME |
+| RDB$RELATIONS | RDB$SCHEMA_NAME |
+| RDB$RELATION_CONSTRAINTS | RDB$SCHEMA_NAME |
+| RDB$RELATION_FIELDS | RDB$FIELD_SOURCE_SCHEMA_NAME |
+| RDB$RELATION_FIELDS | RDB$SCHEMA_NAME |
+| RDB$SCHEMAS | RDB$CHARACTER_SET_NAME |
+| RDB$SCHEMAS | RDB$CHARACTER_SET_SCHEMA_NAME |
+| RDB$SCHEMAS | RDB$SQL_SECCURITY |
+| RDB$SCHEMAS | RDB$DESCRIPTION |
+| RDB$SCHEMAS | RDB$OWNER_NAME |
+| RDB$SCHEMAS | RDB$SCHEMA_NAME |
+| RDB$SCHEMAS | RDB$SECURITY_CLASS |
+| RDB$SCHEMAS | RDB$SYSTEM_FLAG |
+| RDB$TRIGGERS | RDB$SCHEMA_NAME |
+| RDB$TRIGGER_MESSAGES | RDB$SCHEMA_NAME |
+| RDB$USER_PRIVILEGES | RDB$RELATION_SCHEMA_NAME |
+| RDB$USER_PRIVILEGES | RDB$USER_SCHEMA_NAME |
+| RDB$VIEW_RELATIONS | RDB$RELATION_SCHEMA_NAME |
+| RDB$VIEW_RELATIONS | RDB$SCHEMA_NAME |
+
+## Differences with previous versions
+
+### CREATE SCHEMA in `IAttachment::executeCreateDatabase` and `isc_create_database`
+
+In earlier versions, `CREATE SCHEMA` served as an alias for `CREATE DATABASE`, when using the API functions
+`IAttachment::executeCreateDatabase` and `isc_create_database` to create databases. This is no longer the case;
+the only valid syntax now is `CREATE DATABASE`.
+
+### Object names in error messages and expressions
+
+Object names in error and informational messages are now consistently qualified and quoted within message parameters,
+even in DIALECT 1 databases.
+
+```sql
+SQL> create table TABLE1 (ID integer);
+SQL> create table TABLE1 (ID integer);
+Statement failed, SQLSTATE = 42S01
+unsuccessful metadata update
+-CREATE TABLE "PUBLIC"."TABLE1" failed
+-Table "PUBLIC"."TABLE1" already exists
+
+SQL> create schema "Weird ""Schema""";
+SQL> create schema "Weird ""Schema""";
+Statement failed, SQLSTATE = 42000
+unsuccessful metadata update
+-CREATE SCHEMA "Weird ""Schema""" failed
+-Schema "Weird ""Schema""" already exists
+```
+
+The `RDB$ERROR(EXCEPTION)` expression now returns the fully qualified and quoted name of the exception as well.
+
+### Object name parsing outside SQL
+
+When working with object names in `isc_dpb_search_path`, `isc_dpb_lc_ctype`, `isc_dpb_set_db_charset` and `MAKE_DBKEY`,
+the names follow the same rules as in SQL.
+This means that names containing special characters or lowercase letters must be enclosed in quotes.
+
+With `isc_dpb_lc_ctype` and `isc_dpb_set_db_charset`, names not qualified with a schema are resolved using the `SYSTEM`
+schema.
+
+With `MAKE_DBKEY`, unqualified names are resolved using the current search path. In earlier versions, `MAKE_DBKEY`
+required an exact table name as its first parameter and did not support the use of double quotes for special
+characters.
+
+### Minimum page size
+
+The minimum database page size has been increased from 4096 to 8192 bytes. This change was necessary because the
+previous minimum could no longer accommodate updates done in the system indexes.
+
+### System function overrides
+
+In Firebird versions prior to 6, user-defined functions could override system functions that use standard syntax,
+such as `ABS` and `MOD`. This behavior is no longer allowed.
+
+Starting with Firebird 6, system functions must be called without quotes and without a schema name. If a user-defined
+function shares a name with a system function, it must be explicitly called using quotes or qualified with the schema
+name.
+
+### Built-in plugins
+
+Built-in plugins are migrated by `gbak` to their own schemas. Stored routines referenceing them should be updated to
+include their schema names before changes.
+
+## Replication
+
+### Config parameters `include_schema_filter` and `exclude_schema_filter`
+
+`replication.conf` now includes the `include_schema_filter` and `exclude_schema_filter` parameters, which complement
+the previously existing `include_filter` and `exclude_filter`. If `include_schema_filter` is not specified,
+all schemas are included by default. Likewise, if `exclude_schema_filter` is not provided, no schemas are excluded.
+
+### Config parameter `schema_search_path`
+
+A master database running in Firebird < 6.0 can be asynchronously replicated to a slave database using Firebird ≥ 6.0.
+Since the master database has no schema awareness, the `schema_search_path` config parameter is introduced on the
+slave side. This allows mapping database objects to a specific schema using a search path.
+
+## System packages and functions
+
+Firebird includes system packages such as `RDB$TIME_ZONE_UTIL`, `RDB$PROFILER`, and others. These system packages
+are now located in the `SYSTEM` schema. If the `SYSTEM` schema is not included in the search path, their usage
+requires explicit qualification with `SYSTEM`, as with any other object bound to the `SYSTEM` schema.
+
+In contrast, Firebird also provides non-packaged built-in functions like `RDB$GET_CONTEXT`, `ABS`, and `DATEDIFF`.
+These functions are not listed in the database metadata (`RDB$FUNCTIONS`) and neither require nor accept the
+`SYSTEM` qualifier for usage.
+
+## Downgrade compatibility
+
+It is expected that Firebird 6 databases that do not even use multiple users schemas (for example, a Firebird 5
+database just migrated to Firebird 6 by `gbak`) may not always be downgradable to **unmodified previous versions** of
+Firebird using `gbak`. This issue can occur if user objects reference system objects.
+
+The Firebird team plans to backport essential internal changes to Firebird 5 to enable such downgrades.
+It should also be possible to downgrade databases with multiple user schemas, as long as objects with
+the same name do not exist in multiple schemas.
+
+This documentation will be updated once these changes are implemented.
diff --git a/doc/sql.extensions/README.sql_package.md b/doc/sql.extensions/README.sql_package.md
index 676b000f0be..b5fa5908cf1 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
@@ -24,12 +25,12 @@ Output parameters:
- `KEY_LENGTH` type `INTEGER` - key length for the record source
- `ACCESS_PATH` type `RDB$DESCRIPTION NOT NULL` - friendly plan description
-```
+```sql
select *
from rdb$sql.explain('select * from employee where emp_no = ?');
```
-```
+```sql
select *
from rdb$sql.explain(q'{
select *
@@ -42,5 +43,21 @@ select *
}');
```
+## Procedure `PARSE_UNQUALIFIED_NAMES`
+
+`RDB$SQL.PARSE_UNQUALIFIED_NAMES` is a selectable procedure that parses a list of unqualified SQL names and returns
+one row for each name. The input must follow parse rules for names and the output of unquoted names are uppercased.
+
+```sql
+select *
+ from rdb$sql.parse_unqualified_names('schema1, schema2, "schema3", "schema 4", "schema ""5"""');
+
+-- SCHEMA1
+-- SCHEMA2
+-- schema3
+-- "schema 4"
+-- "schema "5"
+```
+
# Authors
- Adriano dos Santos Fernandes
diff --git a/examples/replication/fbSampleReplicator.cpp b/examples/replication/fbSampleReplicator.cpp
index fcf59537b20..84dc3037c8f 100644
--- a/examples/replication/fbSampleReplicator.cpp
+++ b/examples/replication/fbSampleReplicator.cpp
@@ -35,7 +35,8 @@ class ReplPlugin : public IReplicatedSessionImpl
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 @@ class ReplTransaction: public IReplicatedTransactionImpllog, "%p\tdeprecated Insert record into %s\n", this, name);
+ try
+ {
+ return dumpData(record) ? FB_TRUE : FB_FALSE;
+ }
+ catch (const int)
+ {
+ parent->status->setErrors(err);
+ return FB_FALSE;
+ }
+}
+
+FB_BOOLEAN ReplTransaction::insertRecord2(const char* schemaName, const char* tableName, IReplicatedRecord* record)
{
- WriteLog(parent->log, "%p\tInsert record into %s\n", this, name);
+ WriteLog(parent->log, "%p\tInsert record into %s.%s\n", this, schemaName, tableName);
try
{
return dumpData(record) ? FB_TRUE : FB_FALSE;
@@ -520,9 +547,29 @@ FB_BOOLEAN ReplTransaction::insertRecord(const char* name, IReplicatedRecord* re
}
}
-FB_BOOLEAN ReplTransaction::updateRecord(const char* name, IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord)
+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))
+ 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::updateRecord2(const char* schemaName, const char* tableName,
+ IReplicatedRecord* orgRecord, IReplicatedRecord* newRecord)
{
- WriteLog(parent->log, "%p\tUpdate %s\nOldData:\n", this, name);
+ WriteLog(parent->log, "%p\tUpdate %s.%s\nOldData:\n", this, schemaName, tableName);
try
{
if (!dumpData(orgRecord))
@@ -538,9 +585,23 @@ FB_BOOLEAN ReplTransaction::updateRecord(const char* name, IReplicatedRecord* or
}
}
-FB_BOOLEAN ReplTransaction::deleteRecord(const char* name, IReplicatedRecord* record)
+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;
+ }
+ catch (const int)
+ {
+ parent->status->setErrors(err);
+ return FB_FALSE;
+ }
+}
+
+FB_BOOLEAN ReplTransaction::deleteRecord2(const char* schemaName, const char* tableName, IReplicatedRecord* record)
{
- WriteLog(parent->log, "%p\tDelete from %s\n", this, name);
+ WriteLog(parent->log, "%p\tDelete from %s.%s\n", this, schemaName, tableName);
try
{
return dumpData(record) ? FB_TRUE : FB_FALSE;
@@ -552,14 +613,20 @@ FB_BOOLEAN ReplTransaction::deleteRecord(const char* name, IReplicatedRecord* re
}
}
-FB_BOOLEAN ReplTransaction::executeSql(const char* sql)
+FB_BOOLEAN ReplTransaction::deprecatedExecuteSql(const char* sql)
+{
+ WriteLog(parent->log, "%p\tdeprecatedExecuteSql(%s)\n", this, sql);
+ return FB_TRUE;
+}
+
+FB_BOOLEAN ReplTransaction::deprecatedExecuteSqlIntl(unsigned charset, const char* sql)
{
- WriteLog(parent->log, "%p\tExecuteSql(%s)\n", this, sql);
+ WriteLog(parent->log, "%p\tdeprecatedExecuteSqlIntl(%u, %s)\n", this, charset, sql);
return FB_TRUE;
}
-FB_BOOLEAN ReplTransaction::executeSqlIntl(unsigned charset, const char* sql)
+FB_BOOLEAN ReplTransaction::executeSqlIntl2(unsigned charset, const char* schemaSearchPath, const char* sql)
{
- WriteLog(parent->log, "%p\tExecuteSqlIntl(%u, %s)\n", this, charset, 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 bd56dc06e62..43c4c93f5bc 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 db795d03124..91f26cd1976 100644
--- a/src/auth/SecureRemotePassword/manage/SrpManagement.cpp
+++ b/src/auth/SecureRemotePassword/manage/SrpManagement.cpp
@@ -68,28 +68,32 @@ class SrpManagement final : public Firebird::StdPluginuserName()->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 +357,7 @@ class SrpManagement final : public Firebird::StdPlugin verifier, slt;
if (user->password()->entered())
@@ -558,7 +562,7 @@ class SrpManagement final : public Firebird::StdPluginuserName()->entered())
{
diff --git a/src/auth/SecureRemotePassword/server/SrpServer.cpp b/src/auth/SecureRemotePassword/server/SrpServer.cpp
index 3d7abb15f7e..84501683090 100644
--- a/src/auth/SecureRemotePassword/server/SrpServer.cpp
+++ b/src/auth/SecureRemotePassword/server/SrpServer.cpp
@@ -196,7 +196,7 @@ class SecurityDatabase : public VSecDb
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 PLG$SRP%SCHEMA.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 80cbc070dc0..dd45411b7b1 100644
--- a/src/auth/SecurityDatabase/LegacyManagement.epp
+++ b/src/auth/SecurityDatabase/LegacyManagement.epp
@@ -45,6 +45,8 @@
#include "../common/classes/ParsedList.h"
#include "firebird/Interface.h"
+using namespace Firebird;
+
// Here we use version-independent symbolic link (or copy) of actual database
DATABASE database = STATIC FILENAME "security.fdb";
@@ -130,6 +132,10 @@ void SecurityDatabaseManagement::start(Firebird::CheckStatusWrapper* st, Firebir
dpb.insertByte(isc_dpb_sec_attach, TRUE);
dpb.insertString(isc_dpb_config, Firebird::ParsedList::getNonLoopbackProviders(secDbName));
+ string schemaSearchPath;
+ schemaSearchPath.printf("%s, %s", PLG_LEGACY_SEC_SCHEMA, SYSTEM_SCHEMA);
+ dpb.insertString(isc_dpb_search_path, schemaSearchPath.c_str(), fb_strlen(schemaSearchPath.c_str()));
+
unsigned int authBlockSize;
const unsigned char* authBlock = logonInfo->authBlock(&authBlockSize);
diff --git a/src/auth/SecurityDatabase/LegacyServer.cpp b/src/auth/SecurityDatabase/LegacyServer.cpp
index 03715e96157..66f1340c7d9 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,
+ 14, 'P', 'L', 'G', '$', 'L', 'E', 'G', 'A', 'C', 'Y', '_', 'S', 'E', 'C', // PLG_LEGACY_SEC_SCHEMA
+ 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 85e7bb6ffe9..0dccab7093a 100644
--- a/src/burp/BurpTasks.cpp
+++ b/src/burp/BurpTasks.cpp
@@ -583,7 +583,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 024adfe7762..2ca60361336 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 5abaf298520..a22087c1608 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 4adad932700..2f70763572b 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,11 @@ 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.printf(
+ "select first(1) gen_id(%s, 0) from %srdb$database",
+ name.toQuotedString().c_str(),
+ (tdgbl->runtimeODS >= DB_VERSION_DDL14 ? "system." : ""));
BurpSql getGenerator(tdgbl, sql.c_str());
FB_MESSAGE(GetGen, Firebird::ThrowWrapper, (FB_BIGINT, id));
@@ -962,20 +984,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);
@@ -1612,7 +1635,6 @@ void put_index( burp_rel* relation)
*
**************************************/
ULONG count;
- TEXT temp[GDS_NAME_LEN];
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
@@ -1626,19 +1648,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;
@@ -1650,22 +1675,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;
@@ -1681,6 +1707,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);
@@ -1693,8 +1722,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;
@@ -1703,7 +1732,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)
@@ -1711,7 +1740,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++;
@@ -1727,9 +1756,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);
@@ -1905,8 +1933,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
@@ -1986,11 +2012,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])
@@ -2057,9 +2087,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);
@@ -2068,6 +2106,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();
@@ -2076,7 +2115,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);
@@ -2233,7 +2272,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)
{
/**************************************
*
@@ -2270,6 +2309,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()
{
/**************************************
@@ -2292,9 +2337,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)
@@ -2321,12 +2371,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
{
@@ -2387,13 +2441,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;
@@ -2423,7 +2483,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);
@@ -2434,8 +2499,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);
@@ -2445,10 +2512,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)
{
@@ -2608,16 +2676,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;
@@ -2677,7 +2749,7 @@ void write_exceptions()
* each exception.
*
**************************************/
- TEXT temp[GDS_NAME_LEN];
+ QualifiedMetaString name;
Firebird::IRequest* req_handle1 = nullptr;
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
@@ -2687,11 +2759,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);
@@ -2701,7 +2782,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;
@@ -2711,18 +2793,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);
@@ -2748,13 +2834,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;
@@ -2776,7 +2868,6 @@ void write_filters()
* each filter.
*
**************************************/
- TEXT temp[GDS_NAME_LEN];
Firebird::IRequest* req_handle1 = nullptr;
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
@@ -2784,10 +2875,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);
@@ -2795,10 +2886,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);
}
@@ -2817,8 +2909,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();
@@ -2827,21 +2918,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)
@@ -2880,10 +2976,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;
@@ -2892,11 +2989,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);
@@ -2907,20 +3007,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)
{
/**************************************
*
@@ -2932,8 +3033,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
@@ -2946,23 +3045,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)
@@ -2981,6 +3077,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)
@@ -2996,13 +3094,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;
@@ -3011,12 +3112,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)
@@ -3033,21 +3134,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)
@@ -3066,11 +3168,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
}
}
@@ -3088,7 +3190,7 @@ void write_generators()
*
**************************************/
Firebird::IRequest* req_handle1 = nullptr;
- TEXT temp[GDS_NAME_LEN];
+ QualifiedMetaString name;
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
@@ -3097,17 +3199,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);
- put_int64 (att_gen_value_int64, value);
+ value = get_gen_id(name);
+ put_int64(att_gen_value_int64, value);
}
- if (!X.RDB$DESCRIPTION.NULL) {
+
+ 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)
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);
@@ -3122,10 +3240,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;
@@ -3135,47 +3251,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);
@@ -3195,7 +3319,7 @@ void write_global_fields()
* each global field.
*
**************************************/
- TEXT temp[GDS_NAME_LEN];
+ QualifiedMetaString name;
Firebird::IRequest* req_handle1 = nullptr;
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
@@ -3211,11 +3335,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);
@@ -3271,8 +3404,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;
@@ -3285,10 +3418,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] != ' ')
@@ -3353,10 +3489,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] != ' ')
@@ -3426,7 +3565,7 @@ void write_packages()
* each package.
*
**************************************/
- TEXT temp[GDS_NAME_LEN];
+ QualifiedMetaString name;
Firebird::IRequest* req_handle1 = nullptr;
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
@@ -3437,10 +3576,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)
{
@@ -3492,8 +3638,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();
@@ -3503,22 +3648,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);
@@ -3551,24 +3701,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);
@@ -3579,20 +3733,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)
{
/**************************************
*
@@ -3604,25 +3759,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);
@@ -3638,6 +3797,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);
@@ -3646,27 +3809,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
}
}
@@ -3684,7 +3850,6 @@ void write_publications()
* each publication.
*
**************************************/
- TEXT temp[GDS_NAME_LEN];
Firebird::IRequest* req_handle = nullptr;
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
@@ -3695,10 +3860,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)
@@ -3734,7 +3898,7 @@ void write_pub_tables()
* each publication table.
*
**************************************/
- TEXT temp[GDS_NAME_LEN];
+ QualifiedMetaString tableName;
Firebird::IRequest* req_handle = nullptr;
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
@@ -3746,10 +3910,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;
+ }
+
+ PUT_TEXT(att_ptab_table_name, X.RDB$TABLE_NAME);
+ tableName.object = X.RDB$TABLE_NAME;
- BURP_verbose(398, temp);
+ BURP_verbose(398, tableName.toQuotedString().c_str());
// msg 398 writing publication for table %s
put(tdgbl, att_end);
@@ -3782,14 +3952,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;
@@ -3811,7 +3992,7 @@ void write_rel_constraints()
* each relation constraint.
*
**************************************/
- TEXT temp[GDS_NAME_LEN];
+ QualifiedMetaString name;
Firebird::IRequest* req_handle1 = nullptr;
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
@@ -3819,13 +4000,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);
@@ -3833,7 +4024,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;
@@ -3855,7 +4047,7 @@ void write_relations()
* each relation.
*
**************************************/
- TEXT temp[GDS_NAME_LEN];
+ QualifiedMetaString name;
Firebird::IRequest* req_handle1 = nullptr;
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
@@ -3871,15 +4063,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().
@@ -3920,10 +4120,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;
@@ -3933,12 +4138,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.
@@ -3970,40 +4175,86 @@ 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$SQL_SECURITY.NULL)
+ put_boolean(att_schema_sql_security, X.RDB$SQL_SECURITY);
+
+ 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);
}
@@ -4021,7 +4272,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();
@@ -4030,10 +4280,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);
@@ -4041,10 +4291,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);
}
@@ -4064,7 +4315,6 @@ void write_sql_roles()
*
**************************************/
Firebird::IRequest* req_handle1 = nullptr;
- TEXT temp[GDS_NAME_LEN];
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
@@ -4073,10 +4323,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);
}
@@ -4087,32 +4337,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);
@@ -4133,8 +4381,6 @@ void write_mapping()
*
**************************************/
Firebird::IRequest* req_handle = nullptr;
- TEXT temp[GDS_NAME_LEN];
-
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
if (tdgbl->runtimeODS >= DB_VERSION_DDL12)
@@ -4142,9 +4388,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)
@@ -4168,34 +4414,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);
@@ -4216,7 +4461,6 @@ void write_db_creators()
*
**************************************/
Firebird::IRequest* req_handle = nullptr;
- TEXT temp[GDS_NAME_LEN];
bool first = true;
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
@@ -4245,10 +4489,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
}
@@ -4276,7 +4519,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();
@@ -4293,11 +4536,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)
@@ -4335,8 +4585,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;
@@ -4347,11 +4597,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)
@@ -4369,11 +4620,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);
@@ -4393,25 +4644,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;
@@ -4440,6 +4703,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);
@@ -4450,10 +4714,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);
}
@@ -4472,7 +4737,7 @@ void write_user_privileges()
* each user privilege.
*
**************************************/
- TEXT temp[GDS_NAME_LEN];
+ QualifiedMetaString user;
Firebird::IRequest* req_handle1 = nullptr;
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
@@ -4480,21 +4745,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 9db13af103f..b40fede1719 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();
@@ -1789,7 +1815,7 @@ void BURP_print_status(bool err, Firebird::IStatus* status_vector, USHORT second
}
-void BURP_print_warning(Firebird::IStatus* status)
+void BURP_print_warning(Firebird::IStatus* status, bool printErrorAsWarning)
{
/**************************************
*
@@ -1802,25 +1828,36 @@ void BURP_print_warning(Firebird::IStatus* status)
* to allow redirecting output.
*
**************************************/
- if (status && (status->getState() & Firebird::IStatus::STATE_WARNINGS))
+ if (!status || !(status->getState() & (IStatus::STATE_WARNINGS | IStatus::STATE_ERRORS)))
+ return;
+
+ const ISC_STATUS* vector;
+
+ if (const auto state = status->getState();
+ printErrorAsWarning && (state & IStatus::STATE_ERRORS))
{
- BurpMaster master;
- BurpGlobals* tdgbl = master.get();
+ vector = status->getErrors();
+ }
+ else if (state & IStatus::STATE_WARNINGS)
+ vector = status->getWarnings();
+ else
+ return;
- // print the warning message
- const ISC_STATUS* vector = status->getWarnings();
- SCHAR s[1024];
+ BurpMaster master;
+ BurpGlobals* tdgbl = master.get();
- if (fb_interpret(s, sizeof(s), &vector))
+ // print the warning message
+ SCHAR s[1024];
+
+ if (fb_interpret(s, sizeof(s), &vector))
+ {
+ BURP_msg_partial(false, 255); // msg 255: gbak: WARNING:
+ burp_output(false, "%s\n", s);
+
+ while (fb_interpret(s, sizeof(s), &vector))
{
BURP_msg_partial(false, 255); // msg 255: gbak: WARNING:
- burp_output(false, "%s\n", s);
-
- while (fb_interpret(s, sizeof(s), &vector))
- {
- BURP_msg_partial(false, 255); // msg 255: gbak: WARNING:
- burp_output(false, " %s\n", s);
- }
+ burp_output(false, " %s\n", s);
}
}
}
@@ -2664,59 +2701,25 @@ void close_platf(DESC file)
#endif // WIN_NT
-void BurpGlobals::setupSkipData(const Firebird::string& regexp)
-{
- if (skipDataMatcher)
- {
- BURP_error(356, true);
- // msg 356 regular expression to skip tables was already set
- }
-
- // Compile skip relation expressions
- try
- {
- if (regexp.hasData())
- {
- Firebird::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)
+void BurpGlobals::setupSkipIncludePattern(const string& regexp, USHORT alreadySetErrorCode,
+ AutoPtr& matcher)
{
- if (includeDataMatcher)
- {
- BURP_error(390, true);
- // msg 390 regular expression to include tables was already set
- }
+ if (matcher)
+ BURP_error(alreadySetErrorCode, true);
- // Compile include 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();
- 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 +2753,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 +2767,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 +2893,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 15e143e519f..65a39090b05 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
@@ -396,7 +406,9 @@ enum att_type {
att_xdr_length = SERIES + 16,
att_xdr_array,
+
att_class_description2,
+ att_view_relation_schema_name,
// Trigger attributes
@@ -419,6 +431,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 +457,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 +481,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 +507,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 +518,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 +539,7 @@ enum att_type {
att_gen_sysflag,
att_gen_init_val,
att_gen_id_increment,
+ att_gen_schema_name,
// Stored procedure attributes
@@ -541,6 +562,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 +579,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 +591,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 +601,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 +610,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 +622,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 +636,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 +651,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 +675,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 +689,17 @@ 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_sql_security,
+ 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;
};
@@ -1150,6 +1190,7 @@ class BurpGlobals : public Firebird::ThreadData, public GblPool
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;
@@ -1195,9 +1236,9 @@ class BurpGlobals : public Firebird::ThreadData, public GblPool
{
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
@@ -1205,9 +1246,8 @@ class BurpGlobals : public Firebird::ThreadData, public GblPool
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
@@ -1217,7 +1257,9 @@ class BurpGlobals : public Firebird::ThreadData, public GblPool
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 393da083ccf..ec2ca8b10d4 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.
@@ -47,7 +46,7 @@ void BURP_output_version(void*, const TEXT*);
void BURP_print(bool err, USHORT, const MsgFormat::SafeArg& arg = MsgFormat::SafeArg());
void BURP_print(bool err, USHORT, const char* str);
void BURP_print_status(bool err, Firebird::IStatus* status, USHORT secondNumber = 0);
-void BURP_print_warning(Firebird::IStatus* status);
+void BURP_print_warning(Firebird::IStatus* status, bool printErrorAsWarning = false);
void BURP_verbose(USHORT, const MsgFormat::SafeArg& arg = MsgFormat::SafeArg());
void BURP_verbose(USHORT, const char* str);
void BURP_message(USHORT, const MsgFormat::SafeArg& arg = MsgFormat::SafeArg(), bool totals = false);
diff --git a/src/burp/burpswi.h b/src/burp/burpswi.h
index 609f928614b..57da4f4a1bf 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 0b5eedb805a..8cd3b8a4cc4 100644
--- a/src/burp/restore.epp
+++ b/src/burp/restore.epp
@@ -117,7 +117,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
@@ -146,13 +146,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);
@@ -175,14 +176,15 @@ 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);
void update_ownership(BurpGlobals* tdgbl);
void update_view_dbkey_lengths(BurpGlobals* tdgbl);
void fix_missing_privileges(BurpGlobals* tdgbl);
+void fix_plugins_schemas(BurpGlobals* tdgbl);
void fix_system_generators(BurpGlobals* tdgbl);
void set_transaction(BurpGlobals* tdgbl);
void general_on_error();
@@ -265,21 +267,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;
@@ -289,16 +292,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)
{
@@ -306,19 +312,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
}
}
@@ -336,7 +342,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();
@@ -350,6 +356,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
@@ -360,18 +367,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
@@ -385,12 +395,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;
@@ -400,7 +414,8 @@ int RESTORE_restore (const TEXT* file_name, const TEXT* database_name)
continue;
END_ERROR
}
- END_ERROR;
+ }
+ END_ERROR
if (tdgbl->global_trans)
{
@@ -431,21 +446,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())
@@ -464,23 +483,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;
@@ -560,6 +583,10 @@ int RESTORE_restore (const TEXT* file_name, const TEXT* database_name)
// Fix values of system generators.
fix_system_generators(tdgbl);
+ EXEC SQL COMMIT RETAIN;
+
+ fix_plugins_schemas(tdgbl);
+
COMMIT;
ON_ERROR
general_on_error ();
@@ -990,6 +1017,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);
@@ -1045,10 +1075,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;
@@ -1357,7 +1388,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)
{
/**************************************
*
@@ -1374,14 +1405,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;
@@ -1435,8 +1463,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);
@@ -1885,8 +1923,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);
@@ -2120,8 +2165,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 +2483,7 @@ bool get_character_set(BurpGlobals* tdgbl)
{
};
+ QualifiedMetaString name;
att_type attribute;
scan_attr_t scan_next_attr;
@@ -2439,14 +2491,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 +2519,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 +2542,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 +2609,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 +2646,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 +2708,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 +2745,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 +2755,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 +2776,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 +2797,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 +2827,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 +2923,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 +2957,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 +3030,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 +3061,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 +3128,11 @@ bool get_collation(BurpGlobals* tdgbl)
break;
}
}
- END_STORE;
+ }
+ END_STORE
ON_ERROR
general_on_error ();
- END_ERROR;
+ END_ERROR
}
return true;
@@ -3052,11 +3142,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 +3160,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 +3171,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 +3183,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 +3200,57 @@ 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]);
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
- }
- 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, 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
}
- 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 +3260,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 +3275,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 +3328,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 +3493,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 +3526,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 +3558,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 +3569,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 +3587,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 +3603,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 +3617,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 +3626,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 +3638,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 +3646,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 +3683,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 +3707,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 +3718,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 +3736,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 +3751,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 +3762,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 +3770,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 +3781,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 +3789,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 +3844,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 +3866,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 +3882,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 +4069,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 +4095,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 +4276,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 +4311,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 +4447,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 +4503,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 +4516,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 +4554,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 +4603,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 +4730,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 +4758,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 +4862,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 +4891,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 +4904,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 +4946,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 +4972,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 +4996,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 +5018,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 +5031,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 +5078,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 +5105,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 +5185,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 +5221,8 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments)
break;
}
}
- END_STORE;
+ }
+ END_STORE
ON_ERROR
general_on_error ();
END_ERROR;
@@ -5094,9 +5244,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 +5293,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 +5319,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 +5361,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 +5407,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 +5433,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 +5478,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 +5501,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 +5599,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 +5654,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 +5957,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 +5977,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 +6026,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 +6308,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 +6328,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 +6340,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 +6375,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 +6654,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 +6674,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 +6715,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,15 +6735,21 @@ bool get_index(BurpGlobals* tdgbl, const burp_rel* relation)
X.RDB$SYSTEM_FLAG = 0;
X.RDB$SYSTEM_FLAG.NULL = FALSE;
- skip_init(&scan_next_attr);
+ 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)
{
switch (attribute)
{
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 +6786,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 +6847,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 +6872,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 +7026,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 +7034,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 +7059,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 +7142,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 +7158,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 +7172,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 +7182,28 @@ bool get_procedure(BurpGlobals* tdgbl)
{
switch (attribute)
{
- case att_procedure_name:
- {
- 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);
+ 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;
- MISC_terminate (X.RDB$PROCEDURE_NAME, temp + prefixLen, l,
- sizeof(temp) - prefixLen);
- BURP_verbose (195, temp);
- // msg 195 restoring stored procedure %s
+ case att_procedure_package_name:
+ if (tdgbl->RESTORE_format >= 10)
+ {
+ 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 +7300,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 +7327,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 +7338,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 +7352,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 +7449,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 +7480,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 +7489,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 (name.schema.hasData())
+ {
+ strcpy(X.RDB$SCHEMA_NAME, name.schema.c_str());
+ X.RDB$SCHEMA_NAME.NULL = FALSE;
+ }
+ else
+ X.RDB$SCHEMA_NAME.NULL = TRUE;
- if (package_name[0])
+ if (name.package.hasData())
{
- strcpy(X.RDB$PACKAGE_NAME, package_name);
+ 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 +7523,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 +7533,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 +7546,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 +7620,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 +7642,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 +7665,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 +7724,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 +7774,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 +7843,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 +7854,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 +7869,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 +7889,11 @@ bool get_pub_table(BurpGlobals* tdgbl)
break;
}
}
- END_STORE;
+ }
+ END_STORE
ON_ERROR
general_on_error ();
- END_ERROR;
+ END_ERROR
}
else
{
@@ -7675,6 +7904,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 +7937,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 +7951,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 +7992,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 +8056,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 +8071,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 +8094,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 +8178,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 +8199,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 +8241,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 +8262,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 +8315,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 +8346,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 +8360,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 +8401,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 +8424,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 +8439,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 +8519,134 @@ 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_sql_security:
+ get_boolean(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;
+ }
+
+ QualifiedMetaString name;
+ bool securityClass = false;
+ 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$SQL_SECURITY.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;
+ name.object = X.RDB$SCHEMA_NAME;
+ BURP_verbose(413, name.object.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_sql_security:
+ X.RDB$SQL_SECURITY = get_boolean(tdgbl, false);
+ X.RDB$SQL_SECURITY.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;
+ securityClass = true;
+ 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
+
+ collect_missing_privs(tdgbl, obj_schema, name, securityClass);
+
+ return true;
+}
+
bool get_sql_roles(BurpGlobals* tdgbl)
{
/**************************************
@@ -8271,7 +8661,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 +8681,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 +8741,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 +8861,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 +8873,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 +9033,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 +9108,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 +9165,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 +9181,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 +9191,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 +9441,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 +9470,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 +9513,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 +9529,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 +9580,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 +9601,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 +9693,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 +9747,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 +9837,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 +9852,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 +9879,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 +9895,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 +9947,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 +10049,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 +10077,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 +10095,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 +10124,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 +10169,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 +10181,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 +10193,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 +10211,10 @@ bool get_user_privilege(BurpGlobals* tdgbl)
case obj_udf:
case obj_field:
case obj_generator:
- {
+ case obj_schema:
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;
@@ -9797,6 +10229,16 @@ bool get_user_privilege(BurpGlobals* tdgbl)
}
}
+ if (object_type == obj_schema)
+ {
+ if (tdgbl->RESTORE_format < 12)
+ return false;
+
+ // Discard schemas for engine < FB6
+ if (tdgbl->runtimeODS < DB_VERSION_DDL14)
+ exists = false;
+ }
+
if (object_type == obj_package_header)
{
if (tdgbl->RESTORE_format < 10)
@@ -9822,13 +10264,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 +10292,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 +10327,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 +10335,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 +10346,7 @@ bool get_user_privilege(BurpGlobals* tdgbl)
return true;
}
general_on_error ();
- END_ERROR;
+ END_ERROR
}
return true;
@@ -9920,8 +10376,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 +10395,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 +10443,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 +10499,8 @@ bool get_view(BurpGlobals* tdgbl, burp_rel* relation)
break;
}
}
- END_STORE;
+ }
+ END_STORE
ON_ERROR
general_on_error ();
END_ERROR;
@@ -10435,6 +10907,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 +10917,13 @@ 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);
- tdgbl->systemFields.add(name);
-
- END_FOR;
+ {
+ tdgbl->systemFields.add(QualifiedMetaString(X.RDB$FIELD_NAME, X.RDB$SCHEMA_NAME));
+ }
+ END_FOR
ON_ERROR
general_on_error();
- END_ERROR;
+ END_ERROR
MISC_release_request_silent(req_handle);
tdgbl->systemFields.sort();
@@ -10474,6 +10945,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 +10955,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 +11003,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 +11035,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 +11106,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 +11133,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 +11276,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 +11352,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 +11437,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 +11445,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 +11500,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 +11533,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 +11546,19 @@ 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),
+ 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 +11566,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 +11584,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;
+
+ 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);
+ 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 +11617,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 +11629,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 +11639,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 +11698,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 +11724,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 +11752,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 +11775,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 +11816,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 +11853,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 +11886,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 +11910,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 +11940,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 +11995,12 @@ 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),
+ 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 +12016,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 +12038,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 +12060,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 +12070,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 +12089,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,10 +12137,11 @@ 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 %s%s TO ' || maxInTable; "
"END",
/* SELECT 1 */ g->field, start, g->table, g->field, start, g->field, g->prefix,
/* SELECT 2 */ g->name,
+ /* SET GEN */ (tdgbl->runtimeODS >= DB_VERSION_DDL14 ? "SYSTEM." : ""),
/* SET GEN */ g->name);
try
@@ -11618,6 +12178,892 @@ static const FixGenerator genToFix[] =
{ NULL, NULL, NULL, NULL }
};
+// Migrate plugins from backup < FB6 from the PUBLIC to specific schemas.
+void fix_plugins_schemas(BurpGlobals* tdgbl)
+{
+ if (tdgbl->RESTORE_format >= 12 || tdgbl->runtimeODS < DB_VERSION_DDL14)
+ return;
+
+ struct PluginMigration
+ {
+ const char* pluginName;
+ const char* schemaName;
+ const char* testQuery;
+ const std::vector migrations;
+ };
+
+ const PluginMigration pluginsMigration[] = {
+ {"PROFILER", "PLG$PROFILER",
+ R"""(
+ select exists(
+ select first 1 1
+ from system.rdb$relations
+ where rdb$schema_name = 'PUBLIC' and
+ rdb$relation_name = 'PLG$PROF_SESSIONS'
+ )
+ from system.rdb$database
+ )""",
+ {
+ R"""(
+ execute block
+ as
+ begin
+ execute statement
+ 'create schema plg$profiler default character set utf8';
+ execute statement
+ 'grant usage on schema plg$profiler to plg$profiler';
+
+ execute statement
+ 'create sequence plg$profiler.plg$prof_profile_id';
+ execute statement
+ 'grant usage on sequence plg$profiler.plg$prof_profile_id to plg$profiler';
+
+ execute statement q'{
+ create table plg$profiler.plg$prof_sessions (
+ profile_id bigint not null,
+ attachment_id bigint not null,
+ user_name char(63) character set utf8 not null,
+ description varchar(255) character set utf8,
+ start_timestamp timestamp with time zone not null,
+ finish_timestamp timestamp with time zone
+ )
+ }';
+
+ execute statement
+ 'grant select, update, insert, delete on table plg$profiler.plg$prof_sessions to plg$profiler';
+
+ execute statement q'{
+ create table plg$profiler.plg$prof_statements (
+ profile_id bigint not null,
+ 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
+ )
+ }';
+ execute statement
+ 'grant select, update, insert, delete on table plg$profiler.plg$prof_statements to plg$profiler';
+
+ execute statement q'{
+ create table plg$profiler.plg$prof_cursors (
+ profile_id bigint not null,
+ statement_id bigint not null,
+ cursor_id integer not null,
+ name char(63) character set utf8,
+ line_num integer,
+ column_num integer
+ )
+ }';
+ execute statement
+ 'grant select, update, insert, delete on table plg$profiler.plg$prof_cursors to plg$profiler';
+
+ execute statement q'{
+ create table plg$profiler.plg$prof_record_sources (
+ profile_id bigint not null,
+ statement_id bigint not null,
+ cursor_id integer not null,
+ record_source_id integer not null,
+ parent_record_source_id integer,
+ level integer not null,
+ access_path blob sub_type text character set utf8 not null
+ )
+ }';
+ execute statement
+ 'grant select, update, insert, delete on table plg$profiler.plg$prof_record_sources to plg$profiler';
+
+ execute statement q'{
+ create table plg$profiler.plg$prof_requests (
+ profile_id bigint not null,
+ statement_id bigint not null,
+ request_id bigint not null,
+ caller_statement_id bigint,
+ caller_request_id bigint,
+ start_timestamp timestamp with time zone not null,
+ finish_timestamp timestamp with time zone,
+ total_elapsed_time bigint
+ )
+ }';
+ execute statement
+ 'grant select, update, insert, delete on table plg$profiler.plg$prof_requests to plg$profiler';
+
+ execute statement q'{
+ create table plg$profiler.plg$prof_psql_stats (
+ profile_id bigint not null,
+ statement_id bigint not null,
+ request_id bigint not null,
+ line_num integer not null,
+ column_num integer not null,
+ counter bigint not null,
+ min_elapsed_time bigint not null,
+ max_elapsed_time bigint not null,
+ total_elapsed_time bigint not null
+ )
+ }';
+ execute statement
+ 'grant select, update, insert, delete on table plg$profiler.plg$prof_psql_stats to plg$profiler';
+
+ execute statement q'{
+ create table plg$profiler.plg$prof_record_source_stats (
+ profile_id bigint not null,
+ statement_id bigint not null,
+ request_id bigint not null,
+ cursor_id integer not null,
+ record_source_id integer not null,
+ open_counter bigint not null,
+ open_min_elapsed_time bigint not null,
+ open_max_elapsed_time bigint not null,
+ open_total_elapsed_time bigint not null,
+ fetch_counter bigint not null,
+ fetch_min_elapsed_time bigint not null,
+ fetch_max_elapsed_time bigint not null,
+ fetch_total_elapsed_time bigint not null
+ )
+ }';
+ execute statement
+ 'grant select, update, insert, delete on table plg$profiler.plg$prof_record_source_stats to plg$profiler';
+
+ execute statement q'{
+ 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$profiler.plg$prof_statements
+ where profile_id = req.profile_id and
+ statement_id = coalesce(sta.parent_statement_id, req.statement_id)
+ ) sql_text,
+ count(*) counter,
+ min(req.total_elapsed_time) min_elapsed_time,
+ 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$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$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,
+ sta_parent.statement_type,
+ sta_parent.routine_name
+ order by sum(req.total_elapsed_time) desc
+ }';
+ execute statement
+ 'grant select on table plg$profiler.plg$prof_statement_stats_view to plg$profiler';
+
+ execute statement q'{
+ 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$profiler.plg$prof_statements
+ where profile_id = pstat.profile_id and
+ statement_id = coalesce(sta.parent_statement_id, pstat.statement_id)
+ ) sql_text,
+ pstat.line_num,
+ pstat.column_num,
+ cast(sum(pstat.counter) as bigint) counter,
+ min(pstat.min_elapsed_time) min_elapsed_time,
+ 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$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$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,
+ sta_parent.statement_type,
+ sta_parent.routine_name,
+ pstat.line_num,
+ pstat.column_num
+ order by sum(pstat.total_elapsed_time) desc
+ }';
+ execute statement
+ 'grant select on table plg$profiler.plg$prof_psql_stats_view to plg$profiler';
+
+ execute statement q'{
+ 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$profiler.plg$prof_statements
+ where profile_id = rstat.profile_id and
+ statement_id = coalesce(sta.parent_statement_id, rstat.statement_id)
+ ) sql_text,
+ rstat.cursor_id,
+ cur.name cursor_name,
+ cur.line_num cursor_line_num,
+ cur.column_num cursor_column_num,
+ rstat.record_source_id,
+ recsrc.parent_record_source_id,
+ recsrc.level,
+ recsrc.access_path,
+ cast(sum(rstat.open_counter) as bigint) open_counter,
+ min(rstat.open_min_elapsed_time) open_min_elapsed_time,
+ max(rstat.open_max_elapsed_time) open_max_elapsed_time,
+ cast(sum(rstat.open_total_elapsed_time) as bigint) open_total_elapsed_time,
+ cast(sum(rstat.open_total_elapsed_time) / nullif(sum(rstat.open_counter), 0) as bigint) open_avg_elapsed_time,
+ cast(sum(rstat.fetch_counter) as bigint) fetch_counter,
+ min(rstat.fetch_min_elapsed_time) fetch_min_elapsed_time,
+ max(rstat.fetch_max_elapsed_time) fetch_max_elapsed_time,
+ 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$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$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$profiler.plg$prof_statements sta
+ on sta.profile_id = rstat.profile_id and
+ sta.statement_id = rstat.statement_id
+ 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,
+ sta_parent.statement_type,
+ sta_parent.routine_name,
+ rstat.cursor_id,
+ cur.name,
+ cur.line_num,
+ cur.column_num,
+ rstat.record_source_id,
+ recsrc.parent_record_source_id,
+ recsrc.level,
+ recsrc.access_path
+ order by coalesce(sum(rstat.open_total_elapsed_time), 0) + coalesce(sum(rstat.fetch_total_elapsed_time), 0) desc
+ }';
+ execute statement
+ 'grant select on table plg$profiler.plg$prof_record_source_stats_view to plg$profiler';
+ end
+ )""",
+
+ R"""(
+ execute block
+ as
+ begin
+ insert into plg$profiler.plg$prof_sessions
+ (profile_id,
+ attachment_id,
+ user_name,
+ description,
+ start_timestamp,
+ finish_timestamp
+ )
+ select profile_id,
+ attachment_id,
+ user_name,
+ description,
+ start_timestamp,
+ finish_timestamp
+ from public.plg$prof_sessions;
+
+ insert into plg$profiler.plg$prof_statements
+ (profile_id,
+ statement_id,
+ parent_statement_id,
+ statement_type,
+ schema_name,
+ package_name,
+ routine_name,
+ sql_text
+ )
+ select profile_id,
+ statement_id,
+ parent_statement_id,
+ statement_type,
+ case when routine_name is null then null else 'PUBLIC' end,
+ package_name,
+ routine_name,
+ sql_text
+ from public.plg$prof_statements;
+
+ insert into plg$profiler.plg$prof_cursors
+ (profile_id,
+ statement_id,
+ cursor_id,
+ name,
+ line_num,
+ column_num
+ )
+ select profile_id,
+ statement_id,
+ cursor_id,
+ name,
+ line_num,
+ column_num
+ from public.plg$prof_cursors;
+
+ insert into plg$profiler.plg$prof_record_sources
+ (profile_id,
+ statement_id,
+ cursor_id,
+ record_source_id,
+ parent_record_source_id,
+ level,
+ access_path
+ )
+ select profile_id,
+ statement_id,
+ cursor_id,
+ record_source_id,
+ parent_record_source_id,
+ level,
+ access_path
+ from public.plg$prof_record_sources;
+
+ 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
+ )
+ select profile_id,
+ statement_id,
+ request_id,
+ caller_statement_id,
+ caller_request_id,
+ start_timestamp,
+ finish_timestamp,
+ total_elapsed_time
+ from public.plg$prof_requests;
+
+ insert into plg$profiler.plg$prof_psql_stats
+ (profile_id,
+ statement_id,
+ request_id,
+ line_num,
+ column_num,
+ counter,
+ min_elapsed_time,
+ max_elapsed_time,
+ total_elapsed_time
+ )
+ select profile_id,
+ statement_id,
+ request_id,
+ line_num,
+ column_num,
+ counter,
+ min_elapsed_time,
+ max_elapsed_time,
+ total_elapsed_time
+ from public.plg$prof_psql_stats;
+
+ insert into plg$profiler.plg$prof_record_source_stats
+ (profile_id,
+ statement_id,
+ request_id,
+ cursor_id,
+ record_source_id,
+ open_counter,
+ open_min_elapsed_time,
+ open_max_elapsed_time,
+ open_total_elapsed_time,
+ fetch_counter,
+ fetch_min_elapsed_time,
+ fetch_max_elapsed_time,
+ fetch_total_elapsed_time
+ )
+ select profile_id,
+ statement_id,
+ request_id,
+ cursor_id,
+ record_source_id,
+ open_counter,
+ open_min_elapsed_time,
+ open_max_elapsed_time,
+ open_total_elapsed_time,
+ fetch_counter,
+ fetch_min_elapsed_time,
+ fetch_max_elapsed_time,
+ fetch_total_elapsed_time
+ from public.plg$prof_record_source_stats;
+ end
+ )""",
+
+ R"""(
+ execute block
+ as
+ begin
+ execute statement
+ 'alter sequence plg$profiler.plg$prof_profile_id restart with ' ||
+ (select gen_id(public.plg$prof_profile_id, 1) from system.rdb$database);
+ end
+ )""",
+
+ R"""(
+ alter table plg$profiler.plg$prof_sessions
+ add constraint plg$prof_sessions_pk
+ primary key (profile_id)
+ using index plg$prof_sessions_profile
+ )""",
+
+ R"""(
+ alter table plg$profiler.plg$prof_statements
+ add constraint plg$prof_statements_session_fk
+ foreign key (profile_id)
+ references plg$profiler.plg$prof_sessions
+ on delete cascade
+ using index plg$prof_statements_profile,
+ add constraint plg$prof_statements_pk
+ primary key (profile_id, statement_id)
+ using index plg$prof_statements_profile_statement,
+ add constraint plg$prof_statements_parent_statement_fk
+ 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
+ )""",
+
+ R"""(
+ alter table plg$profiler.plg$prof_cursors
+ add constraint plg$prof_cursors_session_fk
+ foreign key (profile_id)
+ references plg$profiler.plg$prof_sessions
+ on delete cascade
+ using index plg$prof_cursors_profile,
+ add constraint plg$prof_cursors_pk
+ primary key (profile_id, statement_id, cursor_id)
+ using index plg$prof_cursors_profile_statement_cursor,
+ add constraint plg$prof_cursors_statement_fk
+ foreign key (profile_id, statement_id) references plg$profiler.plg$prof_statements
+ on delete cascade
+ using index plg$prof_cursors_profile_statement
+ )""",
+
+ R"""(
+ alter table plg$profiler.plg$prof_record_sources
+ add constraint plg$prof_record_sources_session_fk
+ foreign key (profile_id)
+ references plg$profiler.plg$prof_sessions
+ on delete cascade
+ using index plg$prof_record_sources_profile,
+ add constraint plg$prof_record_sources_pk
+ primary key (profile_id, statement_id, cursor_id, record_source_id)
+ using index plg$prof_record_sources_profile_statement_cursor_recsource,
+ add constraint plg$prof_record_sources_statement_fk
+ foreign key (profile_id, statement_id) references plg$profiler.plg$prof_statements
+ on delete cascade
+ using index plg$prof_record_sources_profile_statement,
+ add constraint plg$prof_record_sources_cursor_fk
+ 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,
+ add constraint plg$prof_record_sources_parent_record_source_fk
+ foreign key (profile_id, statement_id, cursor_id, parent_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
+ )""",
+
+ R"""(
+ alter table plg$profiler.plg$prof_requests
+ add constraint plg$prof_requests_session_fk
+ foreign key (profile_id)
+ references plg$profiler.plg$prof_sessions
+ on delete cascade
+ using index plg$prof_requests_profile,
+ add constraint plg$prof_requests_pk
+ primary key (profile_id, statement_id, request_id)
+ using index plg$prof_requests_profile_request_statement,
+ add constraint plg$prof_requests_statement_fk
+ foreign key (profile_id, statement_id) references plg$profiler.plg$prof_statements
+ on delete cascade
+ using index plg$prof_requests_profile_statement,
+ add constraint plg$prof_requests_caller_statement_fk
+ foreign key (profile_id, caller_statement_id) references plg$profiler.plg$prof_statements
+ on delete cascade
+ using index plg$prof_requests_profile_caller_statement,
+ add constraint plg$prof_requests_caller_request_fk
+ foreign key (profile_id, caller_statement_id, caller_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
+ )""",
+
+ R"""(
+ alter table plg$profiler.plg$prof_psql_stats
+ add constraint plg$prof_psql_stats_session_fk
+ foreign key (profile_id)
+ references plg$profiler.plg$prof_sessions
+ on delete cascade
+ using index plg$prof_psql_stats_profile,
+ add constraint plg$prof_psql_stats_pk
+ primary key (profile_id, statement_id, request_id, line_num, column_num)
+ using index plg$prof_psql_stats_profile_statement_request_line_column,
+ add constraint plg$prof_psql_stats_request_fk
+ 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,
+ add constraint plg$prof_psql_stats_statement_fk
+ foreign key (profile_id, statement_id) references plg$profiler.plg$prof_statements
+ on delete cascade
+ using index plg$prof_psql_stats_profile_statement
+ )""",
+
+ R"""(
+ alter table plg$profiler.plg$prof_record_source_stats
+ add constraint plg$prof_record_source_stats_session_fk
+ foreign key (profile_id)
+ references plg$profiler.plg$prof_sessions
+ on delete cascade
+ using index plg$prof_record_source_stats_profile_id,
+ add constraint plg$prof_record_source_stats_pk
+ 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,
+ add constraint plg$prof_record_source_stats_request_fk
+ 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,
+ add constraint plg$prof_record_source_stats_statement_fk
+ foreign key (profile_id, statement_id) references plg$profiler.plg$prof_statements
+ on delete cascade
+ using index plg$prof_record_source_stats_profile_statement,
+ add constraint plg$prof_record_source_stats_cursor_fk
+ 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,
+ add constraint plg$prof_record_source_stats_record_source_fk
+ 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
+ )""",
+
+ R"""(
+ execute block
+ as
+ begin
+ execute statement
+ 'drop sequence public.plg$prof_profile_id';
+
+ execute statement
+ 'drop view public.plg$prof_statement_stats_view';
+ execute statement
+ 'drop view public.plg$prof_psql_stats_view';
+ execute statement
+ 'drop view public.plg$prof_record_source_stats_view';
+
+ execute statement
+ 'drop table public.plg$prof_psql_stats';
+ execute statement
+ 'drop table public.plg$prof_record_source_stats';
+ execute statement
+ 'drop table public.plg$prof_record_sources';
+ execute statement
+ 'drop table public.plg$prof_cursors';
+ execute statement
+ 'drop table public.plg$prof_requests';
+ execute statement
+ 'drop table public.plg$prof_statements';
+ execute statement
+ 'drop table public.plg$prof_sessions';
+ end
+ )""",
+ }
+ },
+
+ {"SRP", "PLG$SRP",
+ R"""(
+ select exists(
+ select first 1 1
+ from system.rdb$relations
+ where rdb$schema_name = 'PUBLIC' and
+ rdb$relation_name = 'PLG$SRP'
+ )
+ from system.rdb$database
+ )""",
+ {
+ R"""(
+ execute block
+ as
+ begin
+ execute statement
+ 'CREATE SCHEMA PLG$SRP DEFAULT CHARACTER SET UTF8';
+ execute statement
+ 'GRANT USAGE ON SCHEMA PLG$SRP TO PUBLIC';
+
+ execute statement q'{
+ CREATE TABLE PLG$SRP.PLG$SRP (PLG$USER_NAME SYSTEM.SEC$USER_NAME NOT NULL,
+ PLG$VERIFIER VARCHAR(128) CHARACTER SET OCTETS NOT NULL,
+ PLG$SALT VARCHAR(32) CHARACTER SET OCTETS NOT NULL,
+ 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
+ )
+ }';
+
+ execute statement q'{
+ CREATE VIEW PLG$SRP.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.PLG$SRP WHERE RDB$SYSTEM_PRIVILEGE(USER_MANAGEMENT)
+ OR CURRENT_USER = PLG$SRP.PLG$USER_NAME
+ }';
+
+ execute statement
+ 'GRANT ALL ON PLG$SRP.PLG$SRP TO VIEW PLG$SRP.PLG$SRP_VIEW';
+ execute statement
+ 'GRANT SELECT ON PLG$SRP.PLG$SRP_VIEW TO PUBLIC';
+ execute statement
+ 'GRANT UPDATE(PLG$VERIFIER, PLG$SALT, PLG$FIRST, PLG$MIDDLE, PLG$LAST,
+ PLG$COMMENT, PLG$ATTRIBUTES) ON PLG$SRP.PLG$SRP_VIEW TO PUBLIC';
+ execute statement 'GRANT ALL ON PLG$SRP.PLG$SRP_VIEW TO SYSTEM PRIVILEGE USER_MANAGEMENT';
+ end
+ )""",
+
+ R"""(
+ insert into plg$srp.plg$srp
+ (plg$user_name,
+ plg$verifier,
+ plg$salt,
+ plg$comment,
+ plg$middle,
+ plg$attributes,
+ plg$active
+ )
+ select plg$user_name,
+ plg$verifier,
+ plg$salt,
+ plg$comment,
+ plg$middle,
+ plg$attributes,
+ plg$active
+ from public.plg$srp
+ )""",
+
+ R"""(
+ alter table plg$srp.plg$srp add primary key (plg$user_name)
+ )""",
+
+ R"""(
+ execute block
+ as
+ begin
+ execute statement
+ 'drop view public.plg$srp_view';
+
+ execute statement
+ 'drop table public.plg$srp';
+ end
+ )""",
+ }
+ },
+
+ {"LEGACY_SEC", "PLG$LEGACY_SEC",
+ R"""(
+ select exists(
+ select first 1 1
+ from system.rdb$relations
+ where rdb$schema_name = 'PUBLIC' and
+ rdb$relation_name = 'PLG$USERS'
+ )
+ from system.rdb$database
+ )""",
+ {
+ R"""(
+ execute block
+ as
+ begin
+ execute statement
+ 'CREATE SCHEMA PLG$LEGACY_SEC DEFAULT CHARACTER SET UTF8';
+ execute statement
+ 'GRANT USAGE ON SCHEMA PLG$LEGACY_SEC TO PUBLIC';
+
+ execute statement q'{
+ CREATE DOMAIN PLG$LEGACY_SEC.PLG$PASSWD AS VARBINARY(64)
+ }';
+
+ execute statement q'{
+ CREATE DOMAIN PLG$LEGACY_SEC.PLG$ID AS INTEGER
+ }';
+
+ execute statement q'{
+ CREATE TABLE PLG$LEGACY_SEC.PLG$USERS (
+ PLG$USER_NAME SYSTEM.SEC$USER_NAME NOT NULL,
+ PLG$GROUP_NAME SYSTEM.SEC$USER_NAME,
+ PLG$UID PLG$LEGACY_SEC.PLG$ID,
+ PLG$GID PLG$LEGACY_SEC.PLG$ID,
+ PLG$PASSWD PLG$LEGACY_SEC.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
+ )
+ }';
+
+ execute statement q'{
+ CREATE VIEW PLG$LEGACY_SEC.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$LEGACY_SEC.PLG$USERS
+ WHERE CURRENT_USER = 'SYSDBA'
+ OR CURRENT_ROLE = 'RDB$ADMIN'
+ OR CURRENT_USER = PLG$USERS.PLG$USER_NAME
+ }';
+
+ execute statement
+ 'GRANT ALL ON PLG$LEGACY_SEC.PLG$USERS to VIEW PLG$LEGACY_SEC.PLG$VIEW_USERS';
+ execute statement
+ 'GRANT SELECT ON PLG$LEGACY_SEC.PLG$VIEW_USERS to PUBLIC';
+ execute statement
+ 'GRANT UPDATE(PLG$PASSWD, PLG$GROUP_NAME, PLG$UID, PLG$GID, PLG$FIRST_NAME, PLG$MIDDLE_NAME, PLG$LAST_NAME)
+ ON PLG$LEGACY_SEC.PLG$VIEW_USERS TO PUBLIC';
+ end
+ )""",
+
+ R"""(
+ insert into plg$legacy_sec.plg$users
+ (plg$user_name,
+ plg$group_name,
+ plg$uid,
+ plg$gid,
+ plg$passwd,
+ plg$comment,
+ plg$first_name,
+ plg$middle_name,
+ plg$last_name
+ )
+ 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 public.plg$users
+ )""",
+
+ R"""(
+ alter table plg$legacy_sec.plg$users add primary key (plg$user_name)
+ )""",
+
+ R"""(
+ execute block
+ as
+ begin
+ execute statement
+ 'drop view public.plg$view_users';
+
+ execute statement
+ 'drop table public.plg$users';
+
+ execute statement
+ 'drop domain public.plg$passwd';
+ execute statement
+ 'drop domain public.plg$id';
+ end
+ )""",
+ }
+ },
+ };
+
+ for (const auto& pluginMigration : pluginsMigration)
+ {
+ try
+ {
+ BurpSql testStmt(tdgbl, pluginMigration.testQuery);
+ FB_MESSAGE(TestQueryMessage, ThrowWrapper, (FB_BOOLEAN, exists));
+ TestQueryMessage testQueryMessage(&tdgbl->throwStatus, MasterInterfacePtr());
+
+ testStmt.singleSelect(tdgbl->tr_handle, &testQueryMessage);
+
+ if (testQueryMessage->exists)
+ {
+ BURP_message(
+ 421, // isc_gbak_plugin_schema_migration
+ SafeArg() <<
+ pluginMigration.pluginName <<
+ MetaString(pluginMigration.schemaName).toQuotedString().c_str());
+
+ for (const auto migration : pluginMigration.migrations)
+ {
+ BurpSql migrationStmt(tdgbl, migration);
+ migrationStmt.execute(gds_trans);
+ gds_trans->commitRetaining(&tdgbl->throwStatus);
+ }
+ }
+ }
+ catch (const status_exception& ex)
+ {
+ LocalStatus ls;
+ ex.stuffException(&ls);
+
+ BURP_msg_partial(false, 255); // msg 255: gbak: WARNING:
+ BURP_msg_put(
+ false,
+ 422, // isc_gbak_plugin_schema_migration_err
+ SafeArg() <<
+ pluginMigration.pluginName <<
+ MetaString(pluginMigration.schemaName).toQuotedString().c_str());
+
+ BURP_print_warning(&ls, true);
+ }
+ }
+}
+
void fix_system_generators(BurpGlobals* tdgbl)
{
/**************************************
@@ -11848,7 +13294,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);
@@ -11877,10 +13323,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));
@@ -11942,9 +13385,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++;
@@ -12024,7 +13465,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);
@@ -12171,8 +13613,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);
@@ -12205,6 +13658,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);
}
@@ -12359,7 +13813,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 df92765bccb..fac57deec74 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;
}
@@ -316,6 +317,8 @@ IntlParametersBlock::TagType IntlSpbStart::checkTag(UCHAR tag, const char** tagN
{
FB_IPB_TAG(isc_spb_sts_table);
return TAG_STRING;
+ FB_IPB_TAG(isc_spb_sts_schema);
+ return TAG_STRING;
FB_IPB_TAG(isc_spb_command_line);
return TAG_COMMAND_LINE;
}
@@ -324,6 +327,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 fa428a7cdab..657f4f2d019 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 f39307764e6..cfd241daa9c 100644
--- a/src/common/MsgMetadata.h
+++ b/src/common/MsgMetadata.h
@@ -50,6 +50,7 @@ class MsgMetadata : public RefCntIfacefield);
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 858b9fb5c8a..420d3ed2929 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 @@ class TextType
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 8a8f9b9eaca..cc654220d28 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 @@ class BlrReader
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 df1232e2cd4..4df7f794012 100644
--- a/src/common/classes/ClumpletReader.cpp
+++ b/src/common/classes/ClumpletReader.cpp
@@ -292,10 +292,11 @@ ClumpletReader::ClumpletType ClumpletReader::getClumpletType(UCHAR tag) const
case Tpb:
switch (tag)
{
- case isc_tpb_lock_write:
- case isc_tpb_lock_read:
+ case isc_tpb_lock_write:
+ case isc_tpb_lock_read:
case isc_tpb_lock_timeout:
case isc_tpb_at_snapshot_number:
+ case isc_tpb_lock_table_schema:
return TraditionalDpb;
}
return SingleTpb;
@@ -436,6 +437,7 @@ ClumpletReader::ClumpletType ClumpletReader::getClumpletType(UCHAR tag) const
case isc_spb_dbname:
case isc_spb_command_line:
case isc_spb_sts_table:
+ case isc_spb_sts_schema:
return StringSpb;
case isc_spb_options:
return IntSpb;
@@ -490,6 +492,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 6c954d3c07f..874626f5fbc 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
@@ -39,6 +43,31 @@
namespace Firebird {
+template
+string toQuotedString(const T& name)
+{
+ string s;
+
+ if (name.hasData())
+ {
+ s.reserve(name.length() + 2);
+
+ s.append("\"");
+
+ for (const auto c : name)
+ {
+ if (c == '"')
+ s.append("\"");
+
+ s.append(&c, 1);
+ }
+
+ s.append("\"");
+ }
+
+ return s;
+}
+
class MetaString
{
private:
@@ -68,6 +97,122 @@ class MetaString
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)
+ {
+ if (name.length() > MAX_SQL_IDENTIFIER_LEN)
+ (Arg::Gds(isc_invalid_name) << str).raise();
+
+ 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); }
@@ -95,26 +240,7 @@ class MetaString
string toQuotedString() const
{
- string s;
-
- if (hasData())
- {
- s.reserve(count + 2);
-
- s.append("\"");
-
- for (const auto c : *this)
- {
- if (c == '"')
- s.append("\"");
-
- s.append(&c, 1);
- }
-
- s.append("\"");
- }
-
- return s;
+ return Firebird::toQuotedString(*this);
}
bool operator==(const char* s) const { return compare(s) == 0; }
diff --git a/src/common/classes/QualifiedMetaString.h b/src/common/classes/QualifiedMetaString.h
new file mode 100644
index 00000000000..124d0402589
--- /dev/null
+++ b/src/common/classes/QualifiedMetaString.h
@@ -0,0 +1,365 @@
+/*
+ * 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/classes/objects_array.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),
+ unambiguous(src.isUnambiguous())
+ {
+ }
+
+ BaseQualifiedName(const BaseQualifiedName& src)
+ : object(src.object),
+ schema(src.schema),
+ package(src.package),
+ unambiguous(src.isUnambiguous())
+ {
+ }
+
+ template
+ BaseQualifiedName(const BaseQualifiedName& src)
+ : object(src.object),
+ schema(src.schema),
+ package(src.package),
+ unambiguous(src.isUnambiguous())
+ {
+ }
+
+ explicit BaseQualifiedName(MemoryPool& p)
+ : object(p),
+ schema(p),
+ package(p)
+ {
+ }
+
+ BaseQualifiedName()
+ {
+ }
+
+public:
+ static void parseSchemaObjectListNoSep(const string& str, ObjectsArray>& list)
+ {
+ 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)
+ {
+ if (name.length() > MAX_SQL_IDENTIFIER_LEN)
+ (Arg::Gds(isc_invalid_name) << str).raise();
+
+ 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;
+ };
+
+ size_t i = 0;
+
+ const auto skipSpaces = [&]()
+ {
+ while (i < str.size() &&
+ (str[i] == ' ' || str[i] == '\t' || str[i] == '\f' || str[i] == '\r' || str[i] == '\n'))
+ {
+ ++i;
+ }
+ };
+
+ skipSpaces();
+
+ do
+ {
+ BaseQualifiedName result;
+ string schema, object;
+
+ const auto start = i;
+ bool nameFound = false;
+ bool inQuotes = false;
+ auto dotPos = string::npos;
+
+ for (; !nameFound && i < str.size(); ++i)
+ {
+ const auto ch = str[i];
+
+ if (inQuotes)
+ {
+ if (ch == '"')
+ {
+ if (i + 1 < str.size() && str[i + 1] == '"')
+ ++i;
+ else
+ inQuotes = false;
+ }
+ }
+ else
+ {
+ switch (ch)
+ {
+ case '"':
+ inQuotes = true;
+ break;
+
+ case '.':
+ {
+ dotPos = i++;
+ skipSpaces();
+ --i;
+ break;
+ }
+
+ case ' ':
+ case '\t':
+ case '\f':
+ case '\r':
+ case '\n':
+ {
+ skipSpaces();
+
+ if (i < str.size() && str[i] == '.')
+ {
+ dotPos = i++;
+ skipSpaces();
+ }
+ else
+ nameFound = true;
+
+ --i;
+ break;
+ }
+ }
+ }
+ }
+
+ if (dotPos != string::npos)
+ {
+ schema = str.substr(start, dotPos - start);
+ object = str.substr(dotPos + 1, i - dotPos - 1);
+ }
+ else
+ object = str.substr(start, i - start);
+
+ 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 (dotPos != 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();
+
+ list.add(result);
+ } while (i < str.size());
+ }
+
+ static BaseQualifiedName parseSchemaObject(const string& str)
+ {
+ ObjectsArray> list;
+ parseSchemaObjectListNoSep(str, list);
+
+ if (list.getCount() != 1)
+ (Arg::Gds(isc_invalid_name) << str).raise();
+
+ return list[0];
+ }
+
+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:
+ bool isUnambiguous() const
+ {
+ return unambiguous;
+ }
+
+ void setUnambiguous(bool value)
+ {
+ unambiguous = value;
+ }
+
+ 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;
+
+private:
+ bool unambiguous = false;
+};
+
+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 8b3ff24d9d1..648fa7c1ff1 100644
--- a/src/common/classes/array.h
+++ b/src/common/classes/array.h
@@ -145,6 +145,13 @@ class Array : protected Storage
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 449173d09b0..c7fb9f58a60 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 00000000000..35f0f732e40
--- /dev/null
+++ b/src/common/classes/tests/MetaStringTest.cpp
@@ -0,0 +1,73 @@
+#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 00000000000..cc646d81f28
--- /dev/null
+++ b/src/common/classes/tests/QualifiedMetaStringTest.cpp
@@ -0,0 +1,100 @@
+#include "boost/test/unit_test.hpp"
+#include "boost/test/data/test_case.hpp"
+#include "../common/classes/QualifiedMetaString.h"
+#include
+#include
+
+using namespace Firebird;
+using std::make_tuple;
+
+
+BOOST_AUTO_TEST_SUITE(QualifiedMetaStringSuite)
+BOOST_AUTO_TEST_SUITE(QualifiedMetaStringTests)
+
+
+const auto parseSchemaObjectListNoSepTestData = 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\""),
+ make_tuple("Schema1 . Obj1 Schema2.Obj2 Obj3 ", "\"SCHEMA1\".\"OBJ1\", \"SCHEMA2\".\"OBJ2\", \"OBJ3\""),
+});
+
+BOOST_DATA_TEST_CASE(ParseSchemaObjectListNoSepTest, parseSchemaObjectListNoSepTestData, input, formattedList)
+{
+ const auto parseAndFormatList = [](const char* input) -> std::string
+ {
+ ObjectsArray list;
+ QualifiedMetaString::parseSchemaObjectListNoSep(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.object.hasData() ? b.toQuotedString().c_str() : "\" \"");
+ }
+ );
+ }
+ else
+ return {};
+ };
+
+ BOOST_TEST(parseAndFormatList(input) == formattedList);
+}
+
+
+const auto parseSchemaObjectTestData = 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(ParseSchemaObjectTest, parseSchemaObjectTestData, input, expectedSchema, expectedObject)
+{
+ const auto name = QualifiedMetaString::parseSchemaObject(input);
+ BOOST_TEST(name.schema == MetaString(expectedSchema));
+ BOOST_TEST(name.object == MetaString(expectedObject));
+}
+
+
+const auto parseSchemaObjectErrorTestData = 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(ParseSchemaObjectErrorTest, parseSchemaObjectErrorTestData, 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 d1a0e6956dd..b744fb9547d 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 0059a6bda39..a730dad586f 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 ff8016a3a1e..f3914f04a3a 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 c1849817071..c6043f90095 100644
--- a/src/dbs/security.sql
+++ b/src/dbs/security.sql
@@ -22,9 +22,12 @@
* (see http://www.volny.cz/iprenosil/interbase/ for details).
*/
+/* Schema definition */
+CREATE SCHEMA PLG$LEGACY_SEC DEFAULT CHARACTER SET UTF8;
+
/* Domain definitions */
-CREATE DOMAIN PLG$PASSWD AS VARBINARY(64);
-CREATE DOMAIN PLG$ID AS INTEGER;
+CREATE DOMAIN PLG$LEGACY_SEC.PLG$PASSWD AS VARBINARY(64);
+CREATE DOMAIN PLG$LEGACY_SEC.PLG$ID AS INTEGER;
COMMIT;
@@ -36,41 +39,42 @@ 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 PLG$LEGACY_SEC.PLG$USERS (
+ PLG$USER_NAME SYSTEM.SEC$USER_NAME NOT NULL PRIMARY KEY,
+ PLG$GROUP_NAME SYSTEM.SEC$USER_NAME,
+ PLG$UID PLG$LEGACY_SEC.PLG$ID,
+ PLG$GID PLG$LEGACY_SEC.PLG$ID,
+ PLG$PASSWD PLG$LEGACY_SEC.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 PLG$LEGACY_SEC.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 PLG$LEGACY_SEC.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 USAGE ON SCHEMA PLG$LEGACY_SEC TO PUBLIC;
+GRANT ALL ON PLG$LEGACY_SEC.PLG$USERS to VIEW PLG$LEGACY_SEC.PLG$VIEW_USERS;
+GRANT SELECT ON PLG$LEGACY_SEC.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 PLG$LEGACY_SEC.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 PLG$LEGACY_SEC.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 864264b0668..a6b43aeaf0e 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 b05b60912ad..320a1cb8cf8 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,33 @@ 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.toQuotedString() <<
+ 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 +298,26 @@ 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.toQuotedString() <<
+ relationName.toQuotedString() <<
+ viewName.toQuotedString());
}
END_FOR
}
@@ -312,8 +329,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 +477,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 +488,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 +500,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 +513,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 +543,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 +559,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 +577,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 +615,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 +630,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 +664,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 +677,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 +701,10 @@ 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.toQuotedString() <<
+ relationName.toQuotedString());
}
// Find the position of the last field in the relation.
@@ -699,9 +723,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 +772,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 +780,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 +899,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 +917,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 +930,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 +958,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 +975,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 +990,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 +1005,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 +1028,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 +1037,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 +1105,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 +1174,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 +1196,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 +1315,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 +1323,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 +1353,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 +1375,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 +1383,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;
+ }
+
+ 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;
}
- dsc dscName;
- MetaName relationName;
+ 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 +1508,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 +1522,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 +1629,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 +1661,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 +1706,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 +1715,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 +1758,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 +1769,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 +1794,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 +1819,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 +1830,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 +1870,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 +1915,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 +1935,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 +1962,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 +2094,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 +2114,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 +2137,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 +2148,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 +2199,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 +2215,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 +2237,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 +2247,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 +2278,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 +2326,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.toQuotedString());
}
ARG.RDB$DEFAULT_VALUE.NULL = FALSE;
@@ -2282,7 +2392,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 +2442,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 +2486,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 +2515,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 +2539,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 +2574,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 +2609,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 +2619,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 +2636,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 +2696,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 +2745,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 +2753,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 +2796,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 +2807,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 +2832,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 +2843,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 +2857,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 +2868,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 +2879,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 +2908,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 +2945,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 +2964,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 +2995,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 +3069,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 +3101,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 +3126,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 +3137,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 +3183,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 +3206,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 +3262,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.toQuotedString());
}
attachment->storeMetaDataBlob(tdbb, transaction, &PRM.RDB$DEFAULT_SOURCE,
@@ -3183,7 +3304,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 +3357,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 +3401,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 +3418,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 +3435,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 +3445,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 +3462,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 +3522,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 +3558,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 +3570,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 +3588,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 +3597,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 +3619,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 +3643,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 +3731,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 +3788,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 +3833,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 +3848,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 +3880,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 +3974,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 +4020,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 +4054,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 +4063,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()
- {
- MODIFY F USING
- F.RDB$UPDATE_FLAG = FALSE;
- END_MODIFY
+ 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
+ {
+ 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 +4132,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 +4147,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 +4157,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 +4171,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 +4209,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 +4244,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 +4284,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 +4304,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 +4315,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 +4344,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 +4371,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 +4382,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 +4408,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 EQ 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 EQ 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 +4449,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 EQ 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 +4478,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 +4494,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 +4513,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 +4524,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 +4556,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 +4633,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 +5028,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 +5059,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 +5072,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 +5112,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 +5135,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 +5184,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 +5199,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 +5244,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 +5280,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 +5315,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 +5397,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 +5414,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 +5461,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 +5474,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 +5490,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 +5504,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 +5523,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 +5555,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 +5565,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 +5585,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 +5601,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 +5618,16 @@ 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).toQuotedString() <<
+ MetaName(X.RDB$PARAMETER_NAME).toQuotedString());
}
END_FOR
@@ -5442,18 +5635,16 @@ 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).toQuotedString() <<
+ MetaName(X.RDB$ARGUMENT_NAME).toQuotedString());
}
END_FOR
}
@@ -5482,11 +5673,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 +5705,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 +5713,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 +5735,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 +5762,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 +5773,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 +5787,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 +5822,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 +5838,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 +5875,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 +5895,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 +5928,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 +5937,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 +5947,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 +5974,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 +5984,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 +5992,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 +6009,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 +6026,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 +6045,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 +6089,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 +6156,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 +6179,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 +6225,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 +6284,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 +6301,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 +6325,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 +6384,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 +6477,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 +6500,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 +6516,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.toQuotedString() <<
+ relationName.toQuotedString() <<
+ QualifiedName(Y.RDB$RELATION_NAME, Y.RDB$SCHEMA_NAME).toQuotedString());
}
END_FOR
@@ -6280,25 +6534,29 @@ 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.toQuotedString() <<
+ relationName.toQuotedString() <<
+ MetaName(IDX.RDB$INDEX_NAME).toQuotedString());
}
}
END_FOR
@@ -6314,11 +6572,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,8 +6587,9 @@ 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 <<
- fb_utils::exact_name_limit(IDX.RDB$INDEX_NAME, sizeof(IDX.RDB$INDEX_NAME)));
+ fieldName.toQuotedString() <<
+ relationName.toQuotedString() <<
+ MetaName(IDX.RDB$INDEX_NAME).toQuotedString());
}
END_FOR
@@ -6340,12 +6602,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 +6622,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$FIELD_SOURCE_SCHEMA_NAME));
}
END_FOR
@@ -6364,7 +6631,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 EQ 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 +6646,10 @@ 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.toQuotedString() <<
+ relationName.toQuotedString());
}
return found;
@@ -6414,7 +6685,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 +6694,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 +6718,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 +6732,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,10 +6748,14 @@ 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 if (field->collate.hasData())
+ else if (field->collate.object.hasData())
{
// Resolve possible additional collation for domains. For plain types it is already resolved above.
DDL_resolve_intl_type(dsqlScratch, field, field->collate);
@@ -6494,7 +6769,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)
@@ -6503,7 +6779,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;
@@ -6512,9 +6788,12 @@ 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.toQuotedString() <<
+ name.toQuotedString());
}
+ fieldDefinition.identitySequence.schema = fieldDefinition.relationName.schema;
DYN_UTIL_generate_generator_name(tdbb, fieldDefinition.identitySequence);
fieldDefinition.identityType = clause->identityOptions->type;
@@ -6540,7 +6819,7 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
}
fieldDefinition.defaultValue = defaultValue;
- if (field->typeOfName.isEmpty() || field->collate.hasData())
+ if (field->typeOfName.object.isEmpty() || field->collate.object.hasData())
fieldDefinition.collationId = field->collationId;
fieldDefinition.store(tdbb, transaction);
@@ -6620,8 +6899,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 +6958,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 +7043,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 +7058,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 +7107,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 +7130,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 +7141,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 +7161,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 EQ 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 +7177,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 +7190,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 +7214,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 +7243,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 +7266,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 +7318,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 +7373,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 +7407,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 +7489,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 +7505,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 +7547,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 +7564,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 +7594,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 +7634,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 +7655,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 +7757,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 +7766,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 +7775,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 +7807,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 +7827,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 +7840,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 +7934,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 +7973,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 +7989,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 +8003,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 +8014,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 +8042,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 +8078,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 +8098,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 +8107,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 +8115,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 +8143,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 +8153,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 +8177,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 +8198,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 +8262,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 +8296,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 +8374,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 +8391,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 +8470,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 = RFR.RDB$FIELD_SOURCE_SCHEMA_NAME AND
+ FLD.RDB$FIELD_NAME = RFR.RDB$FIELD_SOURCE
{
found = true;
@@ -8137,7 +8494,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 +8502,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 +8528,9 @@ 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.toQuotedString() <<
+ name.toQuotedString());
}
if (hasDimensions)
@@ -8216,7 +8575,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.toQuotedString() <<
+ QualifiedName(FLD.RDB$FIELD_NAME, FLD.RDB$SCHEMA_NAME).toQuotedString());
}
}
else
@@ -8234,7 +8594,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 +8612,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 +8638,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 +8664,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 +8688,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 +8707,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 +8766,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 +8777,21 @@ 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.toQuotedString() <<
+ 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 +8827,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 +8842,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 +8858,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 +8880,9 @@ 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.toQuotedString() <<
+ name.toQuotedString());
}
// Update any indices that exist.
@@ -8527,22 +8904,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 EQ 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 EQ 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 EQ FLD.RDB$SCHEMA_NAME AND
ARG.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME)
{
DropDomainNode::deleteDimensionRecords(tdbb, transaction, globalName);
@@ -8564,12 +8945,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 +8971,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 +8981,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 +8995,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 +9007,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 +9022,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 +9035,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 +9049,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 +9062,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 +9079,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 +9087,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 +9098,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 +9119,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 +9152,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 +9167,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 +9184,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 +9208,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 +9248,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 +9258,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 +9286,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 +9301,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 +9318,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 +9333,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 +9365,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 +9387,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 +9412,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 +9426,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 +9440,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 +9592,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 +9617,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 +9680,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 +9691,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 +9713,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 +9808,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 +9824,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 +9850,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 +9927,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 +9953,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 +10038,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 +10058,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 +10073,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 +10121,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 EQ 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 +10132,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 +10184,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 +10204,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 +10220,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 +10231,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 +10250,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 +10296,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 +10312,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 +10323,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 +10361,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 +10392,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 +10430,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 +10444,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 +10455,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 +10493,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 +10535,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 +10550,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 +10565,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 +10591,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 +10606,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 +10622,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 +10637,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 +10667,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 +10683,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 +10701,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 +10730,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 +10742,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 +10785,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 +10991,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 +11015,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 +11064,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 +11073,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 +11084,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 +11297,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 +11362,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 +11450,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 +11491,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 +11516,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 +11565,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 +11603,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 +11646,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 +11820,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 +11871,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 +11953,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 +11980,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 +11999,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 +12008,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 +12018,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 +12066,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 +12078,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 +12089,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 +12104,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 +12119,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 +12150,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 +12165,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 +12179,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 +12193,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 +12206,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 +12231,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 +12269,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 +12288,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 +12342,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 +12418,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 +12465,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,23 +12492,23 @@ 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.toQuotedString());
}
else
{
///CVC: Make this a warning in the future.
- ///DYN_error_punt(false, 195, objName.c_str());
+ ///DYN_error_punt(false, 195, objName.toQuotedString());
}
}
if (crdb)
{
- CreateDbJob job(userType, user);
+ CreateDbJob job(userType, user.object);
createDbJobs.push(job);
if (!privileges[0])
@@ -12060,10 +12531,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 +12552,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 +12569,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 +12612,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 +12635,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 +12686,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
{
@@ -12225,10 +12702,10 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
if ((grantorRevoker == PRIV.RDB$GRANTOR) ||
(attachment->locksmith(tdbb, GRANT_REVOKE_ON_ANY_OBJECT) || // God-like check
((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
(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 +12735,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 +12752,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 +12765,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 +12778,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 +12790,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 +12803,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.toQuotedString() <<
+ relationName.toQuotedString());
}
}
@@ -12339,9 +12821,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 +12850,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 +12887,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.toQuotedString() << relationName.toQuotedString());
}
if (goFld == -1)
@@ -12412,14 +12896,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.toQuotedString());
}
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.toQuotedString());
}
}
}
@@ -12428,13 +12912,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 +12934,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 +13041,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 +13055,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 +13078,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 +13099,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 +13118,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 +13180,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,14 +13189,16 @@ 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;
@@ -12815,7 +13334,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 +13355,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 +13375,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 +13414,36 @@ 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());
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 +13472,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 +13593,502 @@ 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);
+ NODE_PRINT(printer, setDefaultSqlSecurity);
+
+ 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 && setDefaultCharSet->object.hasData())
+ {
+ dsqlScratch->qualifyExistingName(setDefaultCharSet.value(), obj_charset);
+
+ if (!METD_get_charset(dsqlScratch->getTransaction(), setDefaultCharSet.value()))
+ 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;
+
+ 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());
+
+ if (setDefaultCharSet)
+ {
+ strcpy(SCH.RDB$CHARACTER_SET_NAME, setDefaultCharSet->object.c_str());
+ SCH.RDB$CHARACTER_SET_NAME.NULL = FALSE;
+
+ strcpy(SCH.RDB$CHARACTER_SET_SCHEMA_NAME, setDefaultCharSet->schema.c_str());
+ SCH.RDB$CHARACTER_SET_SCHEMA_NAME.NULL = FALSE;
+ }
+ else
+ {
+ SCH.RDB$CHARACTER_SET_NAME.NULL = TRUE;
+ SCH.RDB$CHARACTER_SET_SCHEMA_NAME.NULL = TRUE;
+ }
+
+ if (setDefaultSqlSecurity)
+ {
+ SCH.RDB$SQL_SECURITY = setDefaultSqlSecurity.value();
+ SCH.RDB$SQL_SECURITY.NULL = FALSE;
+ }
+ else
+ SCH.RDB$SQL_SECURITY.NULL = TRUE;
+ }
+ 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, getDllSecurityName(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);
+
+ if (setDefaultCharSet)
+ dbb->dbb_schemas_dfl_charset.put(name, setDefaultCharSet.value());
+
+ 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)
+ {
+ if (setDefaultCharSet->object.hasData())
+ {
+ strcpy(SCH.RDB$CHARACTER_SET_NAME, setDefaultCharSet->object.c_str());
+ SCH.RDB$CHARACTER_SET_NAME.NULL = FALSE;
+
+ strcpy(SCH.RDB$CHARACTER_SET_SCHEMA_NAME, setDefaultCharSet->schema.c_str());
+ SCH.RDB$CHARACTER_SET_SCHEMA_NAME.NULL = FALSE;
+ }
+ else
+ {
+ SCH.RDB$CHARACTER_SET_NAME.NULL = TRUE;
+ SCH.RDB$CHARACTER_SET_SCHEMA_NAME.NULL = TRUE;
+ }
+ }
+
+ if (setDefaultSqlSecurity)
+ {
+ SCH.RDB$SQL_SECURITY = setDefaultSqlSecurity.value();
+ SCH.RDB$SQL_SECURITY.NULL = setDefaultSqlSecurity == SS_DROP ? TRUE : FALSE;
+ }
+
+ modified = true;
+ }
+ END_MODIFY
+ }
+ END_FOR
+
+ if (modified)
+ {
+ if (setDefaultCharSet)
+ {
+ if (setDefaultCharSet->object.hasData())
+ dbb->dbb_schemas_dfl_charset.put(name, setDefaultCharSet.value());
+ else
+ dbb->dbb_schemas_dfl_charset.remove(name);
+ }
+
+ 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 = SCL_getDdlSecurityClassName(obj, name);
+
+ 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);
+ }
+ 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 7f3f1b15dfa..89f51c33e7d 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 @@ class RecreateNode : public DdlNode
dropNode(p, createNode->name)
{
dropNode.silent = true;
+ dropNode.recreate = true;
}
public:
@@ -234,7 +233,18 @@ class RecreateNode : public DdlNode
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 @@ class RecreateNode : public DdlNode
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 @@ class AlterCharSetNode : public DdlNode
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 @@ class CommentOnNode : public DdlNode
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 @@ class CommentOnNode : public DdlNode
private:
int objType;
- QualifiedName objName;
+ QualifiedName name;
MetaName subName;
Firebird::string text, str;
};
@@ -382,7 +403,7 @@ class CommentOnNode : public DdlNode
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 @@ class CreateAlterFunctionNode : public DdlNode
body(NULL),
compiled(false),
invalid(false),
- package(pool),
packageOwner(pool),
privateScope(false),
preserveDefaults(false),
@@ -416,7 +436,7 @@ class CreateAlterFunctionNode : public DdlNode
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 @@ class CreateAlterFunctionNode : public DdlNode
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 @@ class CreateAlterFunctionNode : public DdlNode
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 @@ class AlterExternalFunctionNode : public DdlNode
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 @@ class AlterExternalFunctionNode : public DdlNode
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 @@ class DropFunctionNode : public DdlNode
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 @@ class CreateAlterProcedureNode : public DdlNode
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 @@ class DropProcedureNode : public DdlNode
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 @@ class TriggerDefinition
}
public:
- MetaName name;
- MetaName relationName;
+ QualifiedName name;
+ QualifiedName relationName;
std::optional type;
Firebird::TriState active;
std::optional position;
@@ -687,7 +709,7 @@ class TriggerDefinition
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 @@ class CreateAlterTriggerNode : public DdlNode, public TriggerDefinition
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 @@ class CreateAlterTriggerNode : public DdlNode, public TriggerDefinition
if (alter)
{
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
- DDL_TRIGGER_ALTER_TRIGGER, name, NULL);
+ DDL_TRIGGER_ALTER_TRIGGER, name, {});
}
}
@@ -730,7 +752,7 @@ class CreateAlterTriggerNode : public DdlNode, public TriggerDefinition
if (alter)
{
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER,
- DDL_TRIGGER_ALTER_TRIGGER, name, NULL);
+ DDL_TRIGGER_ALTER_TRIGGER, name, {});
}
}
@@ -768,7 +790,7 @@ class CreateAlterTriggerNode : public DdlNode, public TriggerDefinition
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 @@ class DropTriggerNode : public DdlNode
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 @@ class CreateCollationNode : public DdlNode
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 @@ class CreateCollationNode : public DdlNode
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 @@ class DropCollationNode : public DdlNode
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 @@ class DropCollationNode : public DdlNode
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 @@ class CreateDomainNode : public DdlNode
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 @@ class CreateDomainNode : public DdlNode
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 @@ class AlterDomainNode : public DdlNode
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 @@ class DropDomainNode : public DdlNode
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 @@ class CreateAlterExceptionNode : public DdlNode
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 @@ class CreateAlterExceptionNode : public DdlNode
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 @@ class CreateAlterExceptionNode : public DdlNode
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 @@ class CreateAlterExceptionNode : public DdlNode
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 @@ class DropExceptionNode : public DdlNode
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 @@ class CreateAlterSequenceNode : public DdlNode
bool createIfNotExistsOnly = false;
bool legacy;
bool restartSpecified;
- const MetaName name;
+ QualifiedName name;
std::optional value;
std::optional step;
};
@@ -1136,30 +1251,43 @@ class CreateAlterSequenceNode : public DdlNode
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 @@ class RelationNode : public DdlNode
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 @@ class RelationNode : public DdlNode
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 @@ class RelationNode : public DdlNode
ConstraintType constraintType;
Firebird::ObjectsArray columns;
NestConst index;
- MetaName refRelation;
+ QualifiedName refRelation;
Firebird::ObjectsArray refColumns;
NestConst refAction;
NestConst check;
@@ -1392,7 +1520,7 @@ class RelationNode : public DdlNode
dsql_fld* field;
NestConst defaultValue;
Firebird::ObjectsArray constraints;
- MetaName collate;
+ QualifiedName collate;
NestConst computed;
NestConst identityOptions;
bool notNullSpecified;
@@ -1487,13 +1615,16 @@ class RelationNode : public DdlNode
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 @@ class RelationNode : public DdlNode
public:
NestConst dsqlNode;
- MetaName name;
+ QualifiedName name;
Firebird::Array > clauses;
Firebird::TriState ssDefiner;
Firebird::TriState replicationState;
@@ -1557,10 +1688,19 @@ class CreateRelationNode : public RelationNode
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 @@ class AlterRelationNode : public RelationNode
{
}
+ 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 @@ class AlterRelationNode : public RelationNode
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 @@ class AlterRelationNode : public RelationNode
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 @@ class DropRelationNode : public DdlNode
{
}
- 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 @@ class CreateAlterViewNode : public RelationNode
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 @@ class CreateIndexNode : public DdlNode
conditionSource.clear();
}
- MetaName relation;
+ QualifiedName relation;
Firebird::ObjectsArray columns;
Firebird::TriState unique;
Firebird::TriState descending;
@@ -1720,34 +1882,35 @@ class CreateIndexNode : public DdlNode
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 @@ class CreateIndexNode : public DdlNode
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 @@ class AlterIndexNode : public DdlNode
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 @@ class AlterIndexNode : public DdlNode
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 @@ class SetStatisticsNode : public DdlNode
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 @@ class CreateFilterNode : public DdlNode
CreateFilterNode(MemoryPool& p, const MetaName& aName)
: DdlNode(p),
name(p, aName),
- inputFilter(NULL),
- outputFilter(NULL),
entryPoint(p),
moduleName(p)
{
@@ -2253,6 +2437,7 @@ class DropUserNode : public UserNode
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,80 @@ class GrantRevokeNode : public PrivilegesNode, private ExecInSecurityDb
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;
+ }
+
+ if (grantee == object)
+ dsqlScratch->ddlSchema = object->second.schema;
+ }
+
+ return PrivilegesNode::dsqlPass(dsqlScratch);
+ }
+
protected:
virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector)
{
@@ -2309,20 +2568,20 @@ class GrantRevokeNode : public PrivilegesNode, private ExecInSecurityDb
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 +2663,12 @@ class AlterDatabaseNode : public DdlNode
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 +2699,88 @@ class AlterDatabaseNode : public DdlNode
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)
+ {
+ }
+
+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;
+ std::optional setDefaultCharSet; // use empty QualifiedName with DROP DEFAULT CHARACTER SET
+ std::optional setDefaultSqlSecurity;
+ bool create = true;
+ bool alter = false;
+ bool createIfNotExistsOnly = false;
+};
+
+
+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 586dfdb9eec..1f62416db93 100644
--- a/src/dsql/DsqlCompilerScratch.cpp
+++ b/src/dsql/DsqlCompilerScratch.cpp
@@ -30,7 +30,9 @@
#include "../dsql/errd_proto.h"
#include "../dsql/gen_proto.h"
#include "../dsql/make_proto.h"
+#include "../dsql/metd_proto.h"
#include "../dsql/pass1_proto.h"
+#include
using namespace Firebird;
using namespace Jrd;
@@ -52,13 +54,167 @@ 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
+void DsqlCompilerScratch::qualifyNewName(QualifiedName& name) const
+{
+ 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 DsqlCompilerScratch::qualifyExistingName(QualifiedName& name, std::initializer_list objectTypes)
+{
+ if (!(name.schema.isEmpty() && name.object.hasData()))
+ return;
+
+ const auto tdbb = JRD_get_thread_data();
+ const auto attachment = tdbb->getAttachment();
+
+ if (ddlSchema.hasData())
+ {
+ if (!cachedDdlSchemaSearchPath)
+ {
+ cachedDdlSchemaSearchPath = FB_NEW_POOL(getPool()) ObjectsArray(getPool(), {ddlSchema});
+
+ if (const auto& searchPath = *attachment->att_schema_search_path;
+ std::find(searchPath.begin(), searchPath.end(), SYSTEM_SCHEMA) != searchPath.end())
+ {
+ cachedDdlSchemaSearchPath->push(SYSTEM_SCHEMA);
+ }
+ }
+
+ attachment->qualifyExistingName(tdbb, name, objectTypes, cachedDdlSchemaSearchPath);
+ }
+ else
+ attachment->qualifyExistingName(tdbb, name, objectTypes);
+}
+
+
+std::variant DsqlCompilerScratch::resolveRoutineOrRelation(
+ QualifiedName& name, std::initializer_list objectTypes)
+{
+ const std::unordered_set objectTypesSet(objectTypes);
+ const bool searchProcedures = objectTypesSet.find(obj_procedure) != objectTypesSet.end();
+ const bool searchRelations = objectTypesSet.find(obj_relation) != objectTypesSet.end();
+ const bool searchFunctions = objectTypesSet.find(obj_udf) != objectTypesSet.end();
+ fb_assert((searchProcedures || searchRelations) != searchFunctions);
+
+ std::variant object;
+
+ const auto notFound = [&]()
+ {
+ return std::holds_alternative(object);
+ };
+
+ const auto setObject = [&](const auto value)
+ {
+ if (value)
+ object = value;
+ };
+
+ // search subroutine: name
+ if (name.schema.isEmpty() &&
+ name.package.isEmpty())
+ {
+ if (searchProcedures)
+ {
+ if (const auto subProcedure = getSubProcedure(name.object))
+ setObject(subProcedure->dsqlProcedure);
+ }
+
+ if (searchFunctions)
+ {
+ if (const auto subFunction = getSubFunction(name.object))
+ setObject(subFunction->dsqlFunction);
+ }
+ }
+
+ // search packaged routine in the same package: name, same_package.name
+ if (notFound() &&
+ package.object.hasData() &&
+ name.package.isEmpty() &&
+ (name.schema.isEmpty() ||
+ (!name.isUnambiguous() && name.schema == package.object)))
+ {
+ const QualifiedName routineName(name.object, package.schema, package.object);
+
+ if (searchProcedures)
+ setObject(METD_get_procedure(getTransaction(), this, routineName));
+
+ if (searchFunctions)
+ setObject(METD_get_function(getTransaction(), this, routineName));
+ }
+
+ // search standalone routine or relation: name, name1%schema.name2, name1.name2
+ if (notFound() &&
+ name.package.isEmpty())
+ {
+ auto qualifiedName = name;
+ qualifyExistingName(qualifiedName, objectTypes);
+
+ if (searchProcedures)
+ setObject(METD_get_procedure(getTransaction(), this, qualifiedName));
+
+ if (searchRelations)
+ setObject(METD_get_relation(getTransaction(), this, qualifiedName));
+
+ if (searchFunctions)
+ setObject(METD_get_function(getTransaction(), this, qualifiedName));
+ }
+
+ // search packaged routine: name1%package.name2, name1.name2.name3
+ if (notFound() &&
+ name.package.hasData())
+ {
+ auto qualifiedName = name;
+ qualifyExistingName(qualifiedName, objectTypes);
+
+ if (searchProcedures)
+ setObject(METD_get_procedure(getTransaction(), this, qualifiedName));
+
+ if (searchFunctions)
+ setObject(METD_get_function(getTransaction(), this, qualifiedName));
+ }
+
+ // search packaged routine: name1.name2
+ if (notFound() &&
+ !name.isUnambiguous() &&
+ name.schema.hasData() &&
+ name.package.isEmpty())
+ {
+ QualifiedName qualifiedName(name.object, {}, name.schema);
+ qualifyExistingName(qualifiedName, objectTypes);
+
+ if (searchProcedures)
+ setObject(METD_get_procedure(getTransaction(), this, qualifiedName));
+
+ if (searchFunctions)
+ setObject(METD_get_function(getTransaction(), this, qualifiedName));
+ }
+
+ if (const auto procedure = std::get_if(&object))
+ name = (*procedure)->prc_name;
+ else if (const auto relation = std::get_if(&object))
+ name = (*relation)->rel_name;
+ else if (const auto function = std::get_if(&object))
+ name = (*function)->udf_name;
+
+ return object;
+}
+
+
void DsqlCompilerScratch::putBlrMarkers(ULONG marks)
{
appendUChar(blr_marks);
@@ -99,40 +255,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 +403,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 +537,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;
@@ -932,12 +1184,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 +1203,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 8755b7cb2d0..eb749f515eb 100644
--- a/src/dsql/DsqlCompilerScratch.h
+++ b/src/dsql/DsqlCompilerScratch.h
@@ -30,7 +30,9 @@
#include "../jrd/MetaName.h"
#include "../common/classes/stack.h"
#include "../common/classes/alloc.h"
+#include
#include
+#include
namespace Jrd
{
@@ -96,6 +98,7 @@ class DsqlCompilerScratch : public BlrDebugWriter
mainScratch(aMainScratch),
outerMessagesMap(p),
outerVarsMap(p),
+ ddlSchema(p),
ctes(p),
cteAliases(p),
subFunctions(p),
@@ -151,16 +154,28 @@ class DsqlCompilerScratch : public BlrDebugWriter
dsqlStatement = aDsqlStatement;
}
+ void qualifyNewName(QualifiedName& name) const;
+ void qualifyExistingName(QualifiedName& name, std::initializer_list objectTypes);
+
+ void qualifyExistingName(QualifiedName& name, ObjectType objectType)
+ {
+ qualifyExistingName(name, {objectType});
+ }
+
+ std::variant resolveRoutineOrRelation(QualifiedName& name,
+ std::initializer_list objectTypes);
+
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 +316,8 @@ class DsqlCompilerScratch : public BlrDebugWriter
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 +332,8 @@ class DsqlCompilerScratch : public BlrDebugWriter
DsqlCompilerScratch* mainScratch = nullptr;
Firebird::NonPooledMap outerMessagesMap; //
Firebird::NonPooledMap outerVarsMap; //
+ MetaName ddlSchema;
+ Firebird::AutoPtr> cachedDdlSchemaSearchPath;
private:
Firebird::HalfStaticArray ctes; // common table expressions
diff --git a/src/dsql/DsqlRequests.cpp b/src/dsql/DsqlRequests.cpp
index cb68720f7e9..9c95a2f2419 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 2ba98386a22..5d50e5cfab1 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 c72f38fd95a..97fac4acbd1 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)
{
@@ -76,6 +86,7 @@ void 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 399852bf633..d483df40c70 100644
--- a/src/dsql/DsqlStatements.h
+++ b/src/dsql/DsqlStatements.h
@@ -68,16 +68,7 @@ class DsqlStatement : public Firebird::PermanentStorage
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 @@ class DsqlStatement : public Firebird::PermanentStorage
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 @@ class DsqlStatement : public Firebird::PermanentStorage
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 @@ class DsqlStatement : public Firebird::PermanentStorage
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 9d5d4849680..6d1c4b8a78b 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()));
+ name.toQuotedString() << procedure->getName().toQuotedString());
}
}
else
@@ -6055,13 +6166,15 @@ 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));
+ PAR_warning(Arg::Warning(isc_fldnotdef) <<
+ name.toQuotedString() <<
+ 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));
+ PAR_error(csb, Arg::Gds(isc_fldnotdef) <<
+ name.toQuotedString() <<
+ relation->rel_name.toQuotedString());
}
else
PAR_error(csb, Arg::Gds(isc_ctxnotdef));
@@ -6129,7 +6242,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 +6266,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 +6326,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 +6342,32 @@ 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);
+ 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 +6379,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 +6404,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 +6448,13 @@ 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)
+ 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)
{
- 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);
}
}
@@ -6834,8 +6945,9 @@ 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));
+ ERR_post(Arg::Gds(isc_no_field_access) <<
+ field->fld_name.toQuotedString() <<
+ relation->rel_name.toQuotedString());
}
// The previous test below is an apparent temporary fix
@@ -6886,7 +6998,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 +7170,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 +7189,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;
+
+ 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);
- 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);
+ 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 +7245,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 +7268,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 +7367,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 +7407,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 +7499,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 +7541,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 +7618,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 +8064,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 +8118,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 +8269,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 +8911,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 +10151,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 +10193,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 +10219,19 @@ ValueExprNode* RecordKeyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
raiseError(context);
if (context->ctx_flags & CTX_null)
- return NullNode::instance();
-
- 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;
+ node = NullNode::instance();
+ else
+ {
+ //// TODO: LocalTableSourceNode
+ auto relNode = FB_NEW_POOL(dsqlScratch->getPool()) RelationSourceNode(
+ dsqlScratch->getPool());
+ relNode->dsqlContext = context;
+
+ const auto recordKeyNode = FB_NEW_POOL(dsqlScratch->getPool()) RecordKeyNode(
+ dsqlScratch->getPool(), blrOp);
+ recordKeyNode->dsqlRelation = relNode;
+ node = recordKeyNode;
+ }
}
}
else
@@ -10097,10 +10241,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 +10253,30 @@ ValueExprNode* RecordKeyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
raiseError(context);
if (context->ctx_flags & CTX_null)
- return NullNode::instance();
-
- //// 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;
+ node = NullNode::instance();
+ else
+ {
+ //// TODO: LocalTableSourceNode
+ auto relNode = FB_NEW_POOL(dsqlScratch->getPool()) RelationSourceNode(dsqlScratch->getPool());
+ relNode->dsqlContext = context;
+
+ 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 +10705,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(
@@ -12327,7 +12477,7 @@ DmlNode* SysFuncCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScrat
if (!node->function)
{
csb->csb_blr_reader.seekBackward(count);
- PAR_error(csb, Arg::Gds(isc_funnotdef) << Arg::Str(name));
+ PAR_error(csb, Arg::Gds(isc_funnotdef) << name.toQuotedString());
}
node->args = PAR_args(tdbb, csb);
@@ -12341,12 +12491,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);
}
}
@@ -12481,15 +12635,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;
@@ -12973,42 +13119,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;
- blrReader.getMetaName(name.identifier);
+ case blr_invoke_function_id_sub:
+ isSub = true;
+ break;
- if (functionType == blr_invoke_function_type_sub)
+ default:
+ PAR_error(csb, Arg::Gds(isc_random) << "Invalid blr_invoke_function_id");
+ break;
+ }
+ }
+
+ 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;
@@ -13016,7 +13175,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();
@@ -13035,7 +13194,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));
@@ -13051,10 +13210,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);
@@ -13064,17 +13224,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();
@@ -13095,13 +13258,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));
}
}
@@ -13177,15 +13340,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);
}
}
@@ -13208,7 +13371,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())
@@ -13246,29 +13409,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())
{
@@ -13298,7 +13469,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)
@@ -13379,24 +13550,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());
@@ -13473,12 +13646,13 @@ 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));
+ function->getName().object.toQuotedString() <<
+ function->getName().getSchemaAndPackage().toQuotedString());
}
else if (!function->isDefined())
{
status_exception::raise(
- Arg::Gds(isc_funnotdef) << Arg::Str(function->getName().toString()) <<
+ Arg::Gds(isc_funnotdef) << function->getName().toQuotedString() <<
Arg::Gds(isc_modnotfound));
}
@@ -13653,28 +13827,35 @@ dsc* UdfCallNode::execute(thread_db* tdbb, Request* request) const
ValueExprNode* UdfCallNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
{
- 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;
- }
+ const auto resolvedObject = dsqlScratch->resolveRoutineOrRelation(name, {obj_udf});
+ dsql_udf* function = nullptr;
- if (!node->dsqlFunction)
- node->dsqlFunction = METD_get_function(dsqlScratch->getTransaction(), dsqlScratch, name);
+ if (const auto resolvedFunction = std::get_if(&resolvedObject))
+ function = *resolvedFunction;
- if (!node->dsqlFunction)
+ if (!function)
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-804) <<
Arg::Gds(isc_dsql_function_err) <<
- Arg::Gds(isc_random) << Arg::Str(name.toString()));
+ 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.toQuotedString() <<
+ function->udf_name.getSchemaAndPackage().toQuotedString());
+ }
+
+ 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);
+
+ node->dsqlFunction = function;
+
auto argIt = node->args->items.begin();
unsigned pos = 0;
@@ -13716,7 +13897,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;
@@ -14060,7 +14241,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;
@@ -14391,16 +14572,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 9a5c58bc23d..11750d1678c 100644
--- a/src/dsql/ExprNodes.h
+++ b/src/dsql/ExprNodes.h
@@ -339,7 +339,7 @@ class CoalesceNode 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 @@ class CollateNode final : public TypedNode arg;
- MetaName collation;
+ QualifiedName collation;
};
@@ -530,6 +530,29 @@ class CurrentRoleNode 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 @@ class DecodeNode final : public TypedNode
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 @@ class DefaultNode : public DsqlNode
virtual ValueExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);
public:
- const MetaName relationName;
+ const QualifiedName relationName;
const MetaName fieldName;
private:
@@ -839,10 +862,10 @@ class FieldNode final : public TypedNode
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 @@ class LiteralNode final : public TypedNode dsqlStr;
dsc litDesc;
USHORT litNumStringLength = 0;
};
@@ -1671,7 +1694,7 @@ class ParameterNode 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 @@ class RecordKeyNode final : public TypedNode dsqlRelation;
StreamType recStream;
const UCHAR blrOp;
diff --git a/src/dsql/NodePrinter.h b/src/dsql/NodePrinter.h
index 4caa8fedc9c..0f042b6b79d 100644
--- a/src/dsql/NodePrinter.h
+++ b/src/dsql/NodePrinter.h
@@ -85,7 +85,7 @@ class NodePrinter
text += "<";
text += s;
text += ">";
- text += value.toString();
+ text += value.toQuotedString();
text += "";
text += s;
text += ">\n";
diff --git a/src/dsql/Nodes.h b/src/dsql/Nodes.h
index 4df8900d540..d328c4445bf 100644
--- a/src/dsql/Nodes.h
+++ b/src/dsql/Nodes.h
@@ -173,8 +173,6 @@ class Node : public Printable
};
-class DdlNode;
-
class DdlNode : public Node
{
public:
@@ -183,14 +181,24 @@ class DdlNode : public Node
{
}
+ 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 @@ class DdlNode : public Node
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 @@ class DdlNode : public Node
}
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 @@ class ExprNode : public DmlNode
TYPE_CURRENT_TIME,
TYPE_CURRENT_TIMESTAMP,
TYPE_CURRENT_ROLE,
+ TYPE_CURRENT_SCHEMA,
TYPE_CURRENT_USER,
TYPE_DERIVED_EXPR,
TYPE_DECODE,
@@ -1655,7 +1664,7 @@ class RowsClause : public Printable
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 @@ class GeneratorItem : public Printable
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 c13853ce09f..2cf20722aa0 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.toQuotedString());
}
- 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.toQuotedString());
}
- 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