From e395b5372311ad28f690872900c5a5d6576a29db Mon Sep 17 00:00:00 2001 From: shalinilohia50 <46928246+shalinilohia50@users.noreply.github.com> Date: Tue, 21 Nov 2023 16:45:03 +0530 Subject: [PATCH] Fix bugs for GRANT/REVOKE on SCHEMA (#2031) Bug fixes for GRANT/REVOKE .. ON SCHEMA 1. Server crash when using empty bracketed name. `schema::[]` 2. Server crash when using empty quoted identifier. `schema::""` 3. When granting permission to yourself, we need a different error message. 4. Error message in not-supported multi-keyword permission should (i) be in uppercase (ii) have a space between keywords 5. Not-supported object type in error message should be in uppercase 6. GRANT ON SCHEMA:: TO PUBLIC does not take effect 7. Specified collation for column names using NAME datatype Issues Resolved : BABEL-4344 Signed-off-by: Shalini Lohia --- contrib/babelfishpg_tsql/sql/ownership.sql | 11 + .../babelfishpg_tsql--3.3.0--3.4.0.sql | 11 + contrib/babelfishpg_tsql/src/catalog.c | 415 +++++++++ contrib/babelfishpg_tsql/src/catalog.h | 67 ++ contrib/babelfishpg_tsql/src/pl_exec-2.c | 116 +++ contrib/babelfishpg_tsql/src/pl_handler.c | 245 +++++ contrib/babelfishpg_tsql/src/pltsql_utils.c | 5 +- contrib/babelfishpg_tsql/src/tsqlIface.cpp | 122 +++ .../src/tsqlUnsupportedFeatureHandler.cpp | 8 +- test/JDBC/expected/BABEL-GRANT.out | 37 +- test/JDBC/expected/GRANT_SCHEMA.out | 847 ++++++++++++++++++ test/JDBC/input/BABEL-GRANT.sql | 21 +- test/JDBC/input/GRANT_SCHEMA.mix | 531 +++++++++++ 13 files changed, 2427 insertions(+), 9 deletions(-) create mode 100644 test/JDBC/expected/GRANT_SCHEMA.out 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 9b6989b6cf0..b9749cfdcde 100644 --- a/contrib/babelfishpg_tsql/sql/ownership.sql +++ b/contrib/babelfishpg_tsql/sql/ownership.sql @@ -14,6 +14,17 @@ CREATE TABLE sys.babelfish_sysdatabases ( GRANT SELECT on sys.babelfish_sysdatabases TO PUBLIC; +-- BABELFISH_SCHEMA_PERMISSIONS +CREATE TABLE sys.babelfish_schema_permissions ( + dbid smallint NOT NULL, + schema_name NAME NOT NULL COLLATE sys.database_default, + object_name NAME NOT NULL COLLATE sys.database_default, + permission NAME NOT NULL COLLATE sys.database_default, + grantee NAME NOT NULL COLLATE sys.database_default, + object_type NAME COLLATE sys.database_default, + PRIMARY KEY(dbid, schema_name, object_name, permission, grantee) +); + -- BABELFISH_FUNCTION_EXT CREATE TABLE sys.babelfish_function_ext ( nspname NAME NOT NULL, diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.3.0--3.4.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.3.0--3.4.0.sql index dd4abdb8b3c..786ffd2d4ad 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.3.0--3.4.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.3.0--3.4.0.sql @@ -886,6 +886,17 @@ END; $body$ LANGUAGE plpgsql STABLE; +-- BABELFISH_SCHEMA_PERMISSIONS +CREATE TABLE IF NOT EXISTS sys.babelfish_schema_permissions ( + dbid smallint NOT NULL, + schema_name NAME NOT NULL COLLATE sys.database_default, + object_name NAME NOT NULL COLLATE sys.database_default, + permission NAME NOT NULL COLLATE sys.database_default, + grantee NAME NOT NULL COLLATE sys.database_default, + object_type NAME COLLATE sys.database_default, + PRIMARY KEY(dbid, schema_name, object_name, permission, grantee) +); + create or replace function sys.babelfish_timezone_mapping(IN tmz text) returns text AS 'babelfishpg_tsql', 'timezone_mapping' LANGUAGE C IMMUTABLE ; diff --git a/contrib/babelfishpg_tsql/src/catalog.c b/contrib/babelfishpg_tsql/src/catalog.c index c9b91d8af05..c9704d8ae79 100644 --- a/contrib/babelfishpg_tsql/src/catalog.c +++ b/contrib/babelfishpg_tsql/src/catalog.c @@ -2804,6 +2804,421 @@ rename_procfunc_update_bbf_catalog(RenameStmt *stmt) table_close(bbf_func_ext_rel, RowExclusiveLock); } +/* Add a catalog entry. */ +void +add_entry_to_bbf_schema(const char *schema_name, + const char *object_name, + const char *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") == 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[BBF_SCHEMA_PERMS_DBID] = Int16GetDatum(dbid); + new_record_bbf_schema[BBF_SCHEMA_PERMS_SCHEMA_NAME] = CStringGetDatum(pstrdup(schema_name)); + new_record_bbf_schema[BBF_SCHEMA_PERMS_OBJECT_NAME] = CStringGetDatum(pstrdup(object_name)); + new_record_bbf_schema[BBF_SCHEMA_PERMS_PERMISSION] = CStringGetDatum(pstrdup(permission)); + new_record_bbf_schema[BBF_SCHEMA_PERMS_GRANTEE] = CStringGetDatum(pstrdup(grantee)); + if (object_type != NULL) + new_record_bbf_schema[BBF_SCHEMA_PERMS_OBJECT_TYPE] = CStringGetDatum(pstrdup(object_type)); + else + new_record_nulls_bbf_schema[BBF_SCHEMA_PERMS_OBJECT_TYPE] = true; + + 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(); +} + +/* Check if the catalog entry exists. */ +bool +check_bbf_schema_for_entry(const char *schema_name, + const char *object_name, + const char *permission, + const char *grantee) +{ + Relation bbf_schema_rel; + HeapTuple tuple_bbf_schema; + ScanKeyData scanKey[5]; + SysScanDesc scan; + bool catalog_entry_exists = false; + int16 dbid = get_cur_db_id(); + + /* Immediately return false, if grantee is NULL or PUBLIC. */ + if ((grantee == NULL) || (strcmp(grantee, "public") == 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_NAMEEQ, + CStringGetDatum(schema_name)); + ScanKeyEntryInitialize(&scanKey[2], 0, + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_NAMEEQ, + CStringGetDatum(object_name)); + ScanKeyEntryInitialize(&scanKey[3], 0, + Anum_bbf_schema_perms_permission, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_NAMEEQ, + CStringGetDatum(permission)); + ScanKeyEntryInitialize(&scanKey[4], 0, + Anum_bbf_schema_perms_grantee, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_NAMEEQ, + CStringGetDatum(grantee)); + 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)) + catalog_entry_exists = true; + + systable_endscan(scan); + table_close(bbf_schema_rel, AccessShareLock); + return catalog_entry_exists; +} + +/* + * Checks if a particular schema has any SCHEMA level permission granted to any user. + */ +bool +check_bbf_schema_for_schema(const char *schema_name, + const char *object_name, + const char *permission) +{ + Relation bbf_schema_rel; + HeapTuple tuple_bbf_schema; + ScanKeyData key[4]; + SysScanDesc scan; + bool catalog_entry_exists = false; + int16 dbid = get_cur_db_id(); + + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), + AccessShareLock); + 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_NAMEEQ, + CStringGetDatum(schema_name)); + ScanKeyEntryInitialize(&key[2], 0, + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_NAMEEQ, + CStringGetDatum(object_name)); + ScanKeyEntryInitialize(&key[3], 0, + Anum_bbf_schema_perms_permission, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_NAMEEQ, + CStringGetDatum(permission)); + + scan = systable_beginscan(bbf_schema_rel, + get_bbf_schema_perms_idx_oid(), + true, NULL, 4, key); + + 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; +} + +void +del_from_bbf_schema(const char *schema_name, + const char *object_name, + const char *permission, + const char *grantee) +{ + Relation bbf_schema_rel; + HeapTuple tuple_bbf_schema; + ScanKeyData scanKey[5]; + SysScanDesc scan; + int16 dbid = get_cur_db_id(); + + /* Immediately return, if grantee is NULL or PUBLIC. */ + if ((grantee == NULL) || (strcmp(grantee, "public") == 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_NAMEEQ, + CStringGetDatum(schema_name)); + ScanKeyEntryInitialize(&scanKey[2], 0, + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_NAMEEQ, + CStringGetDatum(object_name)); + ScanKeyEntryInitialize(&scanKey[3], 0, + Anum_bbf_schema_perms_permission, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_NAMEEQ, + CStringGetDatum(permission)); + ScanKeyEntryInitialize(&scanKey[4], 0, + Anum_bbf_schema_perms_grantee, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_NAMEEQ, + CStringGetDatum(grantee)); + 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); +} + +void +clean_up_bbf_schema(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(); + + /* 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_NAMEEQ, + CStringGetDatum(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_NAMEEQ, + CStringGetDatum(schema_name)); + ScanKeyEntryInitialize(&scanKey[2], 0, + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_NAMEEQ, + CStringGetDatum(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, + const char *permission, + const char *grantee) +{ + SysScanDesc scan; + Relation bbf_schema_rel; + HeapTuple tuple_bbf_schema; + const char *object_name; + const char *object_type; + ScanKeyData scanKey[4]; + 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); + 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_NAMEEQ, + CStringGetDatum(schema_name)); + ScanKeyEntryInitialize(&scanKey[2], 0, + Anum_bbf_schema_perms_permission, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_NAMEEQ, + CStringGetDatum(permission)); + ScanKeyEntryInitialize(&scanKey[3], 0, + Anum_bbf_schema_perms_grantee, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_NAMEEQ, + CStringGetDatum(grantee)); + + scan = systable_beginscan(bbf_schema_rel, get_bbf_schema_perms_idx_oid(), + true, NULL, 4, scanKey); + tuple_bbf_schema = systable_getnext(scan); + + while (HeapTupleIsValid(tuple_bbf_schema)) + { + Form_bbf_schema_perms schemaform; + schemaform = (Form_bbf_schema_perms) GETSTRUCT(tuple_bbf_schema); + object_name = pstrdup(NameStr(schemaform->object_name)); + object_type = pstrdup(NameStr(schemaform->object_type)); + + /* For each object, grant the permission explicitly. */ + if (strcmp(object_name, "ALL") != 0) + { + StringInfoData query; + char *schema; + List *res; + Node *res_stmt; + PlannedStmt *wrapper; + + schema = get_physical_schema_name((char *)db_name, schema_name); + initStringInfo(&query); + if (strcmp(permission, "execute") != 0) + appendStringInfo(&query, "GRANT \"%s\" ON \"%s\".\"%s\" TO \"%s\"; ", permission, schema, object_name, grantee); + else + { + if (object_type != NULL && strcmp(object_type, "f") == 0) + appendStringInfo(&query, "GRANT \"%s\" ON FUNCTION \"%s\".\"%s\" TO \"%s\"; ", permission, schema, object_name, grantee); + else + appendStringInfo(&query, "GRANT \"%s\" ON PROCEDURE \"%s\".\"%s\" TO \"%s\"; ", permission, 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); + + /* make sure later steps can see the object created here */ + CommandCounterIncrement(); + } + 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 558969b7583..c3a7de00859 100644 --- a/contrib/babelfishpg_tsql/src/catalog.h +++ b/contrib/babelfishpg_tsql/src/catalog.h @@ -280,6 +280,73 @@ 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 BBF_SCHEMA_PERMS_DBID 0 +#define BBF_SCHEMA_PERMS_SCHEMA_NAME 1 +#define BBF_SCHEMA_PERMS_OBJECT_NAME 2 +#define BBF_SCHEMA_PERMS_PERMISSION 3 +#define BBF_SCHEMA_PERMS_GRANTEE 4 +#define BBF_SCHEMA_PERMS_OBJECT_TYPE 5 +#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 PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA "ALL" + +extern Oid bbf_schema_perms_oid; +extern Oid bbf_schema_perms_idx_oid; + +extern Oid get_bbf_schema_perms_oid(void); +extern Oid get_bbf_schema_perms_idx_oid(void); + +typedef struct FormData_bbf_schema_perms +{ + int16 dbid; + NameData schema_name; + NameData object_name; + NameData permission; + NameData grantee; + NameData object_type; +} FormData_bbf_schema_perms; + +typedef FormData_bbf_schema_perms *Form_bbf_schema_perms; + +extern void add_entry_to_bbf_schema(const char *schema_name, + const char *object_name, + const char *permission, + const char *grantee, + const char *object_type); + +extern bool check_bbf_schema_for_entry(const char *schema_name, + const char *object_name, + const char *permission, + const char *grantee); + +extern void del_from_bbf_schema(const char *schema_name, + const char *object_name, + const char *permission, + const char *grantee); + +extern bool check_bbf_schema_for_schema(const char *schema_name, + const char *object_name, + const char *permission); + +extern void clean_up_bbf_schema(const char *schema_name, + const char *object_name, + bool is_schema); + +extern void grant_perms_to_objects_in_schema(const char *schema_name, + const char *permission, + const char *grantee); + /***************************************** * DOMAIN MAPPING *****************************************/ diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index 7cd31efd24a..211cebb86e2 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -3675,6 +3675,122 @@ get_insert_bulk_kilobytes_per_batch() return insert_bulk_kilobytes_per_batch; } +static int +exec_stmt_grantschema(PLtsql_execstate *estate, PLtsql_stmt_grantschema *stmt) +{ + List *parsetree_list; + ListCell *parsetree_item; + char *dbname = get_cur_db_name(); + char *login = GetUserNameFromId(GetSessionUserId(), false); + bool login_is_db_owner; + char *rolname; + char *schema_name; + ListCell *lc; + ListCell *lc1; + Oid schemaOid; + char *user = GetUserNameFromId(GetUserId(), false); + + /* + * 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. + */ + login_is_db_owner = 0 == strncmp(login, get_owner_of_db(dbname), NAMEDATALEN); + schema_name = get_physical_schema_name(dbname, stmt->schema_name); + + if(schema_name) + { + 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", + schema_name))); + + foreach(lc1, stmt->privileges) + { + char *priv_name = (char *) lfirst(lc1); + foreach(lc, stmt->grantees) + { + char *grantee_name = (char *) lfirst(lc); + Oid role_oid; + bool grantee_is_db_owner; + if (strcmp(grantee_name, "public") != 0) + rolname = get_physical_user_name(dbname, grantee_name); + else + rolname = pstrdup("public"); + role_oid = get_role_oid(rolname, true); + grantee_is_db_owner = 0 == strncmp(grantee_name, get_owner_of_db(dbname), NAMEDATALEN); + + if (strcmp(grantee_name, "public") != 0 && role_oid == InvalidOid) + 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) || pg_namespace_ownercheck(schemaOid, role_oid) || is_member_of_role(role_oid, get_sysadmin_oid()) || grantee_is_db_owner) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Cannot grant, deny, or revoke permissions to sa, dbo, entity owner, information_schema, sys, or yourself."))); + + if (!is_member_of_role(GetSessionUserId(), get_sysadmin_oid()) && !login_is_db_owner && !pg_namespace_ownercheck(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))); + + parsetree_list = gen_grantschema_subcmds(schema_name, rolname, stmt->is_grant, stmt->with_grant_option, priv_name); + /* 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); + + /* make sure later steps can see the object created here */ + CommandCounterIncrement(); + } + /* Add entry for each grant statement. */ + if (stmt->is_grant && !check_bbf_schema_for_entry(stmt->schema_name, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, priv_name, rolname)) + add_entry_to_bbf_schema(stmt->schema_name, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, priv_name, rolname, NULL); + /* Remove entry for each revoke statement. */ + if (!stmt->is_grant && check_bbf_schema_for_entry(stmt->schema_name, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, priv_name, rolname)) + { + /* If any object in the schema has the OBJECT level permission. Then, internally grant that permission back. */ + grant_perms_to_objects_in_schema(stmt->schema_name, priv_name, rolname); + del_from_bbf_schema(stmt->schema_name, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, priv_name, rolname); + } + 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_handler.c b/contrib/babelfishpg_tsql/src/pl_handler.c index eb304aecb26..987ee47a85f 100644 --- a/contrib/babelfishpg_tsql/src/pl_handler.c +++ b/contrib/babelfishpg_tsql/src/pl_handler.c @@ -3546,6 +3546,251 @@ 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; + const char *obj_type = "r"; + 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) + { + if (grant->is_grant) + { + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + int i = 0; + char *permissions[] = {"select", "insert", "update", "references", "delete"}; + for(i = 0; i < 5; i++) + { + /* + * If object permission doesn't exist already, add an entry to the catalog. + */ + if (!check_bbf_schema_for_entry(logical_schema, obj, permissions[i], rol_spec->rolename)) + add_entry_to_bbf_schema(logical_schema, obj, permissions[i], rol_spec->rolename, obj_type); + } + } + break; + } + else + { + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + int i = 0; + bool has_schema_perms = false; + char *permissions[] = {"select", "insert", "update", "references", "delete"}; + for(i = 0; i < 5; i++) + { + /* + * 1. If only schema permission exists, don't revoke any permission. + * 2. If only object permission exists, delete entry from the catalog and revoke permission. + * 3. If both schema and object permission exist, don't revoke any permission but delete object + * entry from the catalog. + */ + if (check_bbf_schema_for_entry(logical_schema, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, permissions[i], rol_spec->rolename) && !has_schema_perms) + has_schema_perms = true; + del_from_bbf_schema(logical_schema, obj, permissions[i], rol_spec->rolename); + } + if (has_schema_perms) + return; + } + break; + } + } + foreach(lc1, grant->privileges) + { + AccessPriv *ap = (AccessPriv *) lfirst(lc1); + if (grant->is_grant) + { + /* + * 1. Execute the GRANT statement. + * 2. Add its corresponding entry in the catalog, if doesn't exist already. + * 3. Don't add an entry, if the permission is granted on column list. + */ + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + /* + * Don't add an entry, if the permission is granted on column list. + */ + if (ap->cols != NULL) + break; + if (!check_bbf_schema_for_entry(logical_schema, obj, ap->priv_name, rol_spec->rolename)) + add_entry_to_bbf_schema(logical_schema, obj, ap->priv_name, rol_spec->rolename, obj_type); + } + } + else + { + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + /* + * 1. If GRANT on schema does not exist, execute REVOKE statement and remove the catalog entry if exists. + * 2. If GRANT on schema exist, only remove the entry from the catalog if exists. + */ + if ((logical_schema != NULL) && !check_bbf_schema_for_entry(logical_schema, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, ap->priv_name, rol_spec->rolename)) + { + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + } + /* + * Don't remove an entry, if the permission is revoked on column list. + */ + if (ap->cols != NULL) + break; + del_from_bbf_schema(logical_schema, obj, ap->priv_name, rol_spec->rolename); + } + } + } + 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 = "f"; + else + obj_type = "p"; + 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) + { + if(check_bbf_schema_for_schema(logicalschema, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, "execute")) + return; + } + + if (grant->is_grant) + { + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + if (!check_bbf_schema_for_entry(logicalschema, funcname, "execute", rol_spec->rolename)) + add_entry_to_bbf_schema(logicalschema, funcname, "execute", rol_spec->rolename, obj_type); + } + } + else + { + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + bool has_schema_perms = false; + if (check_bbf_schema_for_entry(logicalschema, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, "execute", rol_spec->rolename) && !has_schema_perms) + has_schema_perms = true; + del_from_bbf_schema(logicalschema, funcname, "execute", rol_spec->rolename); + if (has_schema_perms) + return; + } + } + break; + } + foreach(lc1, grant->privileges) + { + AccessPriv *ap = (AccessPriv *) lfirst(lc1); + if (grant->is_grant) + { + /* Execute the GRANT statement. */ + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + /* Add entry to the catalog if it doesn't exist already. */ + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + /* Add an entry to the catalog, if an entry doesn't exist already. */ + if (!check_bbf_schema_for_entry(logicalschema, funcname, ap->priv_name, rol_spec->rolename)) + { + add_entry_to_bbf_schema(logicalschema, funcname, ap->priv_name, rol_spec->rolename, obj_type); + } + } + } + else + { + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + /* + * 1. If GRANT on schema does not exist, execute REVOKE statement and remove the catalog entry if exists. + * 2. If GRANT on schema exist, only remove the entry from the catalog if exists. + */ + if (!check_bbf_schema_for_entry(logicalschema, PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA, ap->priv_name, rol_spec->rolename)) + { + /* Execute REVOKE statement. */ + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + } + /* Remove an entry from the catalog, if it exists. */ + del_from_bbf_schema(logicalschema, funcname, ap->priv_name, rol_spec->rolename); + } + } + } + return; + } + } default: break; } diff --git a/contrib/babelfishpg_tsql/src/pltsql_utils.c b/contrib/babelfishpg_tsql/src/pltsql_utils.c index ba4022e9cd6..ff7d22b57f8 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_utils.c +++ b/contrib/babelfishpg_tsql/src/pltsql_utils.c @@ -1036,7 +1036,10 @@ update_GrantStmt(Node *n, const char *object, const char *obj_schema, const char if (grantee && stmt->grantees) { RoleSpec *tmp = (RoleSpec *) llast(stmt->grantees); - + if (strcmp(grantee, "public") == 0) + { + tmp->roletype = ROLESPEC_PUBLIC; + } tmp->rolename = pstrdup(grantee); } } diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index 3c560021c6c..87e7b89d364 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -5481,6 +5481,11 @@ makeGrantdbStatement(TSqlParser::Security_statementContext *ctx) 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"); + grantee_list = lappend(grantee_list, grantee_name); + } } result->grantees = grantee_list; return (PLtsql_stmt *) result; @@ -5509,12 +5514,129 @@ makeGrantdbStatement(TSqlParser::Security_statementContext *ctx) 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"); + grantee_list = lappend(grantee_list, grantee_name); + } } result->grantees = grantee_list; return (PLtsql_stmt *) result; } } } + if (ctx->grant_statement() && ctx->grant_statement()->ON() && ctx->grant_statement()->permission_object() + && ctx->grant_statement()->permission_object()->object_type() && ctx->grant_statement()->permission_object()->object_type()->SCHEMA()) + { + if (ctx->grant_statement()->TO() && ctx->grant_statement()->principals() && ctx->grant_statement()->permissions()) + { + PLtsql_stmt_grantschema *result = (PLtsql_stmt_grantschema *) palloc0(sizeof(PLtsql_stmt_grantschema)); + result->cmd_type = PLTSQL_STMT_GRANTSCHEMA; + result->lineno = getLineNo(ctx->grant_statement()); + result->is_grant = true; + std::string schema_name; + if (ctx->grant_statement()->permission_object()->full_object_name()->object_name) + { + schema_name = stripQuoteFromId(ctx->grant_statement()->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->grant_statement()->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"); + grantee_list = lappend(grantee_list, grantee_name); + } + } + List *privilege_list = NIL; + for (auto perm: ctx->grant_statement()->permissions()->permission()) + { + auto single_perm = perm->single_permission(); + if (single_perm->EXECUTE()) + privilege_list = lappend(privilege_list, (void *)"execute"); + if (single_perm->EXEC()) + privilege_list = lappend(privilege_list, (void *)"execute"); + if (single_perm->SELECT()) + privilege_list = lappend(privilege_list, (void *)"select"); + if (single_perm->INSERT()) + privilege_list = lappend(privilege_list, (void *)"insert"); + if (single_perm->UPDATE()) + privilege_list = lappend(privilege_list, (void *)"update"); + if (single_perm->DELETE()) + privilege_list = lappend(privilege_list, (void *)"delete"); + if (single_perm->REFERENCES()) + privilege_list = lappend(privilege_list, (void *)"references"); + } + result->privileges = privilege_list; + if (ctx->grant_statement()->WITH()) + result->with_grant_option = true; + result->grantees = grantee_list; + return (PLtsql_stmt *) result; + } + } + + if (ctx->revoke_statement() && ctx->revoke_statement()->ON() && ctx->revoke_statement()->permission_object() + && ctx->revoke_statement()->permission_object()->object_type() && ctx->revoke_statement()->permission_object()->object_type()->SCHEMA()) + { + if (ctx->revoke_statement()->FROM() && ctx->revoke_statement()->principals() && ctx->revoke_statement()->permissions()) + { + PLtsql_stmt_grantschema *result = (PLtsql_stmt_grantschema *) palloc0(sizeof(PLtsql_stmt_grantschema)); + result->cmd_type = PLTSQL_STMT_GRANTSCHEMA; + result->lineno = getLineNo(ctx->revoke_statement()); + result->is_grant = false; + std::string schema_name; + if (ctx->revoke_statement()->permission_object()->full_object_name()->object_name) + { + schema_name = stripQuoteFromId(ctx->revoke_statement()->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()) + { + 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"); + grantee_list = lappend(grantee_list, grantee_name); + } + } + List *privilege_list = NIL; + for (auto perm: ctx->revoke_statement()->permissions()->permission()) + { + auto single_perm = perm->single_permission(); + if (single_perm->EXECUTE()) + privilege_list = lappend(privilege_list, (void *)"execute"); + if (single_perm->EXEC()) + privilege_list = lappend(privilege_list, (void *)"execute"); + if (single_perm->SELECT()) + privilege_list = lappend(privilege_list, (void *)"select"); + if (single_perm->INSERT()) + privilege_list = lappend(privilege_list, (void *)"insert"); + if (single_perm->UPDATE()) + privilege_list = lappend(privilege_list, (void *)"update"); + if (single_perm->DELETE()) + privilege_list = lappend(privilege_list, (void *)"delete"); + if (single_perm->REFERENCES()) + privilege_list = lappend(privilege_list, (void *)"references"); + } + result->privileges = privilege_list; + 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/tsqlUnsupportedFeatureHandler.cpp b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp index d8b3e7473c5..ef597a31872 100644 --- a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp @@ -1744,7 +1744,8 @@ 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)); } @@ -1758,6 +1759,7 @@ void TsqlUnsupportedFeatureHandlerImpl::checkSupportedGrantStmt(TSqlParser::Gran if (obj_type && !obj_type->OBJECT()) { 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)); } } @@ -1837,7 +1839,8 @@ 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)); } @@ -1851,6 +1854,7 @@ void TsqlUnsupportedFeatureHandlerImpl::checkSupportedRevokeStmt(TSqlParser::Rev if (obj_type && !obj_type->OBJECT()) { 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/BABEL-GRANT.out b/test/JDBC/expected/BABEL-GRANT.out index 7847a641567..d2d340992f0 100644 --- a/test/JDBC/expected/BABEL-GRANT.out +++ b/test/JDBC/expected/BABEL-GRANT.out @@ -155,7 +155,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,20 +172,48 @@ 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: 'GRANT ON SCHEMA' is not currently supported in Babelfish)~~ -REVOKE ALL ON SCHEMA::scm TO guest; -- unsupported class +REVOKE ALL ON SCHEMA::scm TO guest; GO ~~ERROR (Code: 33557097)~~ ~~ERROR (Message: 'REVOKE ON SCHEMA' is not currently supported in Babelfish)~~ +GRANT create table ON OBJECT::t1 TO guest; -- unsupported permission +GO +~~ERROR (Code: 33557097)~~ + +~~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; GO ~~ERROR (Code: 33557097)~~ diff --git a/test/JDBC/expected/GRANT_SCHEMA.out b/test/JDBC/expected/GRANT_SCHEMA.out new file mode 100644 index 00000000000..935acbe2f53 --- /dev/null +++ b/test/JDBC/expected/GRANT_SCHEMA.out @@ -0,0 +1,847 @@ +-- 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 schema babel_4344_s1; +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 babel_4344_t3(a int, b int); +go + +create table babel_4344_s1.babel_4344_t3(a int, b int); +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 AS BEGIN RETURN (SELECT COUNT(*) FROM sys.tables) END +go + +CREATE FUNCTION babel_4344_s1.babel_4344_f1() RETURNS INT AS BEGIN RETURN (SELECT COUNT(*) FROM sys.objects) END +go + +grant SELECT on schema::babel_4344_S1 to public, αιώνια; +go + +grant select on schema::αγάπη to αιώνια; +go + +-- tsql user=αιώνια password=12345678 +use babel_4344_d1; +go + +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 +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 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 +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 +3 +~~END~~ + +select * from babel_4344_s1.babel_4344_f1(); +go +~~START~~ +int +9 +~~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 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" and object_name = 'ALL' collate "C" order by permission; +go +~~START~~ +name#!#name#!#name#!#name +babel_4344_s1#!#ALL#!#execute#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#ALL#!#insert#!#babel_4344_d1_babel_4344_u1 +babel_4344_s1#!#ALL#!#select#!#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 +11 +~~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 +9 +~~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 +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 +15 +~~END~~ + +use master; +go + +-- tsql +-- REVOKE OBJECT privileges +use babel_4344_d1; +go +REVOKE all on babel_4344_s1.babel_4344_t1 FROM babel_4344_u1; +go +REVOKE select on babel_4344_s1.babel_4344_t3(a) FROM babel_4344_u1; +go +REVOKE select on babel_4344_s1.babel_4344_v1 FROM babel_4344_u1; +go +REVOKE execute on babel_4344_s1.babel_4344_p1 FROM babel_4344_u1; +go +REVOKE execute on babel_4344_s1.babel_4344_f1 FROM babel_4344_u1; +go +REVOKE all on babel_4344_s1.babel_4344_f1 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_s1.babel_4344_t1 +go +~~START~~ +int +2 +3 +3 +4 +~~END~~ + +insert into babel_4344_s1.babel_4344_t1 values(5); +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 +15 +~~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#!#name#!#name#!#name#!#name#!#name +~~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; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t1)~~ + +insert into babel_4344_s1.babel_4344_t1 values(5); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t1)~~ + +select * from babel_4344_s1.babel_4344_t3; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t3)~~ + +select * from babel_4344_s1.babel_4344_v1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for view babel_4344_v1)~~ + +exec babel_4344_s1.babel_4344_p1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for procedure babel_4344_p1)~~ + +select * from babel_4344_s1.babel_4344_f1(); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function babel_4344_f1)~~ + +use master; +go + +-- psql +-- grant object permission +grant select on babel_4344_s1.babel_4344_t1 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; -- 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; -- not accessible +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t1)~~ + +use master +go + +-- tsql +-- Drop objects +use babel_4344_d1; +go + +drop table babel_4344_t1; +go + +drop table babel_4344_s1.babel_4344_t1; +go + +drop table babel_4344_t3; +go + +drop table babel_4344_s1.babel_4344_t3; +go + +drop table babel_4344_s1.babel_4344_t2; +go + +drop view babel_4344_v1; +go + +drop view babel_4344_s1.babel_4344_v1; +go + +drop view babel_4344_s1.babel_4344_v2; +go + +drop proc babel_4344_p1; +go + +drop proc babel_4344_s1.babel_4344_p1; +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; +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 user babel_4344_u1; +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 diff --git a/test/JDBC/input/BABEL-GRANT.sql b/test/JDBC/input/BABEL-GRANT.sql index c175c338575..5728ae1ff47 100644 --- a/test/JDBC/input/BABEL-GRANT.sql +++ b/test/JDBC/input/BABEL-GRANT.sql @@ -145,16 +145,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 + +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 ALL ON SCHEMA::scm TO guest; -- unsupported class +REVOKE SELECT ON table::t1 FROM guest; -- unsupported object GO GRANT ALL ON OBJECT::t1 TO guest WITH GRANT OPTION AS superuser; diff --git a/test/JDBC/input/GRANT_SCHEMA.mix b/test/JDBC/input/GRANT_SCHEMA.mix new file mode 100644 index 00000000000..f4af9f7af76 --- /dev/null +++ b/test/JDBC/input/GRANT_SCHEMA.mix @@ -0,0 +1,531 @@ +-- 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 schema babel_4344_s1; +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 babel_4344_t3(a int, b int); +go + +create table babel_4344_s1.babel_4344_t3(a int, b int); +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 AS BEGIN RETURN (SELECT COUNT(*) FROM sys.tables) END +go + +CREATE FUNCTION babel_4344_s1.babel_4344_f1() RETURNS INT AS BEGIN RETURN (SELECT COUNT(*) FROM sys.objects) END +go + +grant SELECT on schema::babel_4344_S1 to public, αιώνια; +go + +grant select on schema::αγάπη to αιώνια; +go + +-- tsql user=αιώνια password=12345678 +use babel_4344_d1; +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 +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 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 +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 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" and object_name = 'ALL' 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 +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 +use master; +go + +-- tsql +-- REVOKE OBJECT privileges +use babel_4344_d1; +go +REVOKE all on babel_4344_s1.babel_4344_t1 FROM babel_4344_u1; +go +REVOKE select on babel_4344_s1.babel_4344_t3(a) FROM babel_4344_u1; +go +REVOKE select on babel_4344_s1.babel_4344_v1 FROM babel_4344_u1; +go +REVOKE execute on babel_4344_s1.babel_4344_p1 FROM babel_4344_u1; +go +REVOKE execute on babel_4344_s1.babel_4344_f1 FROM babel_4344_u1; +go +REVOKE all on babel_4344_s1.babel_4344_f1 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_s1.babel_4344_t1 +go +insert into babel_4344_s1.babel_4344_t1 values(5); +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 +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; +go +insert into babel_4344_s1.babel_4344_t1 values(5); +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 + +-- psql +-- grant object permission +grant select on babel_4344_s1.babel_4344_t1 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; -- 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; -- not accessible +go +use master +go + +-- tsql +-- Drop objects +use babel_4344_d1; +go + +drop table babel_4344_t1; +go + +drop table babel_4344_s1.babel_4344_t1; +go + +drop table babel_4344_t3; +go + +drop table babel_4344_s1.babel_4344_t3; +go + +drop table babel_4344_s1.babel_4344_t2; +go + +drop view babel_4344_v1; +go + +drop view babel_4344_s1.babel_4344_v1; +go + +drop view babel_4344_s1.babel_4344_v2; +go + +drop proc babel_4344_p1; +go + +drop proc babel_4344_s1.babel_4344_p1; +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; +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 user babel_4344_u1; +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