From 41df701eadb96240115fc3d843fc012ec7873ef2 Mon Sep 17 00:00:00 2001 From: shalinilohia50 <46928246+shalinilohia50@users.noreply.github.com> Date: Thu, 1 Feb 2024 17:24:35 +0530 Subject: [PATCH] Support GRANT .. ON SCHEMA .. in Babelfish (#2326) Support GRANT/REVOKE .. ON SCHEMA .. in Babelfish PLEASE NOTE: This change is with the assumption that we are going to restrict function overloading. Based on any other decision made otherwise, the catalog implementation would be extended to store the arguments in another PR. Supported syntax GRANT ON SCHEMA:: TO Supported syntax REVOKE ON SCHEMA:: FROM Added one SQL statement PLTSQL_STMT_GRANTSCHEMA to store relevant information to execute GRANT/REVOKE .. ON SCHEMA .. statements. Created one catalog table sys.babelfish_schema_permissions to hold the details for each GRANT/REVOKE statements. GRANT on schema/objects adds a row in the catalog table if not exists already. REVOKE on schema/objects removes the corresponding row in the catalog table if it exists already. REVOKE on schema internally grants permission to all the objects if there are explicit permissions granted to the objects belonging to the same schema. GRANT ALL on objects work as it is and add rows in the catalog for each relevant permission depending on the object type. REVOKE ALL on object should do nothing, if the relevant schema permission exists in the catalog. But, it should remove the rows from the catalog if the object level permission is granted. Drop statement for OBJECT/SCHEMA removes all the relevant object entries from the catalog. Issues Resolved Task: BABEL-4344, BABEL-4485 Signed-off-by: Shalini Lohia lshalini@amazon.com --- contrib/babelfishpg_tsql/sql/ownership.sql | 13 + .../babelfishpg_tsql--4.0.0--4.1.0.sql | 11 + contrib/babelfishpg_tsql/src/catalog.c | 761 +++++++++++ contrib/babelfishpg_tsql/src/catalog.h | 45 + contrib/babelfishpg_tsql/src/codegen.c | 1 + contrib/babelfishpg_tsql/src/dbcmds.c | 4 +- contrib/babelfishpg_tsql/src/iterative_exec.c | 3 + contrib/babelfishpg_tsql/src/pl_exec-2.c | 130 ++ contrib/babelfishpg_tsql/src/pl_funcs-2.c | 1 + contrib/babelfishpg_tsql/src/pl_handler.c | 223 +++- contrib/babelfishpg_tsql/src/pltsql.h | 20 +- contrib/babelfishpg_tsql/src/pltsql_utils.c | 188 ++- contrib/babelfishpg_tsql/src/stmt_walker.c | 2 + contrib/babelfishpg_tsql/src/stmt_walker.h | 2 + contrib/babelfishpg_tsql/src/tsqlIface.cpp | 248 +++- contrib/babelfishpg_tsql/src/tsqlNodes.h | 1 + .../src/tsqlUnsupportedFeatureHandler.cpp | 18 +- .../JDBC/expected/AUTO_ANALYZE-vu-prepare.out | 1 + test/JDBC/expected/BABEL-CROSS-DB.out | 6 + test/JDBC/expected/BABEL-GRANT.out | 60 +- test/JDBC/expected/BABEL-SESSION.out | 15 + .../JDBC/expected/GRANT_SCHEMA-vu-cleanup.out | 75 ++ .../JDBC/expected/GRANT_SCHEMA-vu-prepare.out | 74 ++ test/JDBC/expected/GRANT_SCHEMA-vu-verify.out | 291 +++++ test/JDBC/expected/GRANT_SCHEMA.out | 1110 +++++++++++++++++ test/JDBC/input/BABEL-CROSS-DB.mix | 6 + test/JDBC/input/BABEL-GRANT.sql | 40 +- test/JDBC/input/BABEL-SESSION.mix | 15 + test/JDBC/input/GRANT_SCHEMA-vu-cleanup.mix | 66 + test/JDBC/input/GRANT_SCHEMA-vu-prepare.mix | 74 ++ test/JDBC/input/GRANT_SCHEMA-vu-verify.mix | 179 +++ test/JDBC/input/GRANT_SCHEMA.mix | 711 +++++++++++ test/JDBC/jdbc_schedule | 3 + test/JDBC/upgrade/13_6/schedule | 2 +- test/JDBC/upgrade/13_9/schedule | 3 +- test/JDBC/upgrade/14_10/schedule | 1 + test/JDBC/upgrade/14_3/schedule | 3 +- test/JDBC/upgrade/14_5/schedule | 1 + test/JDBC/upgrade/14_6/schedule | 1 + test/JDBC/upgrade/15_2/schedule | 1 + test/JDBC/upgrade/15_4/schedule | 1 + test/JDBC/upgrade/15_5/schedule | 1 + .../expected_create.out | 1 + 43 files changed, 4345 insertions(+), 67 deletions(-) create mode 100644 test/JDBC/expected/GRANT_SCHEMA-vu-cleanup.out create mode 100644 test/JDBC/expected/GRANT_SCHEMA-vu-prepare.out create mode 100644 test/JDBC/expected/GRANT_SCHEMA-vu-verify.out create mode 100644 test/JDBC/expected/GRANT_SCHEMA.out create mode 100644 test/JDBC/input/GRANT_SCHEMA-vu-cleanup.mix create mode 100644 test/JDBC/input/GRANT_SCHEMA-vu-prepare.mix create mode 100644 test/JDBC/input/GRANT_SCHEMA-vu-verify.mix create mode 100644 test/JDBC/input/GRANT_SCHEMA.mix diff --git a/contrib/babelfishpg_tsql/sql/ownership.sql b/contrib/babelfishpg_tsql/sql/ownership.sql index a053f1f477..d333098624 100644 --- a/contrib/babelfishpg_tsql/sql/ownership.sql +++ b/contrib/babelfishpg_tsql/sql/ownership.sql @@ -14,6 +14,19 @@ CREATE TABLE sys.babelfish_sysdatabases ( GRANT SELECT on sys.babelfish_sysdatabases TO PUBLIC; +-- BABELFISH_SCHEMA_PERMISSIONS +-- This catalog is implemented specially to support GRANT/REVOKE .. ON SCHEMA .. +-- Please avoid using this catalog anywhere else. +CREATE TABLE sys.babelfish_schema_permissions ( + dbid smallint NOT NULL, + schema_name sys.NVARCHAR(128) NOT NULL COLLATE sys.database_default, + object_name sys.NVARCHAR(128) NOT NULL COLLATE sys.database_default, + permission INT NOT NULL, + grantee sys.NVARCHAR(128) NOT NULL COLLATE sys.database_default, + object_type CHAR(1) NOT NULL COLLATE sys.database_default, + PRIMARY KEY(dbid, schema_name, object_name, grantee, object_type) +); + -- BABELFISH_FUNCTION_EXT CREATE TABLE sys.babelfish_function_ext ( nspname NAME NOT NULL, diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--4.0.0--4.1.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--4.0.0--4.1.0.sql index a6b79f4c1f..893e428b99 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--4.0.0--4.1.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--4.0.0--4.1.0.sql @@ -2863,6 +2863,17 @@ END; $$ LANGUAGE pltsql; GRANT EXECUTE ON PROCEDURE sys.sp_procedure_params_100_managed TO PUBLIC; +-- BABELFISH_SCHEMA_PERMISSIONS +CREATE TABLE IF NOT EXISTS sys.babelfish_schema_permissions ( + dbid smallint NOT NULL, + schema_name sys.NVARCHAR(128) NOT NULL COLLATE sys.database_default, + object_name sys.NVARCHAR(128) NOT NULL COLLATE sys.database_default, + permission INT NOT NULL, + grantee sys.NVARCHAR(128) NOT NULL COLLATE sys.database_default, + object_type CHAR(1) NOT NULL COLLATE sys.database_default, + PRIMARY KEY(dbid, schema_name, object_name, grantee, object_type) +); + CALL sys.babelfish_drop_deprecated_object('view', 'sys', 'sysforeignkeys_deprecated_4_1_0'); CALL sys.babelfish_drop_deprecated_object('view', 'sys', 'system_objects_deprecated_4_1_0'); CALL sys.babelfish_drop_deprecated_object('view', 'sys', 'syscolumns_deprecated_4_1_0'); diff --git a/contrib/babelfishpg_tsql/src/catalog.c b/contrib/babelfishpg_tsql/src/catalog.c index 458af485e6..a6a8b5aff5 100644 --- a/contrib/babelfishpg_tsql/src/catalog.c +++ b/contrib/babelfishpg_tsql/src/catalog.c @@ -83,6 +83,12 @@ Oid bbf_servers_def_idx_oid; Oid bbf_function_ext_oid; Oid bbf_function_ext_idx_oid; +/***************************************** + * SCHEMA + *****************************************/ +Oid bbf_schema_perms_oid; +Oid bbf_schema_perms_idx_oid; + /***************************************** * DOMAIN MAPPING *****************************************/ @@ -1435,6 +1441,29 @@ clean_up_bbf_function_ext(int16 dbid) table_close(bbf_function_ext_rel, RowExclusiveLock); } + +/***************************************** + * SCHEMA + *****************************************/ + +static Oid +get_bbf_schema_perms_oid() +{ + if (!OidIsValid(bbf_schema_perms_oid)) + bbf_schema_perms_oid = get_relname_relid(BBF_SCHEMA_PERMS_TABLE_NAME, + get_namespace_oid("sys", false)); + return bbf_schema_perms_oid; +} + +static Oid +get_bbf_schema_perms_idx_oid() +{ + if (!OidIsValid(bbf_schema_perms_idx_oid)) + bbf_schema_perms_idx_oid = get_relname_relid(BBF_SCHEMA_PERMS_IDX_NAME, + get_namespace_oid("sys", false)); + return bbf_schema_perms_idx_oid; +} + /***************************************** * DOMAIN MAPPING *****************************************/ @@ -1554,6 +1583,9 @@ static void alter_guest_schema_for_db(const char *dbname); /* Helper function Rename BBF catalog update*/ static void rename_view_update_bbf_catalog(RenameStmt *stmt); static void rename_procfunc_update_bbf_catalog(RenameStmt *stmt); +static void rename_object_update_bbf_schema_permission_catalog(RenameStmt *stmt, int rename_type); + +static int get_privilege_of_object(const char *schema_name, const char *object_name, const char *grantee, const char *object_type); /***************************************** * Catalog Extra Info @@ -2598,16 +2630,28 @@ rename_update_bbf_catalog(RenameStmt *stmt) { switch (stmt->renameType) { + /* + * In case of renaming a table, view, procedure and function, modify the object + * names present in all the Babelfish catalogs which stores these object names to + * have consistency with the new names. + * + * List of catalogs which are updated here: + * babelfish_schema_permissions, babelfish_function_ext, babelfish_view_def + */ case OBJECT_TABLE: + rename_object_update_bbf_schema_permission_catalog(stmt, stmt->renameType); break; case OBJECT_VIEW: rename_view_update_bbf_catalog(stmt); + rename_object_update_bbf_schema_permission_catalog(stmt, stmt->renameType); break; case OBJECT_PROCEDURE: rename_procfunc_update_bbf_catalog(stmt); + rename_object_update_bbf_schema_permission_catalog(stmt, stmt->renameType); break; case OBJECT_FUNCTION: rename_procfunc_update_bbf_catalog(stmt); + rename_object_update_bbf_schema_permission_catalog(stmt, stmt->renameType); break; case OBJECT_SEQUENCE: break; @@ -2622,6 +2666,120 @@ rename_update_bbf_catalog(RenameStmt *stmt) } } +/* + * rename_object_update_bbf_schema_permission_catalog + * + * In case of renaming a table, view, procedure and function, modify the 'object_name' in + * 'babelfish_schema_permissions' to have consistency with the new names. + */ +static void +rename_object_update_bbf_schema_permission_catalog(RenameStmt *stmt, int rename_type) +{ + /* Update 'object_name' in 'babelfish_schema_permissions' */ + Relation bbf_schema_rel; + TupleDesc bbf_schema_dsc; + ScanKeyData key[4]; + HeapTuple tuple_bbf_schema; + HeapTuple new_tuple; + SysScanDesc scan; + Datum new_record_bbf_schema[BBF_SCHEMA_PERMS_NUM_OF_COLS] = {0}; + bool new_record_nulls_bbf_schema[BBF_SCHEMA_PERMS_NUM_OF_COLS] = {false}; + bool new_record_repl_bbf_schema[BBF_SCHEMA_PERMS_NUM_OF_COLS] = {false}; + char *logical_schema_name = NULL; + char *object_name = NULL; + const char *object_type = NULL; + int16 dbid = get_cur_db_id(); + ObjectWithArgs *objwargs; + + /* open the catalog table */ + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), RowExclusiveLock); + /* get the description of the table */ + bbf_schema_dsc = RelationGetDescr(bbf_schema_rel); + + if (rename_type == OBJECT_TABLE || rename_type == OBJECT_VIEW) + { + logical_schema_name = (char *) get_logical_schema_name(stmt->relation->schemaname, true); + object_name = stmt->relation->relname; + object_type = OBJ_RELATION; + } + else + { + if (rename_type == OBJECT_PROCEDURE) + object_type = OBJ_PROCEDURE; + else if (rename_type == OBJECT_FUNCTION) + object_type = OBJ_FUNCTION; + objwargs = (ObjectWithArgs *) stmt->object; + DeconstructQualifiedName(objwargs->objname, &logical_schema_name, &object_name); + } + + /* search for the row for update => build the key */ + ScanKeyInit(&key[0], + Anum_bbf_schema_perms_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(dbid)); + ScanKeyEntryInitialize(&key[1], 0, + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, CStringGetTextDatum(logical_schema_name)); + ScanKeyEntryInitialize(&key[2], 0, + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, CStringGetTextDatum(object_name)); + ScanKeyEntryInitialize(&key[3], 0, + Anum_bbf_schema_perms_object_type, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(object_type)); + + /* scan */ + scan = systable_beginscan(bbf_schema_rel, + get_bbf_schema_perms_oid(), + false, NULL, 4, key); + + /* get the scan result -> original tuple */ + tuple_bbf_schema = systable_getnext(scan); + + /* + * If a permission on the same object is granted to multiple grantees, + * there can be multiple rows in the catalog corresponding to each grantee name. + * All such rows need to be updated with the new name. + * + * It is OK to not throw an error if an entry is not found in 'babelfish_schema_permissions'. + * Explaination: An entry is added to 'babelfish_schema_permissions' only if an object has an explicit GRANT on it. + * It is not necessary that each RENAME on an object has a GRANT of that object too. + * Hence, there can be missing entries. + */ + while (HeapTupleIsValid(tuple_bbf_schema)) + { + /* create new tuple to substitute */ + new_record_bbf_schema[Anum_bbf_schema_perms_object_name - 1] = CStringGetTextDatum(stmt->newname); + new_record_repl_bbf_schema[Anum_bbf_schema_perms_object_name - 1] = true; + + new_tuple = heap_modify_tuple(tuple_bbf_schema, + bbf_schema_dsc, + new_record_bbf_schema, + new_record_nulls_bbf_schema, + new_record_repl_bbf_schema); + + CatalogTupleUpdate(bbf_schema_rel, &new_tuple->t_self, new_tuple); + + heap_freetuple(new_tuple); + tuple_bbf_schema = systable_getnext(scan); + } + + if (logical_schema_name != NULL) + pfree(logical_schema_name); + if (object_name != NULL) + pfree(object_name); + + systable_endscan(scan); + table_close(bbf_schema_rel, RowExclusiveLock); +} + static void rename_view_update_bbf_catalog(RenameStmt *stmt) { @@ -2804,6 +2962,609 @@ rename_procfunc_update_bbf_catalog(RenameStmt *stmt) table_close(bbf_func_ext_rel, RowExclusiveLock); } +/* + * Add an entry to catalog BABELFISH_SCHEMA_PERMISSIONS. + */ +void +add_entry_to_bbf_schema_perms(const char *schema_name, + const char *object_name, + int permission, + const char *grantee, + const char *object_type) +{ + Relation bbf_schema_rel; + TupleDesc bbf_schema_dsc; + HeapTuple tuple_bbf_schema; + Datum new_record_bbf_schema[BBF_SCHEMA_PERMS_NUM_OF_COLS]; + bool new_record_nulls_bbf_schema[BBF_SCHEMA_PERMS_NUM_OF_COLS]; + int16 dbid = get_cur_db_id(); + + /* Immediately return, if grantee is NULL or PUBLIC. */ + if ((grantee == NULL) || (strcmp(grantee, PUBLIC_ROLE_NAME) == 0)) + return; + + /* Fetch the relation */ + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), + RowExclusiveLock); + bbf_schema_dsc = RelationGetDescr(bbf_schema_rel); + + /* Build a tuple to insert */ + MemSet(new_record_bbf_schema, 0, sizeof(new_record_bbf_schema)); + MemSet(new_record_nulls_bbf_schema, false, sizeof(new_record_nulls_bbf_schema)); + + new_record_bbf_schema[Anum_bbf_schema_perms_dbid - 1] = Int16GetDatum(dbid); + new_record_bbf_schema[Anum_bbf_schema_perms_schema_name - 1] = CStringGetTextDatum(pstrdup(schema_name)); + new_record_bbf_schema[Anum_bbf_schema_perms_object_name - 1] = CStringGetTextDatum(pstrdup(object_name)); + new_record_bbf_schema[Anum_bbf_schema_perms_permission - 1] = Int32GetDatum(permission); + new_record_bbf_schema[Anum_bbf_schema_perms_grantee - 1] = CStringGetTextDatum(pstrdup(grantee)); + new_record_bbf_schema[Anum_bbf_schema_perms_object_type - 1] = CStringGetTextDatum(pstrdup(object_type)); + + tuple_bbf_schema = heap_form_tuple(bbf_schema_dsc, + new_record_bbf_schema, + new_record_nulls_bbf_schema); + + /* Insert new record in the bbf_authid_user_ext table */ + CatalogTupleInsert(bbf_schema_rel, tuple_bbf_schema); + + /* Close bbf_authid_user_ext, but keep lock till commit */ + table_close(bbf_schema_rel, RowExclusiveLock); + + /* Advance cmd counter to make the insert visible */ + CommandCounterIncrement(); +} + +/* + * Updates the permission column for a particular row in BABELFISH_SCHEMA_PERMISSIONS table. + */ +void +update_privileges_of_object(const char *schema_name, + const char *object_name, + int new_permission, + const char *grantee, + const char *object_type, + bool is_grant) +{ + Relation bbf_schema_rel; + HeapTuple tuple_bbf_schema; + TupleDesc bbf_schema_dsc; + HeapTuple new_tuple; + ScanKeyData scanKey[5]; + SysScanDesc scan; + int16 dbid = get_cur_db_id(); + int old_permission = 0; + int current_permission = 0; + Datum new_record_bbf_schema[BBF_SCHEMA_PERMS_NUM_OF_COLS]; + bool new_record_nulls_bbf_schema[BBF_SCHEMA_PERMS_NUM_OF_COLS]; + bool new_record_repl_bbf_schema[BBF_SCHEMA_PERMS_NUM_OF_COLS]; + + /* Immediately return false, if SCHEMA name is NULL or it's a shared schema. */ + if (schema_name == NULL || is_shared_schema(schema_name)) + return; + + /* Immediately return, if grantee is NULL or PUBLIC. */ + if ((grantee == NULL) || (strcmp(grantee, PUBLIC_ROLE_NAME) == 0)) + return; + + /* Get existing privilege of an object. */ + old_permission = get_privilege_of_object(schema_name, object_name, grantee, object_type); + + if (is_grant) + { + /* + * In case of GRANT, we add the new privilege along with the previous privilege in the column. + */ + current_permission = old_permission | new_permission; + } + else + { + /* + * In case of REVOKE, we remove the new privilege and keep the previous privilege as it is. + */ + current_permission = old_permission & ~new_permission; + } + + if (current_permission == 0) + { + remove_entry_from_bbf_schema_perms(schema_name, object_name, grantee, object_type); + return; + } + + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), + RowExclusiveLock); + + ScanKeyInit(&scanKey[0], + Anum_bbf_schema_perms_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(dbid)); + ScanKeyEntryInitialize(&scanKey[1], 0, + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(schema_name)); + ScanKeyEntryInitialize(&scanKey[2], 0, + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(object_name)); + ScanKeyInit(&scanKey[3], + Anum_bbf_schema_perms_permission, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(old_permission)); + ScanKeyEntryInitialize(&scanKey[4], 0, + Anum_bbf_schema_perms_grantee, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(grantee)); + + scan = systable_beginscan(bbf_schema_rel, + get_bbf_schema_perms_idx_oid(), + false, NULL, 5, scanKey); + + tuple_bbf_schema = systable_getnext(scan); + if (HeapTupleIsValid(tuple_bbf_schema)) + { + bbf_schema_dsc = RelationGetDescr(bbf_schema_rel); + /* Build a tuple to insert */ + MemSet(new_record_bbf_schema, 0, sizeof(new_record_bbf_schema)); + MemSet(new_record_nulls_bbf_schema, false, sizeof(new_record_nulls_bbf_schema)); + MemSet(new_record_repl_bbf_schema, false, sizeof(new_record_repl_bbf_schema)); + + new_record_bbf_schema[Anum_bbf_schema_perms_permission - 1] = Int32GetDatum(current_permission); + new_record_repl_bbf_schema[Anum_bbf_schema_perms_permission - 1] = true; + + new_tuple = heap_modify_tuple(tuple_bbf_schema, + bbf_schema_dsc, + new_record_bbf_schema, + new_record_nulls_bbf_schema, + new_record_repl_bbf_schema); + + CatalogTupleUpdate(bbf_schema_rel, &new_tuple->t_self, new_tuple); + heap_freetuple(new_tuple); + } + + systable_endscan(scan); + table_close(bbf_schema_rel, RowExclusiveLock); +} + +/* + * Checks if a particular privilege exists in catalog BABELFISH_SCHEMA_PERMISSIONS. + */ +bool +privilege_exists_in_bbf_schema_permissions(const char *schema_name, + const char *object_name, + const char *grantee, + bool missing_ok) +{ + Relation bbf_schema_rel; + HeapTuple tuple_bbf_schema; + SysScanDesc scan; + bool catalog_entry_exists = false; + int16 dbid = get_cur_db_id(); + + /* Immediately return false, if SCHEMA name is NULL or it's a shared schema. */ + if (schema_name == NULL || is_shared_schema(schema_name)) + return false; + + if (!missing_ok) + { + ScanKeyData scanKey[4]; + /* Immediately return false, if grantee is NULL or PUBLIC. */ + if ((grantee == NULL) || (strcmp(grantee, PUBLIC_ROLE_NAME) == 0)) + return false; + + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), + AccessShareLock); + ScanKeyInit(&scanKey[0], + Anum_bbf_schema_perms_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(dbid)); + ScanKeyEntryInitialize(&scanKey[1], 0, + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(schema_name)); + ScanKeyEntryInitialize(&scanKey[2], 0, + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(object_name)); + ScanKeyEntryInitialize(&scanKey[3], 0, + Anum_bbf_schema_perms_grantee, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(grantee)); + scan = systable_beginscan(bbf_schema_rel, + get_bbf_schema_perms_idx_oid(), + true, NULL, 4, scanKey); + } + else + { + ScanKeyData scanKey[3]; + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), + AccessShareLock); + ScanKeyInit(&scanKey[0], + Anum_bbf_schema_perms_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(dbid)); + ScanKeyEntryInitialize(&scanKey[1], 0, + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(schema_name)); + ScanKeyEntryInitialize(&scanKey[2], 0, + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(object_name)); + + scan = systable_beginscan(bbf_schema_rel, + get_bbf_schema_perms_idx_oid(), + true, NULL, 3, scanKey); + } + + tuple_bbf_schema = systable_getnext(scan); + if (HeapTupleIsValid(tuple_bbf_schema)) + catalog_entry_exists = true; + + systable_endscan(scan); + table_close(bbf_schema_rel, AccessShareLock); + return catalog_entry_exists; +} + +/* + * Get the value of permission column from BABELFISH_SCHEMA_PERMISSIONS table. + */ +static int +get_privilege_of_object(const char *schema_name, + const char *object_name, + const char *grantee, + const char *object_type) +{ + Relation bbf_schema_rel; + HeapTuple tuple_bbf_schema; + ScanKeyData scanKey[5]; + SysScanDesc scan; + int16 dbid = get_cur_db_id(); + int permission = 0; + + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), + AccessShareLock); + ScanKeyInit(&scanKey[0], + Anum_bbf_schema_perms_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(dbid)); + ScanKeyEntryInitialize(&scanKey[1], 0, + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(schema_name)); + ScanKeyEntryInitialize(&scanKey[2], 0, + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(object_name)); + ScanKeyEntryInitialize(&scanKey[3], 0, + Anum_bbf_schema_perms_grantee, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(grantee)); + ScanKeyEntryInitialize(&scanKey[4], 0, + Anum_bbf_schema_perms_object_type, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(object_type)); + scan = systable_beginscan(bbf_schema_rel, + get_bbf_schema_perms_idx_oid(), + true, NULL, 5, scanKey); + tuple_bbf_schema = systable_getnext(scan); + + if (HeapTupleIsValid(tuple_bbf_schema)) + { + Datum datum; + bool isnull; + datum = heap_getattr(tuple_bbf_schema, Anum_bbf_schema_perms_permission, RelationGetDescr(bbf_schema_rel), &isnull); + permission = DatumGetInt32(datum); + } + + systable_endscan(scan); + table_close(bbf_schema_rel, AccessShareLock); + return permission; +} + +/* + * Removes a row from the catalog BABELFISH_SCHEMA_PERMISSIONS. + */ +void +remove_entry_from_bbf_schema_perms(const char *schema_name, + const char *object_name, + const char *grantee, + const char *object_type) +{ + Relation bbf_schema_rel; + HeapTuple tuple_bbf_schema; + ScanKeyData scanKey[5]; + SysScanDesc scan; + int16 dbid = get_cur_db_id(); + + /* Immediately return false, if SCHEMA name is NULL or it's a shared schema. */ + if (schema_name == NULL || is_shared_schema(schema_name)) + return; + + /* Immediately return, if grantee is NULL or PUBLIC. */ + if ((grantee == NULL) || (strcmp(grantee, PUBLIC_ROLE_NAME) == 0)) + return; + + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), + RowExclusiveLock); + ScanKeyInit(&scanKey[0], + Anum_bbf_schema_perms_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(dbid)); + ScanKeyEntryInitialize(&scanKey[1], 0, + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(schema_name)); + ScanKeyEntryInitialize(&scanKey[2], 0, + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(object_name)); + ScanKeyEntryInitialize(&scanKey[3], 0, + Anum_bbf_schema_perms_grantee, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(grantee)); + ScanKeyEntryInitialize(&scanKey[4], 0, + Anum_bbf_schema_perms_object_type, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(object_type)); + scan = systable_beginscan(bbf_schema_rel, + get_bbf_schema_perms_idx_oid(), + true, NULL, 5, scanKey); + + tuple_bbf_schema = systable_getnext(scan); + + if (HeapTupleIsValid(tuple_bbf_schema)) + CatalogTupleDelete(bbf_schema_rel, &tuple_bbf_schema->t_self); + + systable_endscan(scan); + table_close(bbf_schema_rel, RowExclusiveLock); +} + +/* + * Add an entry to BABELFISH_SCHEMA_PERMISSIONS table, if it doesn't exist already. + * If exists, updates the PERMISSION column in the table. + */ +void +add_or_update_object_in_bbf_schema(const char *schema_name, + const char *object_name, + int new_permission, + const char *grantee, + const char *object_type, + bool is_grant) +{ + if (!privilege_exists_in_bbf_schema_permissions(schema_name, object_name, grantee, false)) + add_entry_to_bbf_schema_perms(schema_name, object_name, new_permission, grantee, object_type); + else + update_privileges_of_object(schema_name, object_name, new_permission, grantee, object_type, is_grant); +} + +/* + * Removes all the rows corresponding to an OBJECT/SCHEMA from the catalog BABELFISH_SCHEMA_PERMISSIONS. + */ +void +clean_up_bbf_schema_permissions(const char *schema_name, + const char *object_name, + bool is_schema) +{ + SysScanDesc scan; + Relation bbf_schema_rel; + HeapTuple tuple_bbf_schema; + int16 dbid = get_cur_db_id(); + + /* Immediately return false, if SCHEMA name is NULL or it's a shared schema. */ + if (schema_name == NULL || is_shared_schema(schema_name)) + return; + + /* Fetch the relation */ + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), + RowExclusiveLock); + + if (is_schema) + { + ScanKeyData scanKey[2]; + ScanKeyInit(&scanKey[0], + Anum_bbf_schema_perms_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(dbid)); + ScanKeyEntryInitialize(&scanKey[1], 0, + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(schema_name)); + scan = systable_beginscan(bbf_schema_rel, + get_bbf_schema_perms_idx_oid(), + true, NULL, 2, scanKey); + } + else + { + ScanKeyData scanKey[3]; + ScanKeyInit(&scanKey[0], + Anum_bbf_schema_perms_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(dbid)); + ScanKeyEntryInitialize(&scanKey[1], 0, + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(schema_name)); + ScanKeyEntryInitialize(&scanKey[2], 0, + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(object_name)); + scan = systable_beginscan(bbf_schema_rel, + get_bbf_schema_perms_idx_oid(), + true, NULL, 3, scanKey); + } + + while ((tuple_bbf_schema = systable_getnext(scan)) != NULL) + { + if (HeapTupleIsValid(tuple_bbf_schema)) + CatalogTupleDelete(bbf_schema_rel, + &tuple_bbf_schema->t_self); + } + + systable_endscan(scan); + table_close(bbf_schema_rel, RowExclusiveLock); +} + +/* + * For all objects belonging to a schema which has OBJECT level permission, + * It grants the permission explicitly when REVOKE has been executed on that + * specific schema. + */ +void +grant_perms_to_objects_in_schema(const char *schema_name, + int permission, + const char *grantee) +{ + SysScanDesc scan; + Relation bbf_schema_rel; + TupleDesc dsc; + HeapTuple tuple_bbf_schema; + const char *object_name; + const char *object_type; + int current_permission; + ScanKeyData scanKey[3]; + int16 dbid = get_cur_db_id(); + const char *db_name = get_cur_db_name(); + + /* Fetch the relation */ + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), + AccessShareLock); + dsc = RelationGetDescr(bbf_schema_rel); + ScanKeyInit(&scanKey[0], + Anum_bbf_schema_perms_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(dbid)); + ScanKeyEntryInitialize(&scanKey[1], 0, + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(schema_name)); + ScanKeyEntryInitialize(&scanKey[2], 0, + Anum_bbf_schema_perms_grantee, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(grantee)); + + scan = systable_beginscan(bbf_schema_rel, get_bbf_schema_perms_idx_oid(), + true, NULL, 3, scanKey); + tuple_bbf_schema = systable_getnext(scan); + + while (HeapTupleIsValid(tuple_bbf_schema)) + { + bool isnull; + object_name = pstrdup(TextDatumGetCString(heap_getattr(tuple_bbf_schema, Anum_bbf_schema_perms_object_name, dsc, &isnull))); + object_type = pstrdup(TextDatumGetCString(heap_getattr(tuple_bbf_schema, Anum_bbf_schema_perms_object_type, dsc, &isnull))); + current_permission = DatumGetInt32(heap_getattr(tuple_bbf_schema, Anum_bbf_schema_perms_permission, dsc, &isnull)); + + /* For each object, grant the permission explicitly. */ + if (strcmp(object_name, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA) != 0) + { + StringInfoData query; + char *schema; + List *res; + Node *res_stmt; + PlannedStmt *wrapper; + const char *priv_name; + + schema = get_physical_schema_name((char *)db_name, schema_name); + initStringInfo(&query); + /* Check if the permission to be REVOKED on SCHEMA exists on the OBJECT. */ + + if (current_permission & permission) + { + priv_name = privilege_to_string(permission); + if (strcmp(object_type, OBJ_RELATION) == 0) + appendStringInfo(&query, "GRANT \"%s\" ON \"%s\".\"%s\" TO \"%s\"; ", priv_name, schema, object_name, grantee); + else if (strcmp(object_type, OBJ_FUNCTION) == 0) + appendStringInfo(&query, "GRANT \"%s\" ON FUNCTION \"%s\".\"%s\" TO \"%s\"; ", priv_name, schema, object_name, grantee); + else if (strcmp(object_type, OBJ_PROCEDURE) == 0) + appendStringInfo(&query, "GRANT \"%s\" ON PROCEDURE \"%s\".\"%s\" TO \"%s\"; ", priv_name, schema, object_name, grantee); + res = raw_parser(query.data, RAW_PARSE_DEFAULT); + res_stmt = ((RawStmt *) linitial(res))->stmt; + + /* need to make a wrapper PlannedStmt */ + wrapper = makeNode(PlannedStmt); + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = res_stmt; + wrapper->stmt_location = 0; + wrapper->stmt_len = 1; + + /* do this step */ + ProcessUtility(wrapper, + "(GRANT STATEMENT )", + false, + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); + } + } + tuple_bbf_schema = systable_getnext(scan); + } + systable_endscan(scan); + table_close(bbf_schema_rel, AccessShareLock); +} + PG_FUNCTION_INFO_V1(update_user_catalog_for_guest_schema); Datum update_user_catalog_for_guest_schema(PG_FUNCTION_ARGS) diff --git a/contrib/babelfishpg_tsql/src/catalog.h b/contrib/babelfishpg_tsql/src/catalog.h index 558969b758..c8a1475b9f 100644 --- a/contrib/babelfishpg_tsql/src/catalog.h +++ b/contrib/babelfishpg_tsql/src/catalog.h @@ -280,6 +280,51 @@ typedef struct FormData_bbf_function_ext typedef FormData_bbf_function_ext *Form_bbf_function_ext; +/***************************************** + * SCHEMA_PERMISSIONS + *****************************************/ +#define BBF_SCHEMA_PERMS_TABLE_NAME "babelfish_schema_permissions" +#define BBF_SCHEMA_PERMS_IDX_NAME "babelfish_schema_permissions_pkey" +#define BBF_SCHEMA_PERMS_NUM_OF_COLS 6 +#define Anum_bbf_schema_perms_dbid 1 +#define Anum_bbf_schema_perms_schema_name 2 +#define Anum_bbf_schema_perms_object_name 3 +#define Anum_bbf_schema_perms_permission 4 +#define Anum_bbf_schema_perms_grantee 5 +#define Anum_bbf_schema_perms_object_type 6 + +#define PUBLIC_ROLE_NAME "public" +#define PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA "ALL" +#define ALL_PERMISSIONS_ON_RELATION 47 /* last 6 bits as 101111 represents ALL privileges on a relation. */ +#define ALL_PERMISSIONS_ON_FUNCTION 128 /* last 8 bits as 10000000 represents ALL privileges on a procedure/function. */ +#define OBJ_SCHEMA "s" +#define OBJ_RELATION "r" +#define OBJ_PROCEDURE "p" +#define OBJ_FUNCTION "f" + +extern Oid bbf_schema_perms_oid; +extern Oid bbf_schema_perms_idx_oid; + +typedef struct FormData_bbf_schema_perms +{ + int16 dbid; + VarChar schema_name; + VarChar object_name; + int32 permission; + VarChar grantee; + char object_type; +} FormData_bbf_schema_perms; + +typedef FormData_bbf_schema_perms *Form_bbf_schema_perms; + +extern void add_entry_to_bbf_schema_perms(const char *schema_name, const char *object_name, int permission, const char *grantee, const char *object_type); +extern bool privilege_exists_in_bbf_schema_permissions(const char *schema_name, const char *object_name, const char *grantee, bool missing_ok); +extern void update_privileges_of_object(const char *schema_name, const char *object_name, int new_permission, const char *grantee, const char *object_type, bool is_grant); +extern void remove_entry_from_bbf_schema_perms(const char *schema_name, const char *object_name, const char *grantee, const char *object_type); +extern void add_or_update_object_in_bbf_schema(const char *schema_name, const char *object_name, int new_permission, const char *grantee, const char *object_type, bool is_grant); +extern void clean_up_bbf_schema_permissions(const char *schema_name, const char *object_name, bool is_schema); +extern void grant_perms_to_objects_in_schema(const char *schema_name, int permission, const char *grantee); + /***************************************** * DOMAIN MAPPING *****************************************/ diff --git a/contrib/babelfishpg_tsql/src/codegen.c b/contrib/babelfishpg_tsql/src/codegen.c index 745152d1dd..c42eefa3d7 100644 --- a/contrib/babelfishpg_tsql/src/codegen.c +++ b/contrib/babelfishpg_tsql/src/codegen.c @@ -302,6 +302,7 @@ stmt_default_act(Walker_context *ctx, PLtsql_stmt *stmt) case PLTSQL_STMT_GRANTDB: case PLTSQL_STMT_CHANGE_DBOWNER: case PLTSQL_STMT_FULLTEXTINDEX: + case PLTSQL_STMT_GRANTSCHEMA: case PLTSQL_STMT_INSERT_BULK: case PLTSQL_STMT_DBCC: case PLTSQL_STMT_SET_EXPLAIN_MODE: diff --git a/contrib/babelfishpg_tsql/src/dbcmds.c b/contrib/babelfishpg_tsql/src/dbcmds.c index 4fda259cb8..89d4b081af 100644 --- a/contrib/babelfishpg_tsql/src/dbcmds.c +++ b/contrib/babelfishpg_tsql/src/dbcmds.c @@ -133,7 +133,7 @@ gen_createdb_subcmds(const char *schema, const char *dbo, const char *db_owner, update_CreateRoleStmt(stmt, dbo, NULL, db_owner); stmt = parsetree_nth_stmt(res, i++); - update_GrantStmt(stmt, get_database_name(MyDatabaseId), NULL, dbo); + update_GrantStmt(stmt, get_database_name(MyDatabaseId), NULL, dbo, NULL); if (guest) { @@ -240,7 +240,7 @@ gen_dropdb_subcmds(const char *schema, update_DropOwnedStmt(stmt, list_make2(pstrdup(db_owner), pstrdup(dbo))); stmt = parsetree_nth_stmt(stmt_list, i++); - update_GrantStmt(stmt, get_database_name(MyDatabaseId), NULL, dbo); + update_GrantStmt(stmt, get_database_name(MyDatabaseId), NULL, dbo, NULL); stmt = parsetree_nth_stmt(stmt_list, i++); update_DropRoleStmt(stmt, db_owner); diff --git a/contrib/babelfishpg_tsql/src/iterative_exec.c b/contrib/babelfishpg_tsql/src/iterative_exec.c index c057ee7d11..6e27865f04 100644 --- a/contrib/babelfishpg_tsql/src/iterative_exec.c +++ b/contrib/babelfishpg_tsql/src/iterative_exec.c @@ -809,6 +809,9 @@ dispatch_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt) } exec_stmt_change_dbowner(estate, (PLtsql_stmt_change_dbowner *) stmt); break; + case PLTSQL_STMT_GRANTSCHEMA: + exec_stmt_grantschema(estate, (PLtsql_stmt_grantschema *) stmt); + break; case PLTSQL_STMT_FULLTEXTINDEX: if (pltsql_explain_only) { diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index ae74d5e8a5..8193b5cf13 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -55,6 +55,7 @@ static int exec_stmt_usedb(PLtsql_execstate *estate, PLtsql_stmt_usedb *stmt); static int exec_stmt_usedb_explain(PLtsql_execstate *estate, PLtsql_stmt_usedb *stmt, bool shouldRestoreDb); static int exec_stmt_grantdb(PLtsql_execstate *estate, PLtsql_stmt_grantdb *stmt); static int exec_stmt_fulltextindex(PLtsql_execstate *estate, PLtsql_stmt_fulltextindex *stmt); +static int exec_stmt_grantschema(PLtsql_execstate *estate, PLtsql_stmt_grantschema *stmt); static int exec_stmt_insert_execute_select(PLtsql_execstate *estate, PLtsql_expr *expr); static int exec_stmt_insert_bulk(PLtsql_execstate *estate, PLtsql_stmt_insert_bulk *expr); static int exec_stmt_dbcc(PLtsql_execstate *estate, PLtsql_stmt_dbcc *stmt); @@ -3688,6 +3689,135 @@ get_insert_bulk_kilobytes_per_batch() return insert_bulk_kilobytes_per_batch; } +static int +exec_stmt_grantschema(PLtsql_execstate *estate, PLtsql_stmt_grantschema *stmt) +{ + char *dbname = get_cur_db_name(); + char *login = GetUserNameFromId(GetSessionUserId(), false); + bool login_is_db_owner; + char *schema_name; + ListCell *lc; + Oid schemaOid; + char *user = GetUserNameFromId(GetUserId(), false); + const char *db_owner = get_owner_of_db(dbname); + + login_is_db_owner = 0 == strcmp(login, db_owner); + schema_name = get_physical_schema_name(dbname, stmt->schema_name); + + if(schema_name) + { + /* Return immediately for shared schema. */ + if(is_shared_schema(schema_name)) + return PLTSQL_RC_OK; + + schemaOid = LookupExplicitNamespace(schema_name, true); + } + else + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as \"\" or [] are not allowed. Change the alias to a valid name."))); + } + + if (!OidIsValid(schemaOid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("schema \"%s\" does not exist", + stmt->schema_name))); + + foreach(lc, stmt->grantees) + { + char *rolname = NULL; + char *grantee_name = (char *) lfirst(lc); + Oid role_oid; + bool is_public = 0 == strcmp(grantee_name, PUBLIC_ROLE_NAME); + if (!is_public) + rolname = get_physical_user_name(dbname, grantee_name); + else + rolname = pstrdup(PUBLIC_ROLE_NAME); + role_oid = get_role_oid(rolname, true); + + /* Special database roles should throw an error. */ + if (strcmp(grantee_name, "db_owner") == 0) + ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Cannot grant, deny or revoke permissions to or from special roles."))); + + if (!is_public && !OidIsValid(role_oid)) + { + /* sys or information_schema roles should throw an error. */ + if ((strcmp(grantee_name, "sys") == 0) || (strcmp(grantee_name, "information_schema") == 0)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Cannot grant, deny, or revoke permissions to sa, dbo, entity owner, information_schema, sys, or yourself."))); + else + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Cannot find the principal '%s', because it does not exist or you do not have permission.", grantee_name))); + } + + if ((strcmp(rolname, user) == 0) || (!is_public && object_ownercheck(NamespaceRelationId, schemaOid, role_oid)) || is_member_of_role(role_oid, get_sysadmin_oid())) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Cannot grant, deny, or revoke permissions to sa, dbo, entity owner, information_schema, sys, or yourself."))); + + /* + * If the login is not the db owner or the login is not the member of + * sysadmin or login is not the schema owner, then it doesn't have the permission to GRANT/REVOKE. + */ + if (!is_member_of_role(GetSessionUserId(), get_sysadmin_oid()) && !login_is_db_owner && !object_ownercheck(NamespaceRelationId,schemaOid, GetUserId())) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Cannot find the schema \"%s\", because it does not exist or you do not have permission.", stmt->schema_name))); + + /* Execute the GRANT SCHEMA subcommands. */ + if (stmt->privileges & ACL_EXECUTE) + exec_grantschema_subcmds(schema_name, rolname, stmt->is_grant, stmt->with_grant_option, ACL_EXECUTE); + if (stmt->privileges & ACL_SELECT) + exec_grantschema_subcmds(schema_name, rolname, stmt->is_grant, stmt->with_grant_option, ACL_SELECT); + if (stmt->privileges & ACL_INSERT) + exec_grantschema_subcmds(schema_name, rolname, stmt->is_grant, stmt->with_grant_option, ACL_INSERT); + if (stmt->privileges & ACL_UPDATE) + exec_grantschema_subcmds(schema_name, rolname, stmt->is_grant, stmt->with_grant_option, ACL_UPDATE); + if (stmt->privileges & ACL_DELETE) + exec_grantschema_subcmds(schema_name, rolname, stmt->is_grant, stmt->with_grant_option, ACL_DELETE); + if (stmt->privileges & ACL_REFERENCES) + exec_grantschema_subcmds(schema_name, rolname, stmt->is_grant, stmt->with_grant_option, ACL_REFERENCES); + + if (stmt->is_grant) + { + /* For GRANT statement, add or update privileges in the catalog. */ + add_or_update_object_in_bbf_schema(stmt->schema_name, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, stmt->privileges, rolname, OBJ_SCHEMA, true); + } + else + { + /* For REVOKE statement, update privileges in the catalog. */ + if (privilege_exists_in_bbf_schema_permissions(stmt->schema_name, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, rolname, false)) + { + /* If any object in the schema has the OBJECT level permission. Then, internally grant that permission back. */ + if (stmt->privileges & ACL_EXECUTE) + grant_perms_to_objects_in_schema(stmt->schema_name, ACL_EXECUTE, rolname); + if (stmt->privileges & ACL_SELECT) + grant_perms_to_objects_in_schema(stmt->schema_name, ACL_SELECT, rolname); + if (stmt->privileges & ACL_INSERT) + grant_perms_to_objects_in_schema(stmt->schema_name, ACL_INSERT, rolname); + if (stmt->privileges & ACL_UPDATE) + grant_perms_to_objects_in_schema(stmt->schema_name, ACL_UPDATE, rolname); + if (stmt->privileges & ACL_DELETE) + grant_perms_to_objects_in_schema(stmt->schema_name, ACL_DELETE, rolname); + if (stmt->privileges & ACL_REFERENCES) + grant_perms_to_objects_in_schema(stmt->schema_name, ACL_REFERENCES, rolname); + update_privileges_of_object(stmt->schema_name, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, stmt->privileges, rolname, OBJ_SCHEMA, false); + } + } + pfree(rolname); + } + pfree(user); + pfree(schema_name); + pfree(dbname); + pfree(login); + return PLTSQL_RC_OK; +} + /* * ALTER AUTHORIZATION ON DATABASE::dbname TO loginname */ diff --git a/contrib/babelfishpg_tsql/src/pl_funcs-2.c b/contrib/babelfishpg_tsql/src/pl_funcs-2.c index 80352240b6..4e2c77f82d 100644 --- a/contrib/babelfishpg_tsql/src/pl_funcs-2.c +++ b/contrib/babelfishpg_tsql/src/pl_funcs-2.c @@ -485,6 +485,7 @@ free_stmt2(PLtsql_stmt *stmt) case PLTSQL_STMT_GRANTDB: case PLTSQL_STMT_CHANGE_DBOWNER: case PLTSQL_STMT_FULLTEXTINDEX: + case PLTSQL_STMT_GRANTSCHEMA: case PLTSQL_STMT_SET_EXPLAIN_MODE: { /* Nothing to free */ diff --git a/contrib/babelfishpg_tsql/src/pl_handler.c b/contrib/babelfishpg_tsql/src/pl_handler.c index 1df622785e..cab41ed592 100644 --- a/contrib/babelfishpg_tsql/src/pl_handler.c +++ b/contrib/babelfishpg_tsql/src/pl_handler.c @@ -128,6 +128,14 @@ static void bbf_ProcessUtility(PlannedStmt *pstmt, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc); +static void call_prev_ProcessUtility(PlannedStmt *pstmt, + const char *queryString, + bool readOnlyTree, + ProcessUtilityContext context, + ParamListInfo params, + QueryEnvironment *queryEnv, + DestReceiver *dest, + QueryCompletion *qc); static void set_pgtype_byval(List *name, bool byval); static bool pltsql_truncate_identifier(char *ident, int len, bool warn); static Name pltsql_cstr_to_name(char *s, int len); @@ -3481,6 +3489,7 @@ bbf_ProcessUtility(PlannedStmt *pstmt, List *res; GrantStmt *stmt; PlannedStmt *wrapper; + RoleSpec *rolspec = create_schema->authrole; if (strcmp(queryString, "(CREATE LOGICAL DATABASE )") == 0 && context == PROCESS_UTILITY_SUBCOMMAND) @@ -3529,7 +3538,17 @@ bbf_ProcessUtility(PlannedStmt *pstmt, NULL); CommandCounterIncrement(); - + /* Grant ALL schema privileges to the user.*/ + if (rolspec && strcmp(queryString, "(CREATE LOGICAL DATABASE )") != 0) + { + int permissions[6] = {ACL_INSERT, ACL_SELECT, ACL_UPDATE, ACL_DELETE, ACL_REFERENCES, ACL_EXECUTE}; + int i; + for (i = 0; i < 6; i++) + { + /* Execute the GRANT SCHEMA subcommands. */ + exec_grantschema_subcmds(create_schema->schemaname, rolspec->rolename, true, false, permissions[i]); + } + } return; } else @@ -3543,7 +3562,6 @@ bbf_ProcessUtility(PlannedStmt *pstmt, { if (sql_dialect == SQL_DIALECT_TSQL) bbf_ExecDropStmt(drop_stmt); - break; } @@ -3555,10 +3573,11 @@ bbf_ProcessUtility(PlannedStmt *pstmt, * database command. */ const char *schemaname = strVal(lfirst(list_head(drop_stmt->objects))); + char *cur_db = get_cur_db_name(); + const char *logicalschema = get_logical_schema_name(schemaname, true); if (strcmp(queryString, "(DROP DATABASE )") != 0) { - char *cur_db = get_cur_db_name(); char *guest_schema_name = get_physical_schema_name(cur_db, "guest"); if (strcmp(schemaname, guest_schema_name) == 0) @@ -3571,6 +3590,7 @@ bbf_ProcessUtility(PlannedStmt *pstmt, bbf_ExecDropStmt(drop_stmt); del_ns_ext_info(schemaname, drop_stmt->missing_ok); + clean_up_bbf_schema_permissions(logicalschema, NULL, true); if (prev_ProcessUtility) prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, @@ -3814,16 +3834,176 @@ bbf_ProcessUtility(PlannedStmt *pstmt, } break; } + case T_GrantStmt: + { + GrantStmt *grant = (GrantStmt *) parsetree; + char *dbname = get_cur_db_name(); + const char *current_user = GetUserNameFromId(GetUserId(), false); + /* Ignore when GRANT statement has no specific named object. */ + if (sql_dialect != SQL_DIALECT_TSQL || grant->targtype != ACL_TARGET_OBJECT) + break; + Assert(list_length(grant->objects) == 1); + if (grant->objtype == OBJECT_SCHEMA) + break; + else if (grant->objtype == OBJECT_TABLE) + { + /* Ignore CREATE database subcommands */ + if (strcmp("(CREATE LOGICAL DATABASE )", queryString) != 0) + { + RangeVar *rv = (RangeVar *) linitial(grant->objects); + const char *logical_schema = NULL; + char *obj = rv->relname; + ListCell *lc; + ListCell *lc1; + if (rv->schemaname != NULL) + logical_schema = get_logical_schema_name(rv->schemaname, true); + else + logical_schema = get_authid_user_ext_schema_name(dbname, current_user); + + /* If ALL PRIVILEGES is granted/revoked. */ + if (list_length(grant->privileges) == 0) + { + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + if (grant->is_grant) + add_or_update_object_in_bbf_schema(logical_schema, obj, ALL_PERMISSIONS_ON_RELATION, rol_spec->rolename, OBJ_RELATION, true); + else + { + /* + * 1. If permission on schema exists, don't revoke any permission from the object. + * 2. If permission on object exists, update the privilege in the catalog and revoke permission. + */ + update_privileges_of_object(logical_schema, obj, ALL_PERMISSIONS_ON_RELATION, rol_spec->rolename, OBJ_RELATION, false); + if (privilege_exists_in_bbf_schema_permissions(logical_schema, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, rol_spec->rolename, false)) + return; + } + } + call_prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); + } + foreach(lc1, grant->privileges) + { + AccessPriv *ap = (AccessPriv *) lfirst(lc1); + AclMode privilege = string_to_privilege(ap->priv_name); + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + if (grant->is_grant) + { + call_prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); + /* Don't add/update an entry, if the permission is granted on column list.*/ + if (ap->cols == NULL) + add_or_update_object_in_bbf_schema(logical_schema, obj, privilege, rol_spec->rolename, OBJ_RELATION, true); + } + else + { + /* + * If permission on schema exists, don't revoke any permission from the object. + */ + if (!privilege_exists_in_bbf_schema_permissions(logical_schema, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, rol_spec->rolename, false)) + { + call_prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); + } + /* Don't update an entry, if the permission is granted on column list.*/ + if (ap->cols == NULL) + update_privileges_of_object(logical_schema, obj, privilege, rol_spec->rolename, OBJ_RELATION, false); + } + } + } + return; + } + } + else if ((grant->objtype == OBJECT_PROCEDURE) || (grant->objtype == OBJECT_FUNCTION)) + { + ObjectWithArgs *ob = (ObjectWithArgs *) linitial(grant->objects); + ListCell *lc; + ListCell *lc1; + const char *logicalschema = NULL; + char *funcname = NULL; + const char *obj_type = NULL; + if (grant->objtype == OBJECT_FUNCTION) + obj_type = OBJ_FUNCTION; + else + obj_type = OBJ_PROCEDURE; + if (list_length(ob->objname) == 1) + { + Node *func = (Node *) linitial(ob->objname); + funcname = strVal(func); + logicalschema = get_authid_user_ext_schema_name(dbname, current_user); + } + else + { + Node *schema = (Node *) linitial(ob->objname); + char *schemaname = strVal(schema); + Node *func = (Node *) lsecond(ob->objname); + logicalschema = get_logical_schema_name(schemaname, true); + funcname = strVal(func); + } + + /* If ALL PRIVILEGES is granted/revoked. */ + if (list_length(grant->privileges) == 0) + { + /* + * Case: When ALL PRIVILEGES is revoked internally during create function. + * Check if schema entry exists in the catalog, do not revoke any permission if exists. + */ + if ((pstmt->stmt_len == 0) && privilege_exists_in_bbf_schema_permissions(logicalschema, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, NULL, true)) + return; + + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + if (grant->is_grant) + { + add_or_update_object_in_bbf_schema(logicalschema, funcname, ALL_PERMISSIONS_ON_FUNCTION, rol_spec->rolename, obj_type, true); + } + else + { + /* + * 1. If permission on schema exists, don't revoke any permission from the object. + * 2. If permission on object exists, update the privilege in the catalog and revoke permission. + */ + update_privileges_of_object(logicalschema, funcname, ALL_PERMISSIONS_ON_FUNCTION, rol_spec->rolename, obj_type, false); + if (privilege_exists_in_bbf_schema_permissions(logicalschema, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, rol_spec->rolename, false)) + return; + } + } + call_prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); + } + foreach(lc1, grant->privileges) + { + AccessPriv *ap = (AccessPriv *) lfirst(lc1); + AclMode privilege = string_to_privilege(ap->priv_name); + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + if (grant->is_grant) + { + call_prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); + add_or_update_object_in_bbf_schema(logicalschema, funcname, privilege, rol_spec->rolename, obj_type, true); + } + else + { + /* + * If permission on schema exists, don't revoke any permission from the object. + */ + if (!privilege_exists_in_bbf_schema_permissions(logicalschema, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, rol_spec->rolename, false)) + { + call_prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); + } + /* Update the privilege in the catalog. */ + update_privileges_of_object(logicalschema, funcname, privilege, rol_spec->rolename, obj_type, false); + } + } + } + return; + } + } default: break; } - if (prev_ProcessUtility) - prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); - else - standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); + call_prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); /* Cleanup babelfish_server_options catalog when tds_fdw extension is dropped */ if (sql_dialect == SQL_DIALECT_PG && nodeTag(parsetree) == T_DropStmt) @@ -3840,6 +4020,24 @@ bbf_ProcessUtility(PlannedStmt *pstmt, } } +static void +call_prev_ProcessUtility(PlannedStmt *pstmt, + const char *queryString, + bool readOnlyTree, + ProcessUtilityContext context, + ParamListInfo params, + QueryEnvironment *queryEnv, + DestReceiver *dest, + QueryCompletion *qc) +{ + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); +} + /* * Update the pg_type catalog entry for the given name to have * typbyval set to the given value. @@ -5921,6 +6119,7 @@ bbf_ExecDropStmt(DropStmt *stmt) Relation relation = NULL; Oid schema_oid; ListCell *cell; + const char *logicalschema = NULL; db_id = get_cur_db_id(); @@ -5961,6 +6160,8 @@ bbf_ExecDropStmt(DropStmt *stmt) schema_oid = get_object_namespace(&address); if (OidIsValid(schema_oid)) schema_name = get_namespace_name(schema_oid); + if (schema_name != NULL) + logicalschema = get_logical_schema_name(schema_name, true); if (schema_name && major_name) { @@ -5986,6 +6187,7 @@ bbf_ExecDropStmt(DropStmt *stmt) major_name, NULL); } } + clean_up_bbf_schema_permissions(logicalschema, major_name, false); } } else if (stmt->removeType == OBJECT_PROCEDURE || @@ -6029,6 +6231,8 @@ bbf_ExecDropStmt(DropStmt *stmt) schema_oid = get_object_namespace(&address); if (OidIsValid(schema_oid)) schema_name = get_namespace_name(schema_oid); + if (schema_name != NULL) + logicalschema = get_logical_schema_name(schema_name, true); if (schema_name && major_name) { @@ -6042,6 +6246,7 @@ bbf_ExecDropStmt(DropStmt *stmt) delete_extended_property(db_id, type, schema_name, major_name, NULL); } + clean_up_bbf_schema_permissions(logicalschema, major_name, false); } } } diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index 1fac454609..15223c2b7a 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -197,6 +197,7 @@ typedef enum PLtsql_stmt_type PLTSQL_STMT_CHANGE_DBOWNER, PLTSQL_STMT_DBCC, PLTSQL_STMT_FULLTEXTINDEX, + PLTSQL_STMT_GRANTSCHEMA } PLtsql_stmt_type; /* @@ -1067,6 +1068,20 @@ typedef struct PLtsql_stmt_fulltextindex bool is_create; /* flag for create index */ } PLtsql_stmt_fulltextindex; +/* + * Grant on schema stmt + */ +typedef struct PLtsql_stmt_grantschema +{ + PLtsql_stmt_type cmd_type; + int lineno; + bool is_grant; + int privileges; + List *grantees; /* list of users */ + bool with_grant_option; + char *schema_name; /* schema name */ +} PLtsql_stmt_grantschema; + /* * ASSERT statement */ @@ -1988,6 +2003,8 @@ extern void pltsql_exec_get_datum_type_info(PLtsql_execstate *estate, extern int get_insert_bulk_rows_per_batch(void); extern int get_insert_bulk_kilobytes_per_batch(void); extern char *get_original_query_string(void); +extern AclMode string_to_privilege(const char *privname); +extern const char *privilege_to_string(AclMode privilege); /* * Functions for namespace handling in pl_funcs.c @@ -2049,6 +2066,7 @@ extern char *get_fulltext_index_name(Oid relid, const char *table_name); extern const char *gen_schema_name_for_fulltext_index(const char *schema_name); extern bool check_fulltext_exist(const char *schema_name, const char *table_name); extern bool is_unique_index(Oid relid, const char *index_name); +extern void exec_grantschema_subcmds(const char *schema, const char *rolname, bool is_grant, bool with_grant_option, AclMode privilege); extern int TsqlUTF8LengthInUTF16(const void *vin, int len); extern void TsqlCheckUTF16Length_bpchar(const char *s, int32 len, int32 maxlen, int charlen, bool isExplicit); extern void TsqlCheckUTF16Length_varchar(const char *s, int32 len, int32 maxlen, bool isExplicit); @@ -2087,7 +2105,7 @@ extern void update_DropOwnedStmt(Node *n, List *role_list); extern void update_DropRoleStmt(Node *n, const char *role); extern void update_DropStmt(Node *n, const char *object); extern void update_GrantRoleStmt(Node *n, List *privs, List *roles); -extern void update_GrantStmt(Node *n, const char *object, const char *obj_schema, const char *grantee); +extern void update_GrantStmt(Node *n, const char *object, const char *obj_schema, const char *grantee, const char *priv); extern void update_RenameStmt(Node *n, const char *old_name, const char *new_name); extern void update_ViewStmt(Node *n, const char *view_schema); extern void pltsql_check_or_set_default_typmod(TypeName *typeName, int32 *typmod, bool is_cast); diff --git a/contrib/babelfishpg_tsql/src/pltsql_utils.c b/contrib/babelfishpg_tsql/src/pltsql_utils.c index a3f28fe37a..02e0eaaad0 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_utils.c +++ b/contrib/babelfishpg_tsql/src/pltsql_utils.c @@ -1048,7 +1048,7 @@ update_GrantRoleStmt(Node *n, List *privs, List *roles) } void -update_GrantStmt(Node *n, const char *object, const char *obj_schema, const char *grantee) +update_GrantStmt(Node *n, const char *object, const char *obj_schema, const char *grantee, const char *priv) { GrantStmt *stmt = (GrantStmt *) n; @@ -1060,16 +1060,49 @@ update_GrantStmt(Node *n, const char *object, const char *obj_schema, const char else if (obj_schema && stmt->objects) { RangeVar *tmp = (RangeVar *) llast(stmt->objects); - tmp->schemaname = pstrdup(obj_schema); } if (grantee && stmt->grantees) { RoleSpec *tmp = (RoleSpec *) llast(stmt->grantees); - + if (strcmp(grantee, PUBLIC_ROLE_NAME) == 0) + { + tmp->roletype = ROLESPEC_PUBLIC; + } tmp->rolename = pstrdup(grantee); } + + if (priv && stmt->privileges) + { + AccessPriv *tmp = (AccessPriv *) llast(stmt->privileges); + tmp->priv_name = pstrdup(priv); + } +} + +static void +update_AlterDefaultPrivilegesStmt(Node *n, const char *object, const char *grantee, const char *priv) +{ + AlterDefaultPrivilegesStmt *stmt = (AlterDefaultPrivilegesStmt *) n; + ListCell *lc; + + if (!IsA(stmt, AlterDefaultPrivilegesStmt)) + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("query is not a AlterDefaultPrivilegesStmt"))); + + if (grantee && priv && stmt->action) + { + update_GrantStmt((Node *)(stmt->action), NULL, NULL, grantee, priv); + } + + foreach(lc, stmt->options) + { + if (object) + { + DefElem *tmp = (DefElem *) lfirst(lc); + tmp->defname = pstrdup("schemas"); + tmp->arg = (Node *)list_make1(makeString((char *)object)); + } + } } void @@ -2006,3 +2039,152 @@ exec_alter_role_cmd(char *query_str, RoleSpec *role) /* make sure later steps can see the object created here */ CommandCounterIncrement(); } + +/* + * Helper function to generate GRANT on SCHEMA subcommands. + */ +static List +*gen_grantschema_subcmds(const char *schema, const char *rolname, bool is_grant, bool with_grant_option, AclMode privilege) +{ + StringInfoData query; + List *stmt_list; + Node *stmt; + int expected_stmts = 2; + int i = 0; + initStringInfo(&query); + if (is_grant) + { + if (privilege == ACL_EXECUTE) + { + if (with_grant_option) + { + appendStringInfo(&query, "GRANT dummy ON ALL FUNCTIONS IN SCHEMA dummy TO dummy WITH GRANT OPTION; "); + appendStringInfo(&query, "GRANT dummy ON ALL PROCEDURES IN SCHEMA dummy TO dummy WITH GRANT OPTION; "); + } + else + { + appendStringInfo(&query, "GRANT dummy ON ALL FUNCTIONS IN SCHEMA dummy TO dummy; "); + appendStringInfo(&query, "GRANT dummy ON ALL PROCEDURES IN SCHEMA dummy TO dummy; "); + } + } + else + { + if (with_grant_option) + appendStringInfo(&query, "GRANT dummy ON ALL TABLES IN SCHEMA dummy TO dummy WITH GRANT OPTION; "); + else + appendStringInfo(&query, "GRANT dummy ON ALL TABLES IN SCHEMA dummy TO dummy; "); + appendStringInfo(&query, "ALTER DEFAULT PRIVILEGES IN SCHEMA dummy GRANT dummy ON TABLES TO dummy; "); + } + } + else + { + if (privilege == ACL_EXECUTE) + { + appendStringInfo(&query, "REVOKE dummy ON ALL FUNCTIONS IN SCHEMA dummy FROM dummy; "); + appendStringInfo(&query, "REVOKE dummy ON ALL PROCEDURES IN SCHEMA dummy FROM dummy; "); + } + else + { + appendStringInfo(&query, "REVOKE dummy ON ALL TABLES IN SCHEMA dummy FROM dummy; "); + appendStringInfo(&query, "ALTER DEFAULT PRIVILEGES IN SCHEMA dummy REVOKE dummy ON TABLES FROM dummy; "); + } + } + stmt_list = raw_parser(query.data, RAW_PARSE_DEFAULT); + if (list_length(stmt_list) != expected_stmts) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Expected %d statements, but got %d statements after parsing", + expected_stmts, list_length(stmt_list)))); + /* Replace dummy elements in parsetree with real values */ + stmt = parsetree_nth_stmt(stmt_list, i++); + update_GrantStmt(stmt, schema, NULL, rolname, privilege_to_string(privilege)); + + stmt = parsetree_nth_stmt(stmt_list, i++); + if (privilege == ACL_EXECUTE) + update_GrantStmt(stmt, schema, NULL, rolname, privilege_to_string(privilege)); + else + update_AlterDefaultPrivilegesStmt(stmt, schema, rolname, privilege_to_string(privilege)); + + pfree(query.data); + return stmt_list; +} + +/* + * Helper function to execute GRANT on SCHEMA subcommands using + * ProcessUtility(). Caller should make sure their + * inputs are sanitized to prevent unexpected behaviour. + */ +void +exec_grantschema_subcmds(const char *schema, const char *rolname, bool is_grant, bool with_grant_option, AclMode privilege) +{ + List *parsetree_list; + ListCell *parsetree_item; + + parsetree_list = gen_grantschema_subcmds(schema, rolname, is_grant, with_grant_option, privilege); + /* Run all subcommands */ + foreach(parsetree_item, parsetree_list) + { + Node *stmt = ((RawStmt *) lfirst(parsetree_item))->stmt; + PlannedStmt *wrapper; + + /* need to make a wrapper PlannedStmt */ + wrapper = makeNode(PlannedStmt); + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = stmt; + wrapper->stmt_location = 0; + wrapper->stmt_len = 0; + + /* do this step */ + ProcessUtility(wrapper, + "(GRANT SCHEMA )", + false, + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); + } +} + +AclMode +string_to_privilege(const char *privname) +{ + if (strcmp(privname, "insert") == 0) + return ACL_INSERT; + if (strcmp(privname, "select") == 0) + return ACL_SELECT; + if (strcmp(privname, "update") == 0) + return ACL_UPDATE; + if (strcmp(privname, "delete") == 0) + return ACL_DELETE; + if (strcmp(privname, "references") == 0) + return ACL_REFERENCES; + if (strcmp(privname, "execute") == 0) + return ACL_EXECUTE; + else + return 0; +} + +const char * +privilege_to_string(AclMode privilege) +{ + switch (privilege) + { + case ACL_INSERT: + return "insert"; + case ACL_SELECT: + return "select"; + case ACL_UPDATE: + return "update"; + case ACL_DELETE: + return "delete"; + case ACL_REFERENCES: + return "references"; + case ACL_EXECUTE: + return "execute"; + default: + elog(ERROR, "unrecognized privilege: %d", (int) privilege); + } + return NULL; +} \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/src/stmt_walker.c b/contrib/babelfishpg_tsql/src/stmt_walker.c index 6d996059d8..b606a4f7f3 100644 --- a/contrib/babelfishpg_tsql/src/stmt_walker.c +++ b/contrib/babelfishpg_tsql/src/stmt_walker.c @@ -110,6 +110,7 @@ stmt_walker(PLtsql_stmt *stmt, WalkerFunc walker, void *context) case PLTSQL_STMT_CHANGE_DBOWNER: case PLTSQL_STMT_FULLTEXTINDEX: case PLTSQL_STMT_DBCC: + case PLTSQL_STMT_GRANTSCHEMA: break; /* TSQL-only executable node */ case PLTSQL_STMT_SAVE_CTX: @@ -211,6 +212,7 @@ general_walker_func(PLtsql_stmt *stmt, void *context) DISPATCH(CHANGE_DBOWNER, change_dbowner) DISPATCH(DBCC, dbcc) DISPATCH(FULLTEXTINDEX, fulltextindex) + DISPATCH(GRANTSCHEMA, grantschema) /* TSQL-only executable node */ DISPATCH(SAVE_CTX, save_ctx) diff --git a/contrib/babelfishpg_tsql/src/stmt_walker.h b/contrib/babelfishpg_tsql/src/stmt_walker.h index 885f0058a5..7704d9c4f1 100644 --- a/contrib/babelfishpg_tsql/src/stmt_walker.h +++ b/contrib/babelfishpg_tsql/src/stmt_walker.h @@ -90,6 +90,7 @@ typedef bool (*Stmt_grantdb_act) ACTION_SIGNITURE(grantdb); typedef bool (*Stmt_change_dbowner_act) ACTION_SIGNITURE(change_dbowner); typedef bool (*Stmt_dbcc_act) ACTION_SIGNITURE(dbcc); typedef bool (*Stmt_fulltextindex_act) ACTION_SIGNITURE(fulltextindex); +typedef bool (*Stmt_grantschema_act) ACTION_SIGNITURE(grantschema); /* TSQL-only executable node */ typedef bool (*Stmt_save_ctx) ACTION_SIGNITURE(save_ctx); @@ -143,6 +144,7 @@ typedef struct Walker_context Stmt_change_dbowner_act change_dbowner_act; Stmt_dbcc_act dbcc_act; Stmt_fulltextindex_act fulltextindex_act; + Stmt_grantschema_act grantschema_act; /* TSQL-only executable node */ Stmt_save_ctx save_ctx_act; diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index 2dbf21c32d..11b1a75a97 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -25,6 +25,7 @@ #define JOIN_HINTS_INFO_VECTOR_SIZE 6 #define RAISE_ERROR_PARAMS_LIMIT 20 +#define PUBLIC_ROLE_NAME "public" #pragma GCC diagnostic push @@ -1890,32 +1891,80 @@ class tsqlBuilder : public tsqlCommonMutator void exitSecurity_statement(TSqlParser::Security_statementContext *ctx) override { - if (ctx->grant_statement() && ctx->grant_statement()->TO() && !ctx->grant_statement()->permission_object() - && ctx->grant_statement()->permissions()) + if (ctx->grant_statement()) { - for (auto perm : ctx->grant_statement()->permissions()->permission()) + auto grant = ctx->grant_statement(); + if (grant->TO() && !grant->permission_object() && grant->permissions()) { - auto single_perm = perm->single_permission(); - if (single_perm->CONNECT()) + for (auto perm : grant->permissions()->permission()) { - clear_rewritten_query_fragment(); - return; + auto single_perm = perm->single_permission(); + if (single_perm->CONNECT()) + { + clear_rewritten_query_fragment(); + return; + } + } + } + else if (grant->ON() && grant->permission_object() && grant->permission_object()->object_type() && grant->permission_object()->object_type()->SCHEMA()) + { + if (grant->TO() && grant->principals() && grant->permissions()) + { + for (auto perm: grant->permissions()->permission()) + { + auto single_perm = perm->single_permission(); + if (single_perm->EXECUTE() + || single_perm->EXEC() + || single_perm->SELECT() + || single_perm->INSERT() + || single_perm->UPDATE() + || single_perm->DELETE() + || single_perm->REFERENCES()) + { + return; + } + } } } } - else if (ctx->revoke_statement() && ctx->revoke_statement()->FROM() && !ctx->revoke_statement()->permission_object() - && ctx->revoke_statement()->permissions()) + else if (ctx->revoke_statement()) { - for (auto perm : ctx->revoke_statement()->permissions()->permission()) + auto revoke = ctx->revoke_statement(); + if (revoke->FROM() && !revoke->permission_object() && revoke->permissions()) { - auto single_perm = perm->single_permission(); - if (single_perm->CONNECT()) + for (auto perm : revoke->permissions()->permission()) + { + auto single_perm = perm->single_permission(); + if (single_perm->CONNECT()) + { + clear_rewritten_query_fragment(); + return; + } + } + } + + else if (revoke->ON() && revoke->permission_object() && revoke->permission_object()->object_type() && revoke->permission_object()->object_type()->SCHEMA()) + { + if (revoke->FROM() && revoke->principals() && revoke->permissions()) { - clear_rewritten_query_fragment(); - return; + for (auto perm: revoke->permissions()->permission()) + { + auto single_perm = perm->single_permission(); + if (single_perm->EXECUTE() + || single_perm->EXEC() + || single_perm->SELECT() + || single_perm->INSERT() + || single_perm->UPDATE() + || single_perm->DELETE() + || single_perm->REFERENCES()) + { + return; + } + } } } } + PLtsql_stmt_execsql *stmt = (PLtsql_stmt_execsql *) getPLtsql_fragment(ctx); Assert(stmt); @@ -5719,61 +5768,190 @@ makeKillStatement(TSqlParser::Kill_statementContext *ctx) PLtsql_stmt * makeGrantdbStatement(TSqlParser::Security_statementContext *ctx) { - if (ctx->grant_statement() && ctx->grant_statement()->TO() && !ctx->grant_statement()->permission_object() - && ctx->grant_statement()->permissions()) + if (ctx->grant_statement()) { - for (auto perm : ctx->grant_statement()->permissions()->permission()) + auto grant = ctx->grant_statement(); + if (grant->TO() && !grant->permission_object() && grant->permissions()) { - auto single_perm = perm->single_permission(); - if (single_perm->CONNECT()) + for (auto perm : grant->permissions()->permission()) { - PLtsql_stmt_grantdb *result = (PLtsql_stmt_grantdb *) palloc0(sizeof(PLtsql_stmt_grantdb)); - result->cmd_type = PLTSQL_STMT_GRANTDB; - result->lineno = getLineNo(ctx->grant_statement()); + auto single_perm = perm->single_permission(); + if (single_perm->CONNECT()) + { + PLtsql_stmt_grantdb *result = (PLtsql_stmt_grantdb *) palloc0(sizeof(PLtsql_stmt_grantdb)); + result->cmd_type = PLTSQL_STMT_GRANTDB; + result->lineno = getLineNo(grant); + result->is_grant = true; + List *grantee_list = NIL; + for (auto prin : grant->principals()->principal_id()) + { + if (prin->id()) + { + std::string id_str = ::getFullText(prin->id()); + char *grantee_name = pstrdup(downcase_truncate_identifier(id_str.c_str(), id_str.length(), true)); + grantee_list = lappend(grantee_list, grantee_name); + } + if (prin->PUBLIC()) + { + char *grantee_name = pstrdup(PUBLIC_ROLE_NAME); + grantee_list = lappend(grantee_list, grantee_name); + } + } + result->grantees = grantee_list; + return (PLtsql_stmt *) result; + } + } + } + else if (grant->ON() && grant->permission_object() && grant->permission_object()->object_type() && grant->permission_object()->object_type()->SCHEMA()) + { + if (grant->TO() && grant->principals() && grant->permissions()) + { + PLtsql_stmt_grantschema *result = (PLtsql_stmt_grantschema *) palloc0(sizeof(PLtsql_stmt_grantschema)); + result->cmd_type = PLTSQL_STMT_GRANTSCHEMA; + result->lineno = getLineNo(grant); result->is_grant = true; + std::string schema_name; + if (grant->permission_object()->full_object_name()->object_name) + { + schema_name = stripQuoteFromId(grant->permission_object()->full_object_name()->object_name); + if (string_matches(schema_name.c_str(), "information_schema")) + schema_name = "information_schema_tsql"; + result->schema_name = pstrdup(downcase_truncate_identifier(schema_name.c_str(), schema_name.length(), true)); + } List *grantee_list = NIL; - for (auto prin : ctx->grant_statement()->principals()->principal_id()) + for (auto prin : grant->principals()->principal_id()) { if (prin->id()) { - std::string id_str = ::getFullText(prin->id()); + std::string id_str = stripQuoteFromId(prin->id()); char *grantee_name = pstrdup(downcase_truncate_identifier(id_str.c_str(), id_str.length(), true)); grantee_list = lappend(grantee_list, grantee_name); } + if (prin->PUBLIC()) + { + char *grantee_name = pstrdup(PUBLIC_ROLE_NAME); + grantee_list = lappend(grantee_list, grantee_name); + } + } + int privileges = 0; + for (auto perm: grant->permissions()->permission()) + { + auto single_perm = perm->single_permission(); + if (single_perm->EXECUTE()) + privileges |= ACL_EXECUTE; + if (single_perm->EXEC()) + privileges |= ACL_EXECUTE; + if (single_perm->SELECT()) + privileges |= ACL_SELECT; + if (single_perm->INSERT()) + privileges |= ACL_INSERT; + if (single_perm->UPDATE()) + privileges |= ACL_UPDATE; + if (single_perm->DELETE()) + privileges |= ACL_DELETE; + if (single_perm->REFERENCES()) + privileges |= ACL_REFERENCES; } + result->privileges = privileges; + if (grant->WITH()) + result->with_grant_option = true; result->grantees = grantee_list; return (PLtsql_stmt *) result; } } } - if (ctx->revoke_statement() && ctx->revoke_statement()->FROM() && !ctx->revoke_statement()->permission_object() - && ctx->revoke_statement()->permissions()) + + else if (ctx->revoke_statement()) { - for (auto perm : ctx->revoke_statement()->permissions()->permission()) + auto revoke = ctx->revoke_statement(); + if (revoke->FROM() && !revoke->permission_object() && revoke->permissions()) { - auto single_perm = perm->single_permission(); - if (single_perm->CONNECT()) + for (auto perm : revoke->permissions()->permission()) { - PLtsql_stmt_grantdb *result = (PLtsql_stmt_grantdb *) palloc0(sizeof(PLtsql_stmt_grantdb)); - result->cmd_type = PLTSQL_STMT_GRANTDB; - result->lineno = getLineNo(ctx->revoke_statement()); + auto single_perm = perm->single_permission(); + if (single_perm->CONNECT()) + { + PLtsql_stmt_grantdb *result = (PLtsql_stmt_grantdb *) palloc0(sizeof(PLtsql_stmt_grantdb)); + result->cmd_type = PLTSQL_STMT_GRANTDB; + result->lineno = getLineNo(revoke); + result->is_grant = false; + List *grantee_list = NIL; + + for (auto prin : revoke->principals()->principal_id()) + { + if (prin->id()) + { + std::string id_str = ::getFullText(prin->id()); + char *grantee_name = pstrdup(downcase_truncate_identifier(id_str.c_str(), id_str.length(), true)); + grantee_list = lappend(grantee_list, grantee_name); + } + if (prin->PUBLIC()) + { + char *grantee_name = pstrdup(PUBLIC_ROLE_NAME); + grantee_list = lappend(grantee_list, grantee_name); + } + } + result->grantees = grantee_list; + return (PLtsql_stmt *) result; + } + } + } + + else if (revoke->ON() && revoke->permission_object() && revoke->permission_object()->object_type() && revoke->permission_object()->object_type()->SCHEMA()) + { + if (revoke->FROM() && revoke->principals() && revoke->permissions()) + { + PLtsql_stmt_grantschema *result = (PLtsql_stmt_grantschema *) palloc0(sizeof(PLtsql_stmt_grantschema)); + result->cmd_type = PLTSQL_STMT_GRANTSCHEMA; + result->lineno = getLineNo(revoke); result->is_grant = false; + std::string schema_name; + if (revoke->permission_object()->full_object_name()->object_name) + { + schema_name = stripQuoteFromId(revoke->permission_object()->full_object_name()->object_name); + result->schema_name = pstrdup(downcase_truncate_identifier(schema_name.c_str(), schema_name.length(), true)); + } List *grantee_list = NIL; - - for (auto prin : ctx->revoke_statement()->principals()->principal_id()) + for (auto prin : revoke->principals()->principal_id()) { if (prin->id()) { - std::string id_str = ::getFullText(prin->id()); + std::string id_str = stripQuoteFromId(prin->id()); char *grantee_name = pstrdup(downcase_truncate_identifier(id_str.c_str(), id_str.length(), true)); grantee_list = lappend(grantee_list, grantee_name); } + if (prin->PUBLIC()) + { + char *grantee_name = pstrdup(PUBLIC_ROLE_NAME); + grantee_list = lappend(grantee_list, grantee_name); + } + } + int privileges = 0; + for (auto perm: revoke->permissions()->permission()) + { + auto single_perm = perm->single_permission(); + if (single_perm->EXECUTE()) + privileges |= ACL_EXECUTE; + if (single_perm->EXEC()) + privileges |= ACL_EXECUTE; + if (single_perm->SELECT()) + privileges |= ACL_SELECT; + if (single_perm->INSERT()) + privileges |= ACL_INSERT; + if (single_perm->UPDATE()) + privileges |= ACL_UPDATE; + if (single_perm->DELETE()) + privileges |= ACL_DELETE; + if (single_perm->REFERENCES()) + privileges |= ACL_REFERENCES; } + result->privileges = privileges; result->grantees = grantee_list; return (PLtsql_stmt *) result; } } } + PLtsql_stmt *result; result = makeExecSql(ctx); attachPLtsql_fragment(ctx, result); diff --git a/contrib/babelfishpg_tsql/src/tsqlNodes.h b/contrib/babelfishpg_tsql/src/tsqlNodes.h index e41e61ca87..65b3b27d76 100644 --- a/contrib/babelfishpg_tsql/src/tsqlNodes.h +++ b/contrib/babelfishpg_tsql/src/tsqlNodes.h @@ -52,6 +52,7 @@ typedef enum pltsql_stmt_type PLTSQL_STMT_CHANGE_DBOWNER, PLTSQL_STMT_DBCC, PLTSQL_STMT_FULLTEXTINDEX + PLTSQL_STMT_GRANTSCHEMA } PLtsql_stmt_type; typedef struct PLtsql_expr diff --git a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp index ffec553a30..650e85a3bc 100644 --- a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp @@ -1763,10 +1763,10 @@ void TsqlUnsupportedFeatureHandlerImpl::checkSupportedGrantStmt(TSqlParser::Gran continue; else { - unsupported_feature = "GRANT PERMISSION " + perm->getText(); + unsupported_feature = "GRANT PERMISSION " + ::getFullText(single_perm); + std::transform(unsupported_feature.begin(), unsupported_feature.end(), unsupported_feature.begin(), ::toupper); handle(INSTR_UNSUPPORTED_TSQL_REVOKE_STMT, unsupported_feature.c_str(), getLineAndPos(perm)); } - } } @@ -1774,9 +1774,12 @@ void TsqlUnsupportedFeatureHandlerImpl::checkSupportedGrantStmt(TSqlParser::Gran { auto perm_obj = grant->permission_object(); auto obj_type = perm_obj->object_type(); - if (obj_type && !obj_type->OBJECT()) + if (grant->ALL() && obj_type && obj_type->SCHEMA()) + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "The all permission has been deprecated and is not available for this class of entity.", getLineAndPos(grant)); + if (obj_type && !(obj_type->OBJECT() || obj_type->SCHEMA())) { unsupported_feature = "GRANT ON " + obj_type->getText(); + std::transform(unsupported_feature.begin(), unsupported_feature.end(), unsupported_feature.begin(), ::toupper); handle(INSTR_UNSUPPORTED_TSQL_REVOKE_STMT, unsupported_feature.c_str(), getLineAndPos(obj_type)); } } @@ -1856,10 +1859,10 @@ void TsqlUnsupportedFeatureHandlerImpl::checkSupportedRevokeStmt(TSqlParser::Rev continue; else { - unsupported_feature = "REVOKE PERMISSION " + perm->getText(); + unsupported_feature = "REVOKE PERMISSION " + ::getFullText(single_perm); + std::transform(unsupported_feature.begin(), unsupported_feature.end(), unsupported_feature.begin(), ::toupper); handle(INSTR_UNSUPPORTED_TSQL_REVOKE_STMT, unsupported_feature.c_str(), getLineAndPos(perm)); } - } } @@ -1867,9 +1870,12 @@ void TsqlUnsupportedFeatureHandlerImpl::checkSupportedRevokeStmt(TSqlParser::Rev { auto perm_obj = revoke->permission_object(); auto obj_type = perm_obj->object_type(); - if (obj_type && !obj_type->OBJECT()) + if (revoke->ALL() && obj_type && obj_type->SCHEMA()) + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "The all permission has been deprecated and is not available for this class of entity.", getLineAndPos(revoke)); + if (obj_type && !(obj_type->OBJECT() || obj_type->SCHEMA())) { unsupported_feature = "REVOKE ON " + obj_type->getText(); + std::transform(unsupported_feature.begin(), unsupported_feature.end(), unsupported_feature.begin(), ::toupper); handle(INSTR_UNSUPPORTED_TSQL_REVOKE_STMT, unsupported_feature.c_str(), getLineAndPos(obj_type)); } } diff --git a/test/JDBC/expected/AUTO_ANALYZE-vu-prepare.out b/test/JDBC/expected/AUTO_ANALYZE-vu-prepare.out index a555156370..d569a9922d 100644 --- a/test/JDBC/expected/AUTO_ANALYZE-vu-prepare.out +++ b/test/JDBC/expected/AUTO_ANALYZE-vu-prepare.out @@ -22,6 +22,7 @@ babelfish_extended_properties babelfish_function_ext babelfish_helpcollation babelfish_namespace_ext +babelfish_schema_permissions babelfish_server_options babelfish_sysdatabases babelfish_syslanguages diff --git a/test/JDBC/expected/BABEL-CROSS-DB.out b/test/JDBC/expected/BABEL-CROSS-DB.out index bf13b5f26f..2273c92e4f 100644 --- a/test/JDBC/expected/BABEL-CROSS-DB.out +++ b/test/JDBC/expected/BABEL-CROSS-DB.out @@ -522,6 +522,12 @@ DROP PROCEDURE p1 GO -- tsql +USE db1; +GO + +DROP TABLE db1_t1; +GO + USE master; GO diff --git a/test/JDBC/expected/BABEL-GRANT.out b/test/JDBC/expected/BABEL-GRANT.out index 7847a64156..2a59cf3dea 100644 --- a/test/JDBC/expected/BABEL-GRANT.out +++ b/test/JDBC/expected/BABEL-GRANT.out @@ -20,6 +20,10 @@ GO --- --- Prepare Objects --- +---- SCHEMA +CREATE SCHEMA scm; +GO + ---- TABLE CREATE TABLE t1 ( a int, b int); GO @@ -57,6 +61,18 @@ GO --- --- Basic Grant / Revoke --- +GRANT SELECT ON SCHEMA::scm TO guest; +GO + +GRANT SELECT ON SCHEMA::scm TO PUBLIC; +GO + +REVOKE SELECT ON SCHEMA::scm FROM PUBLIC; +GO + +GRANT INSERT ON SCHEMA::scm TO guest; +GO + GRANT ALL ON OBJECT::t1 TO guest WITH GRANT OPTION; GO @@ -155,7 +171,10 @@ GO ~~ERROR (Message: 'REVOKE ALL on Database' is not currently supported in Babelfish)~~ -GRANT SHOWPLAN ON OBJECT::t1 TO guest; -- unsupported permission +REVOKE SELECT ON SCHEMA::scm FROM guest; +GO + +GRANT showplan ON OBJECT::t1 TO guest; -- unsupported permission GO ~~ERROR (Code: 33557097)~~ @@ -169,18 +188,46 @@ GO ~~ERROR (Message: 'REVOKE PERMISSION SHOWPLAN' is not currently supported in Babelfish)~~ -GRANT ALL ON SCHEMA::scm TO guest; -- unsupported class +GRANT ALL ON SCHEMA::scm TO guest; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The all permission has been deprecated and is not available for this class of entity.)~~ + + +REVOKE ALL ON SCHEMA::scm TO guest; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: 'GRANT ON SCHEMA' is not currently supported in Babelfish)~~ +~~ERROR (Message: The all permission has been deprecated and is not available for this class of entity.)~~ -REVOKE ALL ON SCHEMA::scm TO guest; -- unsupported class +GRANT create table ON OBJECT::t1 TO guest; -- unsupported permission GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: 'REVOKE ON SCHEMA' is not currently supported in Babelfish)~~ +~~ERROR (Message: 'GRANT PERMISSION CREATE TABLE' is not currently supported in Babelfish)~~ + + +REVOKE create table ON OBJECT::t2 FROM alogin; -- unsupported permission +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'REVOKE PERMISSION CREATE TABLE' is not currently supported in Babelfish)~~ + + +GRANT SELECT ON table::t1 TO guest; -- unsupported object +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'GRANT ON TABLE' is not currently supported in Babelfish)~~ + + +REVOKE SELECT ON table::t1 FROM guest; -- unsupported object +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'REVOKE ON TABLE' is not currently supported in Babelfish)~~ GRANT ALL ON OBJECT::t1 TO guest WITH GRANT OPTION AS superuser; @@ -213,6 +260,9 @@ GO --- --- Clean Up --- +DROP SCHEMA scm; +GO + DROP VIEW IF EXISTS my_view; GO diff --git a/test/JDBC/expected/BABEL-SESSION.out b/test/JDBC/expected/BABEL-SESSION.out index 87d51024a5..6e9888edd5 100644 --- a/test/JDBC/expected/BABEL-SESSION.out +++ b/test/JDBC/expected/BABEL-SESSION.out @@ -153,6 +153,21 @@ USE master; GO -- tsql +USE db1; +GO + +DROP TABLE tb1; +GO + +DROP TABLE janedoe_schema.t1; +GO + +DROP SCHEMA janedoe_schema; +GO + +USE master; +go + DROP DATABASE db1; GO diff --git a/test/JDBC/expected/GRANT_SCHEMA-vu-cleanup.out b/test/JDBC/expected/GRANT_SCHEMA-vu-cleanup.out new file mode 100644 index 0000000000..af83d2ea36 --- /dev/null +++ b/test/JDBC/expected/GRANT_SCHEMA-vu-cleanup.out @@ -0,0 +1,75 @@ +-- tsql +-- Drop objects +use grant_schema_d1; +go + +drop table grant_schema_s1.grant_schema_t1; +go + +drop table grant_schema_s1.grant_schema_t2; +go + +drop table grant_schema_s1.grant_schema_t3; +go + +drop view grant_schema_s1.grant_schema_v1; +go + +drop view grant_schema_s1.grant_schema_v2; +go + +drop proc grant_schema_s1.grant_schema_p1; +go + +drop proc grant_schema_s1.grant_schema_p2; +go + +drop function grant_schema_s1.grant_schema_f1; +go + +drop function grant_schema_s1.grant_schema_f2; +go + +drop schema grant_schema_s1; +go + +drop table grant_schema_s2.grant_schema_t1; +go + +drop table grant_schema_s2.grant_schema_t2; +go + +drop schema grant_schema_s2; +go + +drop user grant_schema_u1; +go + +use master; +go + +drop database grant_schema_d1; +go + +-- psql +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'grant_schema_l1' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +go +~~START~~ +bool +~~END~~ + + +-- Wait to sync with another session +SELECT pg_sleep(1); +go +~~START~~ +void + +~~END~~ + + +-- tsql +drop login grant_schema_l1; +go diff --git a/test/JDBC/expected/GRANT_SCHEMA-vu-prepare.out b/test/JDBC/expected/GRANT_SCHEMA-vu-prepare.out new file mode 100644 index 0000000000..069a323b57 --- /dev/null +++ b/test/JDBC/expected/GRANT_SCHEMA-vu-prepare.out @@ -0,0 +1,74 @@ +-- tsql +-- create objects +create database grant_schema_d1; +go + +use grant_schema_d1; +go + +create login grant_schema_l1 with password = '12345678' +go + +create user grant_schema_u1 for login grant_schema_l1; +go + +create schema grant_schema_s1; +go + +create table grant_schema_s1.grant_schema_t1(a int); +go + +create table grant_schema_s1.grant_schema_t2(b int); +go + +create table grant_schema_s1.grant_schema_t3(c int); +go + +create view grant_schema_s1.grant_schema_v1 as select 2; +go + +create view grant_schema_s1.grant_schema_v2 as select 2; +go + +create proc grant_schema_s1.grant_schema_p1 as select 2; +go + +create proc grant_schema_s1.grant_schema_p2 as select 2; +go + +CREATE FUNCTION grant_schema_s1.grant_schema_f1() RETURNS INT AS BEGIN RETURN (SELECT COUNT(*) FROM sys.objects) END +go + +CREATE FUNCTION grant_schema_s1.grant_schema_f2() RETURNS INT AS BEGIN RETURN (SELECT COUNT(*) FROM sys.objects) END +go + +create schema grant_schema_s2; +go + +create table grant_schema_s2.grant_schema_t1(a int); +go + +create table grant_schema_s2.grant_schema_t2(a int); +go + +-- GRANT OBJECT privilege +grant select on grant_schema_s1.grant_schema_t1 to grant_schema_u1; +go +grant select on grant_schema_s1.grant_schema_t3 to grant_schema_u1; +go +grant select on grant_schema_s1.grant_schema_v1 to grant_schema_u1; +go +grant select on grant_schema_s1.grant_schema_v2 to grant_schema_u1; +go +grant execute on grant_schema_s1.grant_schema_p1 to grant_schema_u1; +go +grant execute on grant_schema_s1.grant_schema_p2 to grant_schema_u1; +go +grant execute on grant_schema_s1.grant_schema_f1 to grant_schema_u1; +go +grant execute on grant_schema_s1.grant_schema_f2 to grant_schema_u1; +go +grant select on grant_schema_s2.grant_schema_t1 to grant_schema_u1; +go +grant select on grant_schema_s2.grant_schema_t2 to grant_schema_u1; +go diff --git a/test/JDBC/expected/GRANT_SCHEMA-vu-verify.out b/test/JDBC/expected/GRANT_SCHEMA-vu-verify.out new file mode 100644 index 0000000000..16a45233e2 --- /dev/null +++ b/test/JDBC/expected/GRANT_SCHEMA-vu-verify.out @@ -0,0 +1,291 @@ +-- tsql user=grant_schema_l1 password=12345678 +-- User has OBJECT privileges, should be accessible. +use grant_schema_d1; +go + +select * from grant_schema_s1.grant_schema_t1; +go +~~START~~ +int +~~END~~ + + +select * from grant_schema_s1.grant_schema_t2; -- case 1: has no permission +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table grant_schema_t2)~~ + + +select * from grant_schema_s1.grant_schema_v1; +go +~~START~~ +int +2 +~~END~~ + + +exec grant_schema_s1.grant_schema_p1; +go +~~START~~ +int +2 +~~END~~ + + +select * from grant_schema_s1.grant_schema_f1(); +go +~~START~~ +int +10 +~~END~~ + + +-- tsql +-- REVOKE OBJECT privilege +use grant_schema_d1; +go +revoke select on grant_schema_s1.grant_schema_t1 from grant_schema_u1; +go +revoke select on grant_schema_s1.grant_schema_v1 from grant_schema_u1; +go +revoke execute on grant_schema_s1.grant_schema_p1 from grant_schema_u1; +go +revoke execute on grant_schema_s1.grant_schema_f1 from grant_schema_u1; +go + +-- tsql user=grant_schema_l1 password=12345678 +-- User has no privileges, should not be accessible. +use grant_schema_d1; +go + +select * from grant_schema_s1.grant_schema_t1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table grant_schema_t1)~~ + + +select * from grant_schema_s1.grant_schema_v1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for view grant_schema_v1)~~ + + +exec grant_schema_s1.grant_schema_p1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for procedure grant_schema_p1)~~ + + +select * from grant_schema_s1.grant_schema_f1(); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function grant_schema_f1)~~ + + +-- tsql +-- GRANT SCHEMA privilege +use grant_schema_d1; +go +grant select, execute on schema::grant_schema_s1 to grant_schema_u1; +go +use master; +go + +-- tsql user=grant_schema_l1 password=12345678 +-- User has SCHEMA privileges, should be accessible. +use grant_schema_d1; +go + +select * from grant_schema_s1.grant_schema_t1; +go +~~START~~ +int +~~END~~ + + +select * from grant_schema_s1.grant_schema_t2; +go +~~START~~ +int +~~END~~ + + +select * from grant_schema_s1.grant_schema_v1; +go +~~START~~ +int +2 +~~END~~ + + +exec grant_schema_s1.grant_schema_p1; +go +~~START~~ +int +2 +~~END~~ + + +select * from grant_schema_s1.grant_schema_f1(); +go +~~START~~ +int +11 +~~END~~ + + +-- User has OBJECT and SCHEMA privileges, should be accessible. +use grant_schema_d1; +go + +select * from grant_schema_s1.grant_schema_t3; +go +~~START~~ +int +~~END~~ + + +select * from grant_schema_s1.grant_schema_v2; +go +~~START~~ +int +2 +~~END~~ + + +exec grant_schema_s1.grant_schema_p2; +go +~~START~~ +int +2 +~~END~~ + + +select * from grant_schema_s1.grant_schema_f2(); +go +~~START~~ +int +11 +~~END~~ + + +-- tsql +-- Case 6: User has SCHEMA privilege, REVOKE OBJECT privilege +use grant_schema_d1; +go +revoke select on grant_schema_s1.grant_schema_t3 from grant_schema_u1; +go +revoke select on grant_schema_s1.grant_schema_v2 from grant_schema_u1; +go +revoke execute on grant_schema_s1.grant_schema_p2 from grant_schema_u1; +go +revoke execute on grant_schema_s1.grant_schema_f2 from grant_schema_u1; +go + +-- tsql user=grant_schema_l1 password=12345678 +-- User has SCHEMA privileges, should be accessible. +use grant_schema_d1; +go + +select * from grant_schema_s1.grant_schema_t3; +go +~~START~~ +int +~~END~~ + + +select * from grant_schema_s1.grant_schema_v2; +go +~~START~~ +int +2 +~~END~~ + + +exec grant_schema_s1.grant_schema_p2; +go +~~START~~ +int +2 +~~END~~ + + +select * from grant_schema_s1.grant_schema_f2(); +go +~~START~~ +int +11 +~~END~~ + + +-- tsql +-- User has OBJECT privilege, REVOKE OBJECT privilege +-- case 7: User has no privileges, should not be accessible. +use grant_schema_d1; +go +revoke select on grant_schema_s2.grant_schema_t2 from grant_schema_u1; +go +use master; +go + +-- tsql user=grant_schema_l1 password=12345678 +use grant_schema_d1; +go + +select * from grant_schema_s2.grant_schema_t2; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table grant_schema_t2)~~ + + +-- tsql +-- User has OBJECT privilege, REVOKE SCHEMA privilege +-- case 8: User has OBJECT privileges, would not be accessible. +use grant_schema_d1; +go +revoke select on schema::grant_schema_s2 from grant_schema_u1; +go +use master; +go + +-- tsql user=grant_schema_l1 password=12345678 +use grant_schema_d1; +go + +select * from grant_schema_s2.grant_schema_t1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table grant_schema_t1)~~ + + +-- tsql +-- User has OBJECT privilege, GRANT and REVOKE SCHEMA privilege +-- case 5: User has OBJECT privileges, would not be accessible. +use grant_schema_d1; +go +grant select on schema::grant_schema_s2 to grant_schema_u1; +go + +revoke select on schema::grant_schema_s2 from grant_schema_u1; +go +use master; +go + +-- tsql user=grant_schema_l1 password=12345678 +use grant_schema_d1; +go + +select * from grant_schema_s2.grant_schema_t1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table grant_schema_t1)~~ + + diff --git a/test/JDBC/expected/GRANT_SCHEMA.out b/test/JDBC/expected/GRANT_SCHEMA.out new file mode 100644 index 0000000000..c50bdec4ee --- /dev/null +++ b/test/JDBC/expected/GRANT_SCHEMA.out @@ -0,0 +1,1110 @@ +-- tsql +-- create objects +create database babel_4344_d1; +go + +use babel_4344_d1; +go + +create login babel_4344_l1 with password = '12345678' +go + +create user babel_4344_u1 for login babel_4344_l1; +go + +create login αιώνια with password = '12345678' +go + +create user αιώνια for login αιώνια; +go + +create login ログイン with password = '12345678' +go + +create user ログイン for login ログイン; +go + +create schema babel_4344_s1; +go + +create schema "BAbel_4344 S1"; +go + +create table "babel_4344 s1"."babel_4344 t1"(a int); +go + +create schema αγάπη; +go + +create schema スキーマ; +go + +create schema babel_4344_s2 authorization babel_4344_u1; +go + +create table babel_4344_t1(a int); +go + +create table babel_4344_s1.babel_4344_t1(a int); +go + +create table babel_4344_s2.babel_4344_t1(a int); +go + +create table αγάπη.abc(a int); +go + +create table スキーマ.abc(a int); +go + +create table babel_4344_t3(a int, b int); +go + +create table babel_4344_s1.babel_4344_t3(a int, b int); +go + +create schema "update pg_class set oid = 0 where relname = 'babel_4344_t1'"; +go + +create view babel_4344_v1 as select 1; +go + +create view babel_4344_s1.babel_4344_v1 as select 2; +go + +create proc babel_4344_p1 as select 1; +go + +create proc babel_4344_s1.babel_4344_p1 as select 2; +go + +create proc babel_4344_s1.babel_4344_p3 as select 3; +go + +CREATE FUNCTION babel_4344_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +CREATE FUNCTION babel_4344_s1.babel_4344_f1() returns int begin declare @a int; set @a = 1; return @a; END +go + +-- tests with greek character (one byte) and japanese character (muti bytes) +grant SELECT on schema::babel_4344_S1 to public, αιώνια, ログイン; +go + +grant select on schema::αγάπη to αιώνια, ログイン; +go + +grant select on schema::スキーマ to ログイン, αιώνια; +go + +-- test special database roles +grant SELECT on schema::babel_4344_S1 to db_owner; -- throws an error +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot grant, deny or revoke permissions to or from special roles.)~~ + + +grant SELECT on schema::babel_4344_S1 to sys; -- throws an error +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot grant, deny, or revoke permissions to sa, dbo, entity owner, information_schema, sys, or yourself.)~~ + + +grant SELECT on schema::babel_4344_S1 to information_schema; -- throws an error +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot grant, deny, or revoke permissions to sa, dbo, entity owner, information_schema, sys, or yourself.)~~ + + +grant SELECT on schema::babel_4344_S1 to dbo; -- throws an error +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot grant, deny, or revoke permissions to sa, dbo, entity owner, information_schema, sys, or yourself.)~~ + + +-- tsql user=ログイン password=12345678 +use babel_4344_d1; +go + +select * from αγάπη.abc; +go +~~START~~ +int +~~END~~ + + +select * from スキーマ.abc; +go +~~START~~ +int +~~END~~ + + +select * from babel_4344_S1.babel_4344_t1; +go +~~START~~ +int +~~END~~ + + +use master; +go + +-- tsql user=αιώνια password=12345678 +use babel_4344_d1; +go + +select * from αγάπη.abc; +go +~~START~~ +int +~~END~~ + + +select * from スキーマ.abc; +go +~~START~~ +int +~~END~~ + + +select * from babel_4344_S1.babel_4344_t1; +go +~~START~~ +int +~~END~~ + + +use master; +go + +-- tsql user=babel_4344_l1 password=12345678 +use babel_4344_d1; +go + +-- User has select privileges, tables and views be accessible +select * from babel_4344_s1.babel_4344_t1 +go +~~START~~ +int +~~END~~ + +select * from babel_4344_s1.babel_4344_v1; +go +~~START~~ +int +2 +~~END~~ + +use master; +go + +-- tsql +-- object names having more than 64 bytes +create schema abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz +go + +create table abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz(a int); +go + +grant select on schema::abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz to babel_4344_u1; +go + +revoke select on schema::abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz from babel_4344_u1; +go + +grant select on abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz to babel_4344_u1; +go + +revoke select on abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz from babel_4344_u1; +go + +drop table abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz +go + +drop schema abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz +go + +use babel_4344_d1; +go +revoke select on schema::babel_4344_s1 from public, αιώνια, ログイン; +go + +-- tsql user=babel_4344_l1 password=12345678 +use babel_4344_d1; +go + +-- User doesn't have any privileges, objects should not be accessible +select * from babel_4344_t1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t1)~~ + +select * from babel_4344_s1.babel_4344_t1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t1)~~ + +insert into babel_4344_s1.babel_4344_t1 values(1); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t1)~~ + +select * from babel_4344_v1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for view babel_4344_v1)~~ + +select * from babel_4344_s1.babel_4344_v1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for view babel_4344_v1)~~ + +exec babel_4344_p1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for procedure babel_4344_p1)~~ + +exec babel_4344_s1.babel_4344_p1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for procedure babel_4344_p1)~~ + +select * from babel_4344_f1(); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function babel_4344_f1)~~ + +select * from babel_4344_s1.babel_4344_f1(); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function babel_4344_f1)~~ + +use master; +go + +-- tsql +-- GRANT OBJECT privilege +use babel_4344_d1; +go +grant SELECT on schema::"bAbel_4344 s1" to BABEL_4344_U1; +go +grant SELECT on schema::"update pg_class set oid = 0 where relname = 'babel_4344_t1'" to BABEL_4344_U1; +go +grant SELECT on "babel_4344_t1" to BABEL_4344_U1; +go +grant SELECT on "babel_4344_s1".babel_4344_t1 to babel_4344_u1; +go +grant all on babel_4344_s1.babel_4344_t1 to "babel_4344_u1"; +go +grant select on babel_4344_t3(a) to babel_4344_u1; -- column privilege +go +grant select on babel_4344_s1.babel_4344_t3(a) to babel_4344_u1; -- column privilege +go +grant select on babel_4344_v1 to babel_4344_u1; +go +grant select on babel_4344_s1.babel_4344_v1 to babel_4344_u1; +go +grant execute on babel_4344_p1 to babel_4344_u1; +go +grant execute on babel_4344_s1.babel_4344_p1 to babel_4344_u1; +go +-- inside a transaction, permission will not be granted since it is rolled back +begin transaction; +exec sp_executesql N'grant execute on babel_4344_s1.babel_4344_p3 to babel_4344_u1;'; +rollback transaction; +go + +-- Mixed case +grant Execute on Babel_4344_F1 to Babel_4344_u1; +go +grant execute on BABEL_4344_s1.babel_4344_f1 to babEL_4344_u1; +go +-- Grant schema permission to its owner, should fail +grant select on schema::babel_4344_s2 to babel_4344_u1; -- should fail +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot grant, deny, or revoke permissions to sa, dbo, entity owner, information_schema, sys, or yourself.)~~ + +grant select on schema::babel_4344_s2 to jdbc_user; -- should fail +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the principal 'jdbc_user', because it does not exist or you do not have permission.)~~ + +grant SELECT on schema::"babel_4344_s2" to guest; -- should pass +go +grant select on schema::"" to guest; -- should fail +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as "" or [] are not allowed. Change the alias to a valid name.)~~ + +grant select on schema::non_existing_schema to guest; -- should fail +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: schema "non_existing_schema" does not exist)~~ + +-- grant statement via a procedure +create procedure grant_perm_proc as begin exec('grant select on schema::[] to guest') end; +go +exec grant_perm_proc; -- should fail, invalid GRANT statement +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as "" or [] are not allowed. Change the alias to a valid name.)~~ + +-- non-existing role +grant SELECT on schema::dbo to guest, babel_4344_u3; -- should fail +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the principal 'babel_4344_u3', because it does not exist or you do not have permission.)~~ + + +-- tsql user=babel_4344_l1 password=12345678 +-- User has OBJECT privileges, should be accessible. +use babel_4344_d1; +go +select * from babel_4344_t1; +go +~~START~~ +int +~~END~~ + +select * from babel_4344_s1.babel_4344_t1 +go +~~START~~ +int +~~END~~ + +insert into babel_4344_s1.babel_4344_t1 values(2); +go +~~ROW COUNT: 1~~ + +select * from babel_4344_t3; -- not accessible, only column privilege is granted +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t3)~~ + +select * from babel_4344_s1.babel_4344_t3 -- not accessible, only column privilege is granted +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t3)~~ + +select * from babel_4344_v1; +go +~~START~~ +int +1 +~~END~~ + +select * from babel_4344_s1.babel_4344_v1; +go +~~START~~ +int +2 +~~END~~ + +exec babel_4344_p1; +go +~~START~~ +int +1 +~~END~~ + +exec babel_4344_s1.babel_4344_p1; +go +~~START~~ +int +2 +~~END~~ + +exec babel_4344_s1.babel_4344_p3; -- should fail, grant statement was rolled back +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for procedure babel_4344_p3)~~ + +select * from BABEl_4344_f1(); +go +~~START~~ +int +1 +~~END~~ + +select * from babEL_4344_s1.babel_4344_f1(); +go +~~START~~ +int +1 +~~END~~ + +-- Grant schema permission to its owner +grant select on schema::babel_4344_s2 to babel_4344_u1; -- should fail +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot grant, deny, or revoke permissions to sa, dbo, entity owner, information_schema, sys, or yourself.)~~ + +grant select on schema::babel_4344_s2 to guest; -- should pass +go +grant select on schema::babel_4344_s1 to babel_4344_u1; -- should fail +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot grant, deny, or revoke permissions to sa, dbo, entity owner, information_schema, sys, or yourself.)~~ + +use master; +go + +-- tsql +-- GRANT SCHEMA privilege +use babel_4344_d1; +go +grant control on schema::babel_4344_s1 to babel_4344_u1; -- should fail, 'control' is not supported +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'GRANT PERMISSION CONTROL' is not currently supported in Babelfish)~~ + +grant select, insert, execute on schema::babel_4344_s1 to babel_4344_u1; +go +use master; +go + +-- psql +-- GRANT statement add an entry to the catalog +select schema_name, object_name, permission, grantee from sys.babelfish_schema_permissions +where schema_name = 'babel_4344_s1' collate "C" order by permission; -- and object_name = 'ALL' collate "C" +go +~~START~~ +"sys"."varchar"#!#"sys"."varchar"#!#int4#!#"sys"."varchar" +babel_4344_s1#!#babel_4344_v1#!#2#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#babel_4344_t1#!#47#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#babel_4344_p1#!#128#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#babel_4344_f1#!#128#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#ALL#!#131#!#babel_4344_d1_babel_4344_u1 +~~END~~ + + +-- tsql +-- GRANT SCHEMA privilege again +use babel_4344_d1; +go +grant select, insert, execute on schema::babel_4344_s1 to babel_4344_u1; +go +-- GRANT OBJECT privilege again +grant select on babel_4344_s1.babel_4344_v1 to babel_4344_u1; +go +use master; +go + +-- psql +-- check the consistency of catalog +select schema_name, object_name, permission, grantee from sys.babelfish_schema_permissions +where schema_name = 'babel_4344_s1' collate "C" order by permission; +go +~~START~~ +"sys"."varchar"#!#"sys"."varchar"#!#int4#!#"sys"."varchar" +babel_4344_s1#!#babel_4344_v1#!#2#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#babel_4344_t1#!#47#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#babel_4344_p1#!#128#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#babel_4344_f1#!#128#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#ALL#!#131#!#babel_4344_d1_babel_4344_u1 +~~END~~ + + +-- tsql user=babel_4344_l1 password=12345678 +-- User has OBJECT and SCHEMA privileges, should be accessible. +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t1 +go +~~START~~ +int +2 +~~END~~ + +insert into babel_4344_s1.babel_4344_t1 values(3); +go +~~ROW COUNT: 1~~ + +select * from babel_4344_s1.babel_4344_t3 +go +~~START~~ +int#!#int +~~END~~ + +select * from babel_4344_s1.babel_4344_v1; +go +~~START~~ +int +2 +~~END~~ + +exec babel_4344_s1.babel_4344_p1; +go +~~START~~ +int +2 +~~END~~ + +select * from babel_4344_s1.babel_4344_f1(); +go +~~START~~ +int +1 +~~END~~ + +use master; +go + +-- tsql +-- REVOKE SCHEMA privilege +use babel_4344_d1; +go +revoke select, insert, execute on schema::babel_4344_s1 from babel_4344_u1; +go +use master; +go + +-- tsql user=babel_4344_l1 password=12345678 +-- User has OBJECT privileges, should be accessible. +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t1 +go +~~START~~ +int +2 +3 +~~END~~ + +insert into babel_4344_s1.babel_4344_t1 values(3); +go +~~ROW COUNT: 1~~ + +select * from babel_4344_s1.babel_4344_t3 -- not accessible +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t3)~~ + +select * from babel_4344_s1.babel_4344_v1; +go +~~START~~ +int +2 +~~END~~ + +exec babel_4344_s1.babel_4344_p1; +go +~~START~~ +int +2 +~~END~~ + +select * from babel_4344_s1.babel_4344_f1(); +go +~~START~~ +int +1 +~~END~~ + +select * from babel_4344_s2.babel_4344_t1; +go +~~START~~ +int +~~END~~ + +use master; +go + +-- tsql +-- create new objects in same schema +use babel_4344_d1; +go +-- Grant the permissions again +grant select, insert, execute on schema::babel_4344_s1 to babel_4344_u1; +go +grant select, insert, execute on schema::information_schema to babel_4344_u1; +go +create table babel_4344_s1.babel_4344_t2(a int); +go +create view babel_4344_s1.babel_4344_v2 as select 2; +go +create proc babel_4344_s1.babel_4344_p2 as select 2; +go +CREATE FUNCTION babel_4344_s1.babel_4344_f2() RETURNS INT AS BEGIN RETURN (SELECT COUNT(*) FROM sys.objects) END +go +use master; +go + +-- tsql user=babel_4344_l1 password=12345678 +-- User has SCHEMA privileges,objects should be accessible. +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t2 +go +~~START~~ +int +~~END~~ + +insert into babel_4344_s1.babel_4344_t1 values(4); +go +~~ROW COUNT: 1~~ + +select * from babel_4344_s1.babel_4344_v2; +go +~~START~~ +int +2 +~~END~~ + +exec babel_4344_s1.babel_4344_p2; +go +~~START~~ +int +2 +~~END~~ + +select * from babel_4344_s1.babel_4344_f2(); +go +~~START~~ +int +16 +~~END~~ + +select * from "bAbel_4344 s1"."bAbel_4344 t1"; +go +~~START~~ +int +~~END~~ + +use master; +go + +-- tsql +-- REVOKE OBJECT privileges +use babel_4344_d1; +go + +REVOKE SELECT on schema::"bAbel_4344 s1" from "BABEL_4344_U1"; +go +REVOKE SELECT on schema::"update pg_class set oid = 0 where relname = 'babel_4344_t1'" from BABEL_4344_U1; +go +GRANT SELECT on babel_4344_t1 to BABEL_4344_U1; +go + +-- psql +-- should show original object names +select schema_name, object_name, permission, grantee from sys.babelfish_schema_permissions where schema_name = 'babel_4344_s1' collate sys.database_default order by object_name; +go +~~START~~ +"sys"."varchar"#!#"sys"."varchar"#!#int4#!#"sys"."varchar" +babel_4344_s1#!#ALL#!#131#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#babel_4344_f1#!#128#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#babel_4344_p1#!#128#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#babel_4344_t1#!#47#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#babel_4344_v1#!#2#!#babel_4344_d1_babel_4344_u1 +~~END~~ + + +-- tsql +-- rename the objects where permissions are already granted +sp_rename 'babel_4344_t1', 'babel_4344_t1_new', 'OBJECT'; +go +sp_rename 'babel_4344_s1.babel_4344_t1', 'babel_4344_t1_new', 'OBJECT'; +go +sp_rename 'babel_4344_s1.babel_4344_t3', 'babel_4344_t3_new', 'OBJECT'; +go +sp_rename 'babel_4344_s1.babel_4344_v1', 'babel_4344_v1_new', 'OBJECT'; +go +sp_rename 'babel_4344_s1.babel_4344_p1', 'babel_4344_p1_new', 'OBJECT'; +go +sp_rename 'babel_4344_s1.babel_4344_f1', 'babel_4344_f1_new', 'OBJECT'; +go + +-- psql +-- should show renamed objects +select schema_name, object_name, permission, grantee from sys.babelfish_schema_permissions where schema_name = 'babel_4344_s1' collate sys.database_default order by object_name; +go +~~START~~ +"sys"."varchar"#!#"sys"."varchar"#!#int4#!#"sys"."varchar" +babel_4344_s1#!#ALL#!#131#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#babel_4344_f1_new#!#128#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#babel_4344_p1_new#!#128#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#babel_4344_t1_new#!#47#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#babel_4344_v1_new#!#2#!#babel_4344_d1_babel_4344_u1 +~~END~~ + + +-- tsql +-- permissions are transferred to the new objects +-- Revoke permissions from the new objects +REVOKE all on babel_4344_s1.babel_4344_t1_new FROM babel_4344_u1; +go +REVOKE select on babel_4344_s1.babel_4344_t3_new(a) FROM babel_4344_u1; +go +REVOKE select on babel_4344_s1.babel_4344_v1_new FROM babel_4344_u1; +go +REVOKE execute on babel_4344_s1.babel_4344_p1_new FROM babel_4344_u1; +go +REVOKE execute on babel_4344_s1.babel_4344_f1_new FROM babel_4344_u1; +go +REVOKE all on babel_4344_s1.babel_4344_f1_new FROM babel_4344_u1; +go + +-- tsql user=babel_4344_l1 password=12345678 +-- User has SCHEMA privileges, should be accessible. +use babel_4344_d1; +go +select * from babel_4344_t1_new; +go +~~START~~ +int +~~END~~ + +select * from babel_4344_s1.babel_4344_t1_new +go +~~START~~ +int +2 +3 +3 +4 +~~END~~ + +insert into babel_4344_s1.babel_4344_t1_new values(5); +go +~~ROW COUNT: 1~~ + +select * from babel_4344_s1.babel_4344_t3_new; +go +~~START~~ +int#!#int +~~END~~ + +select * from babel_4344_s1.babel_4344_v1_new; +go +~~START~~ +int +2 +~~END~~ + +exec babel_4344_s1.babel_4344_p1_new; +go +~~START~~ +int +2 +~~END~~ + +select * from babel_4344_s1.babel_4344_f1_new(); +go +~~START~~ +int +1 +~~END~~ + +select * from babel_4344_s2.babel_4344_t1; +go +~~START~~ +int +~~END~~ + +use master; +go + +-- tsql +-- REVOKE SCHEMA privileges +use babel_4344_d1; +go +revoke select, insert, execute on schema::babel_4344_s1 from babel_4344_u1; +go +use master; +go + +-- psql +-- REVOKE on schema removes the entry from the catalog +select * from sys.babelfish_schema_permissions where schema_name = 'babel_4344_s1' collate sys.database_default; +go +~~START~~ +int2#!#"sys"."varchar"#!#"sys"."varchar"#!#int4#!#"sys"."varchar"#!#bpchar +~~END~~ + + +-- tsql user=babel_4344_l1 password=12345678 +-- User has no privileges, shouldn't be accessible. +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t1_new; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t1_new)~~ + +insert into babel_4344_s1.babel_4344_t1_new values(5); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t1_new)~~ + +select * from babel_4344_s1.babel_4344_t3_new; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t3_new)~~ + +select * from babel_4344_s1.babel_4344_v1_new; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for view babel_4344_v1_new)~~ + +exec babel_4344_s1.babel_4344_p1_new; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for procedure babel_4344_p1_new)~~ + +select * from babel_4344_s1.babel_4344_f1_new(); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function babel_4344_f1_new)~~ + +use master; +go + +-- psql +-- grant object permission +grant select on babel_4344_s1.babel_4344_t1_new to babel_4344_d1_babel_4344_u1; +go + +-- tsql +-- grant schema permission +use babel_4344_d1; +go +grant select on schema::babel_4344_s1 to babel_4344_u1; +go +use master +go + +-- tsql user=babel_4344_l1 password=12345678 +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t1_new; -- accessible +go +~~START~~ +int +2 +3 +3 +4 +5 +~~END~~ + +use master +go + +-- psql +-- revoke schema permission +revoke select on all tables in schema babel_4344_s1 from babel_4344_d1_babel_4344_u1; +go + +-- tsql user=babel_4344_l1 password=12345678 +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t1_new; -- not accessible +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t1_new)~~ + +use master +go + +-- tsql +-- Drop objects +use babel_4344_d1; +go + +drop schema "update pg_class set oid = 0 where relname = 'babel_4344_t1'"; +go + +drop table babel_4344_t1_new; +go + +drop table babel_4344_s1.babel_4344_t1_new; +go + +drop table babel_4344_t3; +go + +drop table babel_4344_s1.babel_4344_t3_new; +go + +drop table babel_4344_s1.babel_4344_t2; +go + +drop view babel_4344_v1; +go + +drop view babel_4344_s1.babel_4344_v1_new; +go + +drop view babel_4344_s1.babel_4344_v2; +go + +drop proc babel_4344_p1; +go + +drop proc babel_4344_s1.babel_4344_p1_new; +go + +drop proc babel_4344_s1.babel_4344_p2; +go + +drop proc babel_4344_s1.babel_4344_p3; +go + +drop function babel_4344_f1; +go + +drop function babel_4344_s1.babel_4344_f1_new; +go + +drop function babel_4344_s1.babel_4344_f2; +go + +drop schema babel_4344_s1; +go + +drop table babel_4344_s2.babel_4344_t1; +go + +drop schema babel_4344_s2; +go + +drop table αγάπη.abc; +go + +drop schema αγάπη; +go + +drop table スキーマ.abc; +go + +drop schema スキーマ; +go + +drop table "babel_4344 s1"."babel_4344 t1"; +go + +drop schema "BAbel_4344 s1"; +go + +drop user babel_4344_u1; +go + +drop user αιώνια; +go + +drop user ログイン; +go + +use master; +go + +drop database babel_4344_d1; +go + +-- psql +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'babel_4344_l1' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +go +~~START~~ +bool +t +~~END~~ + + +-- Wait to sync with another session +SELECT pg_sleep(1); +go +~~START~~ +void + +~~END~~ + + +-- tsql +drop login babel_4344_l1; +go + +-- psql +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'αιώνια' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +go +~~START~~ +bool +t +~~END~~ + + +-- Wait to sync with another session +SELECT pg_sleep(1); +go +~~START~~ +void + +~~END~~ + + +-- tsql +drop login αιώνια; +go + +-- psql +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'ログイン' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +go +~~START~~ +bool +t +~~END~~ + + +-- Wait to sync with another session +SELECT pg_sleep(1); +go +~~START~~ +void + +~~END~~ + + +-- tsql +drop login ログイン; +go diff --git a/test/JDBC/input/BABEL-CROSS-DB.mix b/test/JDBC/input/BABEL-CROSS-DB.mix index 594fcd1b0e..630af3bad3 100644 --- a/test/JDBC/input/BABEL-CROSS-DB.mix +++ b/test/JDBC/input/BABEL-CROSS-DB.mix @@ -338,6 +338,12 @@ DROP PROCEDURE p1 GO -- tsql +USE db1; +GO + +DROP TABLE db1_t1; +GO + USE master; GO diff --git a/test/JDBC/input/BABEL-GRANT.sql b/test/JDBC/input/BABEL-GRANT.sql index c175c33857..8388f782ff 100644 --- a/test/JDBC/input/BABEL-GRANT.sql +++ b/test/JDBC/input/BABEL-GRANT.sql @@ -20,6 +20,10 @@ GO --- Prepare Objects --- +---- SCHEMA +CREATE SCHEMA scm; +GO + ---- TABLE CREATE TABLE t1 ( a int, b int); GO @@ -55,6 +59,18 @@ GO --- Basic Grant / Revoke --- +GRANT SELECT ON SCHEMA::scm TO guest; +GO + +GRANT SELECT ON SCHEMA::scm TO PUBLIC; +GO + +REVOKE SELECT ON SCHEMA::scm FROM PUBLIC; +GO + +GRANT INSERT ON SCHEMA::scm TO guest; +GO + GRANT ALL ON OBJECT::t1 TO guest WITH GRANT OPTION; GO @@ -145,16 +161,31 @@ GO REVOKE ALL TO alogin; -- database permission GO -GRANT SHOWPLAN ON OBJECT::t1 TO guest; -- unsupported permission +REVOKE SELECT ON SCHEMA::scm FROM guest; +GO + +GRANT showplan ON OBJECT::t1 TO guest; -- unsupported permission GO REVOKE SHOWPLAN ON OBJECT::t2 TO alogin; -- unsupported permission GO -GRANT ALL ON SCHEMA::scm TO guest; -- unsupported class +GRANT ALL ON SCHEMA::scm TO guest; +GO + +REVOKE ALL ON SCHEMA::scm TO guest; GO -REVOKE ALL ON SCHEMA::scm TO guest; -- unsupported class +GRANT create table ON OBJECT::t1 TO guest; -- unsupported permission +GO + +REVOKE create table ON OBJECT::t2 FROM alogin; -- unsupported permission +GO + +GRANT SELECT ON table::t1 TO guest; -- unsupported object +GO + +REVOKE SELECT ON table::t1 FROM guest; -- unsupported object GO GRANT ALL ON OBJECT::t1 TO guest WITH GRANT OPTION AS superuser; @@ -179,6 +210,9 @@ GO --- Clean Up --- +DROP SCHEMA scm; +GO + DROP VIEW IF EXISTS my_view; GO diff --git a/test/JDBC/input/BABEL-SESSION.mix b/test/JDBC/input/BABEL-SESSION.mix index 41c1c85398..d9f7be4a8c 100644 --- a/test/JDBC/input/BABEL-SESSION.mix +++ b/test/JDBC/input/BABEL-SESSION.mix @@ -99,6 +99,21 @@ USE master; GO -- tsql +USE db1; +GO + +DROP TABLE tb1; +GO + +DROP TABLE janedoe_schema.t1; +GO + +DROP SCHEMA janedoe_schema; +GO + +USE master; +go + DROP DATABASE db1; GO diff --git a/test/JDBC/input/GRANT_SCHEMA-vu-cleanup.mix b/test/JDBC/input/GRANT_SCHEMA-vu-cleanup.mix new file mode 100644 index 0000000000..156b92c61e --- /dev/null +++ b/test/JDBC/input/GRANT_SCHEMA-vu-cleanup.mix @@ -0,0 +1,66 @@ +-- tsql +-- Drop objects +use grant_schema_d1; +go + +drop table grant_schema_s1.grant_schema_t1; +go + +drop table grant_schema_s1.grant_schema_t2; +go + +drop table grant_schema_s1.grant_schema_t3; +go + +drop view grant_schema_s1.grant_schema_v1; +go + +drop view grant_schema_s1.grant_schema_v2; +go + +drop proc grant_schema_s1.grant_schema_p1; +go + +drop proc grant_schema_s1.grant_schema_p2; +go + +drop function grant_schema_s1.grant_schema_f1; +go + +drop function grant_schema_s1.grant_schema_f2; +go + +drop schema grant_schema_s1; +go + +drop table grant_schema_s2.grant_schema_t1; +go + +drop table grant_schema_s2.grant_schema_t2; +go + +drop schema grant_schema_s2; +go + +drop user grant_schema_u1; +go + +use master; +go + +drop database grant_schema_d1; +go + +-- psql +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'grant_schema_l1' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +go + +-- Wait to sync with another session +SELECT pg_sleep(1); +go + +-- tsql +drop login grant_schema_l1; +go \ No newline at end of file diff --git a/test/JDBC/input/GRANT_SCHEMA-vu-prepare.mix b/test/JDBC/input/GRANT_SCHEMA-vu-prepare.mix new file mode 100644 index 0000000000..306cd64d58 --- /dev/null +++ b/test/JDBC/input/GRANT_SCHEMA-vu-prepare.mix @@ -0,0 +1,74 @@ +-- tsql +-- create objects +create database grant_schema_d1; +go + +use grant_schema_d1; +go + +create login grant_schema_l1 with password = '12345678' +go + +create user grant_schema_u1 for login grant_schema_l1; +go + +create schema grant_schema_s1; +go + +create table grant_schema_s1.grant_schema_t1(a int); +go + +create table grant_schema_s1.grant_schema_t2(b int); +go + +create table grant_schema_s1.grant_schema_t3(c int); +go + +create view grant_schema_s1.grant_schema_v1 as select 2; +go + +create view grant_schema_s1.grant_schema_v2 as select 2; +go + +create proc grant_schema_s1.grant_schema_p1 as select 2; +go + +create proc grant_schema_s1.grant_schema_p2 as select 2; +go + +CREATE FUNCTION grant_schema_s1.grant_schema_f1() RETURNS INT AS BEGIN RETURN (SELECT COUNT(*) FROM sys.objects) END +go + +CREATE FUNCTION grant_schema_s1.grant_schema_f2() RETURNS INT AS BEGIN RETURN (SELECT COUNT(*) FROM sys.objects) END +go + +create schema grant_schema_s2; +go + +create table grant_schema_s2.grant_schema_t1(a int); +go + +create table grant_schema_s2.grant_schema_t2(a int); +go + +-- GRANT OBJECT privilege +grant select on grant_schema_s1.grant_schema_t1 to grant_schema_u1; +go +grant select on grant_schema_s1.grant_schema_t3 to grant_schema_u1; +go +grant select on grant_schema_s1.grant_schema_v1 to grant_schema_u1; +go +grant select on grant_schema_s1.grant_schema_v2 to grant_schema_u1; +go +grant execute on grant_schema_s1.grant_schema_p1 to grant_schema_u1; +go +grant execute on grant_schema_s1.grant_schema_p2 to grant_schema_u1; +go +grant execute on grant_schema_s1.grant_schema_f1 to grant_schema_u1; +go +grant execute on grant_schema_s1.grant_schema_f2 to grant_schema_u1; +go +grant select on grant_schema_s2.grant_schema_t1 to grant_schema_u1; +go +grant select on grant_schema_s2.grant_schema_t2 to grant_schema_u1; +go \ No newline at end of file diff --git a/test/JDBC/input/GRANT_SCHEMA-vu-verify.mix b/test/JDBC/input/GRANT_SCHEMA-vu-verify.mix new file mode 100644 index 0000000000..09e9a23336 --- /dev/null +++ b/test/JDBC/input/GRANT_SCHEMA-vu-verify.mix @@ -0,0 +1,179 @@ +-- tsql user=grant_schema_l1 password=12345678 +-- User has OBJECT privileges, should be accessible. +use grant_schema_d1; +go + +select * from grant_schema_s1.grant_schema_t1; +go + +select * from grant_schema_s1.grant_schema_t2; -- case 1: has no permission +go + +select * from grant_schema_s1.grant_schema_v1; +go + +exec grant_schema_s1.grant_schema_p1; +go + +select * from grant_schema_s1.grant_schema_f1(); +go + +-- tsql +-- REVOKE OBJECT privilege +use grant_schema_d1; +go +revoke select on grant_schema_s1.grant_schema_t1 from grant_schema_u1; +go +revoke select on grant_schema_s1.grant_schema_v1 from grant_schema_u1; +go +revoke execute on grant_schema_s1.grant_schema_p1 from grant_schema_u1; +go +revoke execute on grant_schema_s1.grant_schema_f1 from grant_schema_u1; +go + +-- tsql user=grant_schema_l1 password=12345678 +-- User has no privileges, should not be accessible. +use grant_schema_d1; +go + +select * from grant_schema_s1.grant_schema_t1; +go + +select * from grant_schema_s1.grant_schema_v1; +go + +exec grant_schema_s1.grant_schema_p1; +go + +select * from grant_schema_s1.grant_schema_f1(); +go + +-- tsql +-- GRANT SCHEMA privilege +use grant_schema_d1; +go +grant select, execute on schema::grant_schema_s1 to grant_schema_u1; +go +use master; +go + +-- tsql user=grant_schema_l1 password=12345678 +-- User has SCHEMA privileges, should be accessible. +use grant_schema_d1; +go + +select * from grant_schema_s1.grant_schema_t1; +go + +select * from grant_schema_s1.grant_schema_t2; +go + +select * from grant_schema_s1.grant_schema_v1; +go + +exec grant_schema_s1.grant_schema_p1; +go + +select * from grant_schema_s1.grant_schema_f1(); +go + +-- User has OBJECT and SCHEMA privileges, should be accessible. +use grant_schema_d1; +go + +select * from grant_schema_s1.grant_schema_t3; +go + +select * from grant_schema_s1.grant_schema_v2; +go + +exec grant_schema_s1.grant_schema_p2; +go + +select * from grant_schema_s1.grant_schema_f2(); +go + +-- tsql +-- Case 6: User has SCHEMA privilege, REVOKE OBJECT privilege +use grant_schema_d1; +go +revoke select on grant_schema_s1.grant_schema_t3 from grant_schema_u1; +go +revoke select on grant_schema_s1.grant_schema_v2 from grant_schema_u1; +go +revoke execute on grant_schema_s1.grant_schema_p2 from grant_schema_u1; +go +revoke execute on grant_schema_s1.grant_schema_f2 from grant_schema_u1; +go + +-- tsql user=grant_schema_l1 password=12345678 +-- User has SCHEMA privileges, should be accessible. +use grant_schema_d1; +go + +select * from grant_schema_s1.grant_schema_t3; +go + +select * from grant_schema_s1.grant_schema_v2; +go + +exec grant_schema_s1.grant_schema_p2; +go + +select * from grant_schema_s1.grant_schema_f2(); +go + +-- tsql +-- User has OBJECT privilege, REVOKE OBJECT privilege +-- case 7: User has no privileges, should not be accessible. +use grant_schema_d1; +go +revoke select on grant_schema_s2.grant_schema_t2 from grant_schema_u1; +go +use master; +go + +-- tsql user=grant_schema_l1 password=12345678 +use grant_schema_d1; +go + +select * from grant_schema_s2.grant_schema_t2; +go + +-- tsql +-- User has OBJECT privilege, REVOKE SCHEMA privilege +-- case 8: User has OBJECT privileges, would not be accessible. +use grant_schema_d1; +go +revoke select on schema::grant_schema_s2 from grant_schema_u1; +go +use master; +go + +-- tsql user=grant_schema_l1 password=12345678 +use grant_schema_d1; +go + +select * from grant_schema_s2.grant_schema_t1; +go + +-- tsql +-- User has OBJECT privilege, GRANT and REVOKE SCHEMA privilege +-- case 5: User has OBJECT privileges, would not be accessible. +use grant_schema_d1; +go +grant select on schema::grant_schema_s2 to grant_schema_u1; +go + +revoke select on schema::grant_schema_s2 from grant_schema_u1; +go +use master; +go + +-- tsql user=grant_schema_l1 password=12345678 +use grant_schema_d1; +go + +select * from grant_schema_s2.grant_schema_t1; +go + diff --git a/test/JDBC/input/GRANT_SCHEMA.mix b/test/JDBC/input/GRANT_SCHEMA.mix new file mode 100644 index 0000000000..f4ecef648a --- /dev/null +++ b/test/JDBC/input/GRANT_SCHEMA.mix @@ -0,0 +1,711 @@ +-- tsql +-- create objects +create database babel_4344_d1; +go + +use babel_4344_d1; +go + +create login babel_4344_l1 with password = '12345678' +go + +create user babel_4344_u1 for login babel_4344_l1; +go + +create login αιώνια with password = '12345678' +go + +create user αιώνια for login αιώνια; +go + +create login ログイン with password = '12345678' +go + +create user ログイン for login ログイン; +go + +create schema babel_4344_s1; +go + +create schema "BAbel_4344 S1"; +go + +create table "babel_4344 s1"."babel_4344 t1"(a int); +go + +create schema αγάπη; +go + +create schema スキーマ; +go + +create schema babel_4344_s2 authorization babel_4344_u1; +go + +create table babel_4344_t1(a int); +go + +create table babel_4344_s1.babel_4344_t1(a int); +go + +create table babel_4344_s2.babel_4344_t1(a int); +go + +create table αγάπη.abc(a int); +go + +create table スキーマ.abc(a int); +go + +create table babel_4344_t3(a int, b int); +go + +create table babel_4344_s1.babel_4344_t3(a int, b int); +go + +create schema "update pg_class set oid = 0 where relname = 'babel_4344_t1'"; +go + +create view babel_4344_v1 as select 1; +go + +create view babel_4344_s1.babel_4344_v1 as select 2; +go + +create proc babel_4344_p1 as select 1; +go + +create proc babel_4344_s1.babel_4344_p1 as select 2; +go + +create proc babel_4344_s1.babel_4344_p3 as select 3; +go + +CREATE FUNCTION babel_4344_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +CREATE FUNCTION babel_4344_s1.babel_4344_f1() returns int begin declare @a int; set @a = 1; return @a; END +go + +-- tests with greek character (one byte) and japanese character (muti bytes) +grant SELECT on schema::babel_4344_S1 to public, αιώνια, ログイン; +go + +grant select on schema::αγάπη to αιώνια, ログイン; +go + +grant select on schema::スキーマ to ログイン, αιώνια; +go + +-- test special database roles +grant SELECT on schema::babel_4344_S1 to db_owner; -- throws an error +go + +grant SELECT on schema::babel_4344_S1 to sys; -- throws an error +go + +grant SELECT on schema::babel_4344_S1 to information_schema; -- throws an error +go + +grant SELECT on schema::babel_4344_S1 to dbo; -- throws an error +go + +-- tsql user=ログイン password=12345678 +use babel_4344_d1; +go + +select * from αγάπη.abc; +go + +select * from スキーマ.abc; +go + +select * from babel_4344_S1.babel_4344_t1; +go + +use master; +go + +-- tsql user=αιώνια password=12345678 +use babel_4344_d1; +go + +select * from αγάπη.abc; +go + +select * from スキーマ.abc; +go + +select * from babel_4344_S1.babel_4344_t1; +go + +use master; +go + +-- tsql user=babel_4344_l1 password=12345678 +use babel_4344_d1; +go + +-- User has select privileges, tables and views be accessible +select * from babel_4344_s1.babel_4344_t1 +go +select * from babel_4344_s1.babel_4344_v1; +go +use master; +go + +-- tsql +-- object names having more than 64 bytes +create schema abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz +go + +create table abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz(a int); +go + +grant select on schema::abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz to babel_4344_u1; +go + +revoke select on schema::abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz from babel_4344_u1; +go + +grant select on abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz to babel_4344_u1; +go + +revoke select on abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz from babel_4344_u1; +go + +drop table abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz +go + +drop schema abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz +go + +use babel_4344_d1; +go +revoke select on schema::babel_4344_s1 from public, αιώνια, ログイン; +go + +-- tsql user=babel_4344_l1 password=12345678 +use babel_4344_d1; +go + +-- User doesn't have any privileges, objects should not be accessible +select * from babel_4344_t1; +go +select * from babel_4344_s1.babel_4344_t1 +go +insert into babel_4344_s1.babel_4344_t1 values(1); +go +select * from babel_4344_v1; +go +select * from babel_4344_s1.babel_4344_v1; +go +exec babel_4344_p1; +go +exec babel_4344_s1.babel_4344_p1; +go +select * from babel_4344_f1(); +go +select * from babel_4344_s1.babel_4344_f1(); +go +use master; +go + +-- tsql +-- GRANT OBJECT privilege +use babel_4344_d1; +go +grant SELECT on schema::"bAbel_4344 s1" to BABEL_4344_U1; +go +grant SELECT on schema::"update pg_class set oid = 0 where relname = 'babel_4344_t1'" to BABEL_4344_U1; +go +grant SELECT on "babel_4344_t1" to BABEL_4344_U1; +go +grant SELECT on "babel_4344_s1".babel_4344_t1 to babel_4344_u1; +go +grant all on babel_4344_s1.babel_4344_t1 to "babel_4344_u1"; +go +grant select on babel_4344_t3(a) to babel_4344_u1; -- column privilege +go +grant select on babel_4344_s1.babel_4344_t3(a) to babel_4344_u1; -- column privilege +go +grant select on babel_4344_v1 to babel_4344_u1; +go +grant select on babel_4344_s1.babel_4344_v1 to babel_4344_u1; +go +grant execute on babel_4344_p1 to babel_4344_u1; +go +grant execute on babel_4344_s1.babel_4344_p1 to babel_4344_u1; +go +-- inside a transaction, permission will not be granted since it is rolled back +begin transaction; +exec sp_executesql N'grant execute on babel_4344_s1.babel_4344_p3 to babel_4344_u1;'; +rollback transaction; +go + +-- Mixed case +grant Execute on Babel_4344_F1 to Babel_4344_u1; +go +grant execute on BABEL_4344_s1.babel_4344_f1 to babEL_4344_u1; +go +-- Grant schema permission to its owner, should fail +grant select on schema::babel_4344_s2 to babel_4344_u1; -- should fail +go +grant select on schema::babel_4344_s2 to jdbc_user; -- should fail +go +grant SELECT on schema::"babel_4344_s2" to guest; -- should pass +go +grant select on schema::"" to guest; -- should fail +go +grant select on schema::non_existing_schema to guest; -- should fail +go +-- grant statement via a procedure +create procedure grant_perm_proc as begin exec('grant select on schema::[] to guest') end; +go +exec grant_perm_proc; -- should fail, invalid GRANT statement +go +-- non-existing role +grant SELECT on schema::dbo to guest, babel_4344_u3; -- should fail +go + +-- tsql user=babel_4344_l1 password=12345678 +-- User has OBJECT privileges, should be accessible. +use babel_4344_d1; +go +select * from babel_4344_t1; +go +select * from babel_4344_s1.babel_4344_t1 +go +insert into babel_4344_s1.babel_4344_t1 values(2); +go +select * from babel_4344_t3; -- not accessible, only column privilege is granted +go +select * from babel_4344_s1.babel_4344_t3 -- not accessible, only column privilege is granted +go +select * from babel_4344_v1; +go +select * from babel_4344_s1.babel_4344_v1; +go +exec babel_4344_p1; +go +exec babel_4344_s1.babel_4344_p1; +go +exec babel_4344_s1.babel_4344_p3; -- should fail, grant statement was rolled back +go +select * from BABEl_4344_f1(); +go +select * from babEL_4344_s1.babel_4344_f1(); +go +-- Grant schema permission to its owner +grant select on schema::babel_4344_s2 to babel_4344_u1; -- should fail +go +grant select on schema::babel_4344_s2 to guest; -- should pass +go +grant select on schema::babel_4344_s1 to babel_4344_u1; -- should fail +go +use master; +go + +-- tsql +-- GRANT SCHEMA privilege +use babel_4344_d1; +go +grant control on schema::babel_4344_s1 to babel_4344_u1; -- should fail, 'control' is not supported +go +grant select, insert, execute on schema::babel_4344_s1 to babel_4344_u1; +go +use master; +go + +-- psql +-- GRANT statement add an entry to the catalog +select schema_name, object_name, permission, grantee from sys.babelfish_schema_permissions +where schema_name = 'babel_4344_s1' collate "C" order by permission; -- and object_name = 'ALL' collate "C" +go + +-- tsql +-- GRANT SCHEMA privilege again +use babel_4344_d1; +go +grant select, insert, execute on schema::babel_4344_s1 to babel_4344_u1; +go +-- GRANT OBJECT privilege again +grant select on babel_4344_s1.babel_4344_v1 to babel_4344_u1; +go +use master; +go + +-- psql +-- check the consistency of catalog +select schema_name, object_name, permission, grantee from sys.babelfish_schema_permissions +where schema_name = 'babel_4344_s1' collate "C" order by permission; +go + +-- tsql user=babel_4344_l1 password=12345678 +-- User has OBJECT and SCHEMA privileges, should be accessible. +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t1 +go +insert into babel_4344_s1.babel_4344_t1 values(3); +go +select * from babel_4344_s1.babel_4344_t3 +go +select * from babel_4344_s1.babel_4344_v1; +go +exec babel_4344_s1.babel_4344_p1; +go +select * from babel_4344_s1.babel_4344_f1(); +go +use master; +go + +-- tsql +-- REVOKE SCHEMA privilege +use babel_4344_d1; +go +revoke select, insert, execute on schema::babel_4344_s1 from babel_4344_u1; +go +use master; +go + +-- tsql user=babel_4344_l1 password=12345678 +-- User has OBJECT privileges, should be accessible. +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t1 +go +insert into babel_4344_s1.babel_4344_t1 values(3); +go +select * from babel_4344_s1.babel_4344_t3 -- not accessible +go +select * from babel_4344_s1.babel_4344_v1; +go +exec babel_4344_s1.babel_4344_p1; +go +select * from babel_4344_s1.babel_4344_f1(); +go +select * from babel_4344_s2.babel_4344_t1; +go +use master; +go + +-- tsql +-- create new objects in same schema +use babel_4344_d1; +go +-- Grant the permissions again +grant select, insert, execute on schema::babel_4344_s1 to babel_4344_u1; +go +grant select, insert, execute on schema::information_schema to babel_4344_u1; +go +create table babel_4344_s1.babel_4344_t2(a int); +go +create view babel_4344_s1.babel_4344_v2 as select 2; +go +create proc babel_4344_s1.babel_4344_p2 as select 2; +go +CREATE FUNCTION babel_4344_s1.babel_4344_f2() RETURNS INT AS BEGIN RETURN (SELECT COUNT(*) FROM sys.objects) END +go +use master; +go + +-- tsql user=babel_4344_l1 password=12345678 +-- User has SCHEMA privileges,objects should be accessible. +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t2 +go +insert into babel_4344_s1.babel_4344_t1 values(4); +go +select * from babel_4344_s1.babel_4344_v2; +go +exec babel_4344_s1.babel_4344_p2; +go +select * from babel_4344_s1.babel_4344_f2(); +go +select * from "bAbel_4344 s1"."bAbel_4344 t1"; +go +use master; +go + +-- tsql +-- REVOKE OBJECT privileges +use babel_4344_d1; +go + +REVOKE SELECT on schema::"bAbel_4344 s1" from "BABEL_4344_U1"; +go +REVOKE SELECT on schema::"update pg_class set oid = 0 where relname = 'babel_4344_t1'" from BABEL_4344_U1; +go +GRANT SELECT on babel_4344_t1 to BABEL_4344_U1; +go + +-- psql +-- should show original object names +select schema_name, object_name, permission, grantee from sys.babelfish_schema_permissions where schema_name = 'babel_4344_s1' collate sys.database_default order by object_name; +go + +-- tsql +-- rename the objects where permissions are already granted +sp_rename 'babel_4344_t1', 'babel_4344_t1_new', 'OBJECT'; +go +sp_rename 'babel_4344_s1.babel_4344_t1', 'babel_4344_t1_new', 'OBJECT'; +go +sp_rename 'babel_4344_s1.babel_4344_t3', 'babel_4344_t3_new', 'OBJECT'; +go +sp_rename 'babel_4344_s1.babel_4344_v1', 'babel_4344_v1_new', 'OBJECT'; +go +sp_rename 'babel_4344_s1.babel_4344_p1', 'babel_4344_p1_new', 'OBJECT'; +go +sp_rename 'babel_4344_s1.babel_4344_f1', 'babel_4344_f1_new', 'OBJECT'; +go + +-- psql +-- should show renamed objects +select schema_name, object_name, permission, grantee from sys.babelfish_schema_permissions where schema_name = 'babel_4344_s1' collate sys.database_default order by object_name; +go + +-- tsql +-- permissions are transferred to the new objects +-- Revoke permissions from the new objects +REVOKE all on babel_4344_s1.babel_4344_t1_new FROM babel_4344_u1; +go +REVOKE select on babel_4344_s1.babel_4344_t3_new(a) FROM babel_4344_u1; +go +REVOKE select on babel_4344_s1.babel_4344_v1_new FROM babel_4344_u1; +go +REVOKE execute on babel_4344_s1.babel_4344_p1_new FROM babel_4344_u1; +go +REVOKE execute on babel_4344_s1.babel_4344_f1_new FROM babel_4344_u1; +go +REVOKE all on babel_4344_s1.babel_4344_f1_new FROM babel_4344_u1; +go + +-- tsql user=babel_4344_l1 password=12345678 +-- User has SCHEMA privileges, should be accessible. +use babel_4344_d1; +go +select * from babel_4344_t1_new; +go +select * from babel_4344_s1.babel_4344_t1_new +go +insert into babel_4344_s1.babel_4344_t1_new values(5); +go +select * from babel_4344_s1.babel_4344_t3_new; +go +select * from babel_4344_s1.babel_4344_v1_new; +go +exec babel_4344_s1.babel_4344_p1_new; +go +select * from babel_4344_s1.babel_4344_f1_new(); +go +select * from babel_4344_s2.babel_4344_t1; +go +use master; +go + +-- tsql +-- REVOKE SCHEMA privileges +use babel_4344_d1; +go +revoke select, insert, execute on schema::babel_4344_s1 from babel_4344_u1; +go +use master; +go + +-- psql +-- REVOKE on schema removes the entry from the catalog +select * from sys.babelfish_schema_permissions where schema_name = 'babel_4344_s1' collate sys.database_default; +go + +-- tsql user=babel_4344_l1 password=12345678 +-- User has no privileges, shouldn't be accessible. +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t1_new; +go +insert into babel_4344_s1.babel_4344_t1_new values(5); +go +select * from babel_4344_s1.babel_4344_t3_new; +go +select * from babel_4344_s1.babel_4344_v1_new; +go +exec babel_4344_s1.babel_4344_p1_new; +go +select * from babel_4344_s1.babel_4344_f1_new(); +go +use master; +go + +-- psql +-- grant object permission +grant select on babel_4344_s1.babel_4344_t1_new to babel_4344_d1_babel_4344_u1; +go + +-- tsql +-- grant schema permission +use babel_4344_d1; +go +grant select on schema::babel_4344_s1 to babel_4344_u1; +go +use master +go + +-- tsql user=babel_4344_l1 password=12345678 +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t1_new; -- accessible +go +use master +go + +-- psql +-- revoke schema permission +revoke select on all tables in schema babel_4344_s1 from babel_4344_d1_babel_4344_u1; +go + +-- tsql user=babel_4344_l1 password=12345678 +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t1_new; -- not accessible +go +use master +go + +-- tsql +-- Drop objects +use babel_4344_d1; +go + +drop schema "update pg_class set oid = 0 where relname = 'babel_4344_t1'"; +go + +drop table babel_4344_t1_new; +go + +drop table babel_4344_s1.babel_4344_t1_new; +go + +drop table babel_4344_t3; +go + +drop table babel_4344_s1.babel_4344_t3_new; +go + +drop table babel_4344_s1.babel_4344_t2; +go + +drop view babel_4344_v1; +go + +drop view babel_4344_s1.babel_4344_v1_new; +go + +drop view babel_4344_s1.babel_4344_v2; +go + +drop proc babel_4344_p1; +go + +drop proc babel_4344_s1.babel_4344_p1_new; +go + +drop proc babel_4344_s1.babel_4344_p2; +go + +drop proc babel_4344_s1.babel_4344_p3; +go + +drop function babel_4344_f1; +go + +drop function babel_4344_s1.babel_4344_f1_new; +go + +drop function babel_4344_s1.babel_4344_f2; +go + +drop schema babel_4344_s1; +go + +drop table babel_4344_s2.babel_4344_t1; +go + +drop schema babel_4344_s2; +go + +drop table αγάπη.abc; +go + +drop schema αγάπη; +go + +drop table スキーマ.abc; +go + +drop schema スキーマ; +go + +drop table "babel_4344 s1"."babel_4344 t1"; +go + +drop schema "BAbel_4344 s1"; +go + +drop user babel_4344_u1; +go + +drop user αιώνια; +go + +drop user ログイン; +go + +use master; +go + +drop database babel_4344_d1; +go + +-- psql +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'babel_4344_l1' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +go + +-- Wait to sync with another session +SELECT pg_sleep(1); +go + +-- tsql +drop login babel_4344_l1; +go + +-- psql +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'αιώνια' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +go + +-- Wait to sync with another session +SELECT pg_sleep(1); +go + +-- tsql +drop login αιώνια; +go + +-- psql +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'ログイン' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +go + +-- Wait to sync with another session +SELECT pg_sleep(1); +go + +-- tsql +drop login ログイン; +go diff --git a/test/JDBC/jdbc_schedule b/test/JDBC/jdbc_schedule index bbbd817389..505c94cdbf 100644 --- a/test/JDBC/jdbc_schedule +++ b/test/JDBC/jdbc_schedule @@ -51,6 +51,9 @@ ignore#!#FULLTEXT_INDEX-vu-verify ignore#!#FULLTEXT_INDEX-vu-cleanup ignore#!#BABEL_4553-vu-prepare ignore#!#BABEL_4553-vu-verify +ignore#!#GRANT_SCHEMA-vu-prepare +ignore#!#GRANT_SCHEMA-vu-verify +ignore#!#GRANT_SCHEMA-vu-cleanup # These tests are meant for upgrade scenario prior to (potential) 14_5 release ignore#!#BABEL-3147-before-14_5-vu-prepare diff --git a/test/JDBC/upgrade/13_6/schedule b/test/JDBC/upgrade/13_6/schedule index 7c960f6df1..20c3ba53b9 100644 --- a/test/JDBC/upgrade/13_6/schedule +++ b/test/JDBC/upgrade/13_6/schedule @@ -334,4 +334,4 @@ BABEL-2999 drop_index-before-15_6-or-16_2 permission_restrictions_from_pg BABEL-730-before-15_6-or-16_1 -babel-4517 \ No newline at end of file +GRANT_SCHEMA diff --git a/test/JDBC/upgrade/13_9/schedule b/test/JDBC/upgrade/13_9/schedule index ea6e3ca61c..fe0bb6c616 100644 --- a/test/JDBC/upgrade/13_9/schedule +++ b/test/JDBC/upgrade/13_9/schedule @@ -332,4 +332,5 @@ BABEL-2999 drop_index-before-15_6-or-16_2 permission_restrictions_from_pg BABEL-730-before-15_6-or-16_1 -babel-4517 \ No newline at end of file +babel-4517 +GRANT_SCHEMA diff --git a/test/JDBC/upgrade/14_10/schedule b/test/JDBC/upgrade/14_10/schedule index be32422594..714cc78e81 100644 --- a/test/JDBC/upgrade/14_10/schedule +++ b/test/JDBC/upgrade/14_10/schedule @@ -425,6 +425,7 @@ sys-parsename-before-15_6-or-16_1 permission_restrictions_from_pg BABEL-4529-before-15_6-or-14_11 BABEL-730-before-15_6-or-16_1 +GRANT_SCHEMA babel-4475 babel-3254 babel-4517 diff --git a/test/JDBC/upgrade/14_3/schedule b/test/JDBC/upgrade/14_3/schedule index 8105025dce..3e88ba22dd 100644 --- a/test/JDBC/upgrade/14_3/schedule +++ b/test/JDBC/upgrade/14_3/schedule @@ -350,4 +350,5 @@ BABEL-2999 drop_index-before-15_6-or-16_2 permission_restrictions_from_pg BABEL-730-before-15_6-or-16_1 -babel-4517 \ No newline at end of file +babel-4517 +GRANT_SCHEMA diff --git a/test/JDBC/upgrade/14_5/schedule b/test/JDBC/upgrade/14_5/schedule index 297e18b42c..7d63b162c6 100644 --- a/test/JDBC/upgrade/14_5/schedule +++ b/test/JDBC/upgrade/14_5/schedule @@ -365,4 +365,5 @@ BABEL-2999 drop_index-before-15_6-or-16_2 permission_restrictions_from_pg BABEL-730-before-15_6-or-16_1 +GRANT_SCHEMA babel-4517 diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index e5f16c6ab0..d5c7f61a1f 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -401,3 +401,4 @@ drop_index-before-15_6-or-16_2 permission_restrictions_from_pg BABEL-730-before-15_6-or-16_1 babel-4517 +GRANT_SCHEMA diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index ab7b8cf110..fcf8c36a95 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -429,5 +429,6 @@ drop_index-before-15_6-or-16_2 BABEL-4606 permission_restrictions_from_pg BABEL-730-before-15_6-or-16_1 +GRANT_SCHEMA babel-4475 babel-4517 diff --git a/test/JDBC/upgrade/15_4/schedule b/test/JDBC/upgrade/15_4/schedule index 1a16bdf3ad..9fc6222aa2 100644 --- a/test/JDBC/upgrade/15_4/schedule +++ b/test/JDBC/upgrade/15_4/schedule @@ -464,4 +464,5 @@ drop_index-before-15_6-or-16_2 BABEL-4606 permission_restrictions_from_pg BABEL-730-before-15_6-or-16_1 +GRANT_SCHEMA babel-4517 diff --git a/test/JDBC/upgrade/15_5/schedule b/test/JDBC/upgrade/15_5/schedule index e13869f714..66fb093cf6 100644 --- a/test/JDBC/upgrade/15_5/schedule +++ b/test/JDBC/upgrade/15_5/schedule @@ -495,3 +495,4 @@ BABEL-730-before-15_6-or-16_1 babel-3254 babel-4517 BABEL-492-before-15_6 +GRANT_SCHEMA \ No newline at end of file diff --git a/test/python/expected/sql_validation_framework/expected_create.out b/test/python/expected/sql_validation_framework/expected_create.out index aba05ac74e..4aeffb5a88 100644 --- a/test/python/expected/sql_validation_framework/expected_create.out +++ b/test/python/expected/sql_validation_framework/expected_create.out @@ -192,6 +192,7 @@ Could not find upgrade tests for procedure sys.sp_unprepare Could not find upgrade tests for procedure sys.sp_updatestats Could not find upgrade tests for table sys.babelfish_configurations Could not find upgrade tests for table sys.babelfish_helpcollation +Could not find upgrade tests for table sys.babelfish_schema_permissions Could not find upgrade tests for table sys.babelfish_syslanguages Could not find upgrade tests for table sys.service_settings Could not find upgrade tests for table sys.spt_datatype_info_table