diff --git a/contrib/babelfishpg_tsql/sql/ownership.sql b/contrib/babelfishpg_tsql/sql/ownership.sql index 5f6a2aa9f7f..38e34be5ca8 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, + object_name NAME NOT NULL, + permission NAME NOT NULL, + grantee NAME NOT NULL, + object_type NAME, + 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 48f1f67825f..e4beff00cc5 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 @@ -789,7 +789,16 @@ $BODY$ LANGUAGE plpgsql IMMUTABLE; - +-- BABELFISH_SCHEMA_PERMISSIONS +CREATE TABLE IF NOT EXISTS sys.babelfish_schema_permissions ( + dbid smallint NOT NULL, + schema_name NAME NOT NULL, + object_name NAME NOT NULL, + permission NAME NOT NULL, + grantee NAME NOT NULL, + object_type NAME, + 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' diff --git a/contrib/babelfishpg_tsql/src/catalog.c b/contrib/babelfishpg_tsql/src/catalog.c index 9279f870129..26e9a97341c 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 + *****************************************/ + +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; +} + +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 *****************************************/ @@ -2799,6 +2828,346 @@ 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(); + + /* 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 key[5]; + TableScanDesc 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)); + ScanKeyInit(&key[1], + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(schema_name)); + ScanKeyInit(&key[2], + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(object_name)); + ScanKeyInit(&key[3], + Anum_bbf_schema_perms_permission, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(permission)); + ScanKeyInit(&key[4], + Anum_bbf_schema_perms_grantee, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(grantee)); + + scan = table_beginscan_catalog(bbf_schema_rel, 5, key); + + tuple_bbf_schema = heap_getnext(scan, ForwardScanDirection); + if (HeapTupleIsValid(tuple_bbf_schema)) + catalog_entry_exists = true; + + table_endscan(scan); + table_close(bbf_schema_rel, AccessShareLock); + return catalog_entry_exists; +} + +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]; + TableScanDesc 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)); + ScanKeyInit(&key[1], + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(schema_name)); + ScanKeyInit(&key[2], + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(object_name)); + ScanKeyInit(&key[3], + Anum_bbf_schema_perms_permission, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(permission)); + + scan = table_beginscan_catalog(bbf_schema_rel, 4, key); + + tuple_bbf_schema = heap_getnext(scan, ForwardScanDirection); + if (HeapTupleIsValid(tuple_bbf_schema)) + catalog_entry_exists = true; + + table_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 key[5]; + TableScanDesc scan; + int16 dbid = get_cur_db_id(); + + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), + RowExclusiveLock); + ScanKeyInit(&key[0], + Anum_bbf_schema_perms_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(dbid)); + ScanKeyInit(&key[1], + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(schema_name)); + ScanKeyInit(&key[2], + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(object_name)); + ScanKeyInit(&key[3], + Anum_bbf_schema_perms_permission, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(permission)); + ScanKeyInit(&key[4], + Anum_bbf_schema_perms_grantee, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(grantee)); + + scan = table_beginscan_catalog(bbf_schema_rel, 5, key); + + tuple_bbf_schema = heap_getnext(scan, ForwardScanDirection); + + if (HeapTupleIsValid(tuple_bbf_schema)) + CatalogTupleDelete(bbf_schema_rel, &tuple_bbf_schema->t_self); + + table_endscan(scan); + table_close(bbf_schema_rel, RowExclusiveLock); + + CommandCounterIncrement(); +} + +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)); + ScanKeyInit(&scanKey[1], + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, 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)); + ScanKeyInit(&scanKey[1], + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(schema_name)); + ScanKeyInit(&scanKey[2], + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, 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); +} + +void +grant_perms_to_objects_in_schema(const char *schema_name, + const char *permission, + const char *grantee) +{ + TableScanDesc 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)); + ScanKeyInit(&scanKey[1], + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(schema_name)); + ScanKeyInit(&scanKey[2], + Anum_bbf_schema_perms_permission, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(permission)); + ScanKeyInit(&scanKey[3], + Anum_bbf_schema_perms_grantee, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(grantee)); + + scan = table_beginscan_catalog(bbf_schema_rel, 4, scanKey); + tuple_bbf_schema = heap_getnext(scan, ForwardScanDirection); + + 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 = heap_getnext(scan, ForwardScanDirection); + } + table_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) @@ -2880,4 +3249,4 @@ alter_guest_schema_for_db (const char *dbname) table_endscan(tblscan); table_close(bbf_authid_user_ext_rel, RowExclusiveLock); -} \ No newline at end of file +} diff --git a/contrib/babelfishpg_tsql/src/catalog.h b/contrib/babelfishpg_tsql/src/catalog.h index 0fd604f6f98..95eae77b8b2 100644 --- a/contrib/babelfishpg_tsql/src/catalog.h +++ b/contrib/babelfishpg_tsql/src/catalog.h @@ -278,6 +278,71 @@ 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 + +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/codegen.c b/contrib/babelfishpg_tsql/src/codegen.c index 1108a78d9c3..c6726ba373d 100644 --- a/contrib/babelfishpg_tsql/src/codegen.c +++ b/contrib/babelfishpg_tsql/src/codegen.c @@ -300,6 +300,7 @@ stmt_default_act(Walker_context *ctx, PLtsql_stmt *stmt) case PLTSQL_STMT_THROW: case PLTSQL_STMT_USEDB: case PLTSQL_STMT_GRANTDB: + case PLTSQL_STMT_GRANTSCHEMA: case PLTSQL_STMT_INSERT_BULK: case PLTSQL_STMT_SET_EXPLAIN_MODE: /* TSQL-only executable node */ diff --git a/contrib/babelfishpg_tsql/src/dbcmds.c b/contrib/babelfishpg_tsql/src/dbcmds.c index ca1d6a4c44b..c602c669204 100644 --- a/contrib/babelfishpg_tsql/src/dbcmds.c +++ b/contrib/babelfishpg_tsql/src/dbcmds.c @@ -154,7 +154,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) { @@ -181,7 +181,7 @@ gen_createdb_subcmds(const char *schema, const char *dbo, const char *db_owner, stmt = parsetree_nth_stmt(res, i++); update_AlterTableStmt(stmt, schema, db_owner); - + if (guest) { stmt = parsetree_nth_stmt(res, i++); diff --git a/contrib/babelfishpg_tsql/src/iterative_exec.c b/contrib/babelfishpg_tsql/src/iterative_exec.c index 6a21c1b1948..24ca677e444 100644 --- a/contrib/babelfishpg_tsql/src/iterative_exec.c +++ b/contrib/babelfishpg_tsql/src/iterative_exec.c @@ -800,6 +800,15 @@ dispatch_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt) } exec_stmt_grantdb(estate, (PLtsql_stmt_grantdb *) stmt); break; + case PLTSQL_STMT_GRANTSCHEMA: + if (pltsql_explain_only) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Showing Estimated Execution Plan for GRANT DB statment is not yet supported"))); + } + exec_stmt_grantschema(estate, (PLtsql_stmt_grantschema *) stmt); + break; case PLTSQL_STMT_INSERT_BULK: 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 dbd4a06471a..ef9c40a9e45 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -50,6 +50,7 @@ static int exec_run_dml_with_output(PLtsql_execstate *estate, PLtsql_stmt_push_r 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_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); extern Datum pltsql_inline_handler(PG_FUNCTION_ARGS); @@ -3287,3 +3288,98 @@ 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; + Oid datdba; + char *rolname; + char *schema_name; + ListCell *lc; + ListCell *lc1; + Oid schemaOid; + + /* + * 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); + datdba = get_role_oid("sysadmin", false); + schema_name = get_physical_schema_name(dbname, stmt->schema_name); + schemaOid = LookupExplicitNamespace(schema_name, true); + + if (!OidIsValid(schemaOid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("schema \"%s\" does not exist", + schema_name))); + + if (!is_member_of_role(GetSessionUserId(), datdba) && !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))); + + 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; + rolname = get_physical_user_name(dbname, grantee_name); + role_oid = get_role_oid(rolname, true); + grantee_is_db_owner = 0 == strncmp(grantee_name, get_owner_of_db(dbname), NAMEDATALEN); + + if (pg_namespace_ownercheck(schemaOid, role_oid) || is_member_of_role(role_oid, datdba) || 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."))); + + 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, "ALL", priv_name, rolname)) + add_entry_to_bbf_schema(stmt->schema_name, "ALL", priv_name, rolname, NULL); + /* Remove entry for each revoke statement. */ + if (!stmt->is_grant && check_bbf_schema_for_entry(stmt->schema_name, "ALL", 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, "ALL", priv_name, rolname); + } + } + } + return PLTSQL_RC_OK; +} diff --git a/contrib/babelfishpg_tsql/src/pl_funcs-2.c b/contrib/babelfishpg_tsql/src/pl_funcs-2.c index e27f145da82..c095a74a9f9 100644 --- a/contrib/babelfishpg_tsql/src/pl_funcs-2.c +++ b/contrib/babelfishpg_tsql/src/pl_funcs-2.c @@ -483,6 +483,7 @@ free_stmt2(PLtsql_stmt *stmt) case PLTSQL_STMT_USEDB: case PLTSQL_STMT_INSERT_BULK: case PLTSQL_STMT_GRANTDB: + 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 edd3c093434..100ec277439 100644 --- a/contrib/babelfishpg_tsql/src/pl_handler.c +++ b/contrib/babelfishpg_tsql/src/pl_handler.c @@ -3213,6 +3213,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) @@ -3261,7 +3262,45 @@ bbf_ProcessUtility(PlannedStmt *pstmt, NULL); CommandCounterIncrement(); - + /* Grant all privileges to the user.*/ + if (rolspec && strcmp(queryString, "(CREATE LOGICAL DATABASE )") != 0) + { + char *permissions[] = {"select", "insert", "update", "references", "delete", "execute"}; + List *parsetree_list; + ListCell *parsetree_item; + int i; + for (i = 0; i < 6; i++) + { + parsetree_list = gen_grantschema_subcmds(create_schema->schemaname, rolspec->rolename, true, false, permissions[i]); + /* 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(); + } + } + } return; } else @@ -3275,7 +3314,6 @@ bbf_ProcessUtility(PlannedStmt *pstmt, { if (sql_dialect == SQL_DIALECT_TSQL) bbf_ExecDropStmt(drop_stmt); - break; } @@ -3287,10 +3325,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) @@ -3303,6 +3342,8 @@ bbf_ProcessUtility(PlannedStmt *pstmt, bbf_ExecDropStmt(drop_stmt); del_ns_ext_info(schemaname, drop_stmt->missing_ok); + if (logicalschema != NULL) + clean_up_bbf_schema(logicalschema, NULL, true); if (prev_ProcessUtility) prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, @@ -3540,6 +3581,233 @@ 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 ((rol_spec->rolename != NULL) && !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++) + { + if (check_bbf_schema_for_entry(logical_schema, "ALL", permissions[i], rol_spec->rolename) && !has_schema_perms) + has_schema_perms = true; + if ((rol_spec->rolename != NULL) && check_bbf_schema_for_entry(logical_schema, obj, permissions[i], rol_spec->rolename)) + 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); + if ((ap->cols == NULL) && !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, "ALL", 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); + } + if ((ap->cols == NULL) && check_bbf_schema_for_entry(logical_schema, obj, ap->priv_name, rol_spec->rolename)) + 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); + } + /* + * 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 && list_length(grant->privileges) == 0) + { + if(check_bbf_schema_for_schema(logicalschema, "ALL", "execute")) + return; + break; + } + /* 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); + if ((rol_spec->rolename != NULL) && !check_bbf_schema_for_entry(logicalschema, funcname, "execute", rol_spec->rolename)) + add_entry_to_bbf_schema(logicalschema, funcname, "execute", rol_spec->rolename, obj_type); + } + break; + } + else + { + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + bool has_schema_perms = false; + if ((rol_spec->rolename != NULL) && check_bbf_schema_for_entry(logicalschema, "ALL", "execute", rol_spec->rolename) && !has_schema_perms) + has_schema_perms = true; + if ((rol_spec->rolename != NULL) && check_bbf_schema_for_entry(logicalschema, funcname, "execute", rol_spec->rolename)) + 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); + /* Don't store a row in catalog, if permission is granted for column */ + 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, "ALL", 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); + } + if (check_bbf_schema_for_entry(logicalschema, funcname, ap->priv_name, rol_spec->rolename)) + del_from_bbf_schema(logicalschema, funcname, ap->priv_name, rol_spec->rolename); + } + } + } + return; + } + } default: break; } @@ -5591,6 +5859,7 @@ bbf_ExecDropStmt(DropStmt *stmt) Relation relation = NULL; Oid schema_oid; ListCell *cell; + const char *logicalschema = NULL; db_id = get_cur_db_id(); @@ -5631,6 +5900,7 @@ bbf_ExecDropStmt(DropStmt *stmt) schema_oid = get_object_namespace(&address); if (OidIsValid(schema_oid)) schema_name = get_namespace_name(schema_oid); + logicalschema = get_logical_schema_name(schema_name, true); if (schema_name && major_name) { @@ -5656,6 +5926,8 @@ bbf_ExecDropStmt(DropStmt *stmt) major_name, NULL); } } + if (logicalschema != NULL) + clean_up_bbf_schema(logicalschema, major_name, false); } } else if (stmt->removeType == OBJECT_PROCEDURE || @@ -5699,6 +5971,7 @@ bbf_ExecDropStmt(DropStmt *stmt) schema_oid = get_object_namespace(&address); if (OidIsValid(schema_oid)) schema_name = get_namespace_name(schema_oid); + logicalschema = get_logical_schema_name(schema_name, true); if (schema_name && major_name) { @@ -5712,6 +5985,8 @@ bbf_ExecDropStmt(DropStmt *stmt) delete_extended_property(db_id, type, schema_name, major_name, NULL); } + if (logicalschema != NULL) + clean_up_bbf_schema(logicalschema, major_name, false); } } } diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index 5df20d340e8..e5cc3adfcbc 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -185,7 +185,8 @@ typedef enum PLtsql_stmt_type PLTSQL_STMT_RESTORE_CTX_FULL, PLTSQL_STMT_RESTORE_CTX_PARTIAL, PLTSQL_STMT_INSERT_BULK, - PLTSQL_STMT_GRANTDB + PLTSQL_STMT_GRANTDB, + PLTSQL_STMT_GRANTSCHEMA } PLtsql_stmt_type; /* @@ -1000,6 +1001,20 @@ typedef struct PLtsql_stmt_grantdb List *grantees; /* list of users */ } PLtsql_stmt_grantdb; +/* + * Grant on schema stmt + */ +typedef struct PLtsql_stmt_grantschema +{ + PLtsql_stmt_type cmd_type; + int lineno; + bool is_grant; + List *privileges; /* list of privileges */ + List *grantees; /* list of users */ + bool with_grant_option; + char *schema_name; /* schema name */ +} PLtsql_stmt_grantschema; + /* * ASSERT statement */ @@ -1966,6 +1981,7 @@ extern void pltsql_scanner_finish(void); extern int pltsql_yyparse(void); /* functions in pltsql_utils.c */ +extern List *gen_grantschema_subcmds(const char *schema, const char *db_user, bool is_grant, bool with_grant_option, const char *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); @@ -2004,7 +2020,8 @@ 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_AlterDefaultPrivilegesStmt(Node *n, const char *object, 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 fc4f10e3a06..08199cd7a2b 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_utils.c +++ b/contrib/babelfishpg_tsql/src/pltsql_utils.c @@ -1012,7 +1012,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; @@ -1034,6 +1034,39 @@ update_GrantStmt(Node *n, const char *object, const char *obj_schema, const char tmp->rolename = pstrdup(grantee); } + + if (priv && stmt->privileges) + { + AccessPriv *tmp = (AccessPriv *) llast(stmt->privileges); + + tmp->priv_name = pstrdup(priv); + } +} + +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 @@ -1683,4 +1716,69 @@ Oid get_sys_varcharoid(void) errmsg("Oid corresponding to sys.varchar datatype could not be found."))); } return sys_varcharoid; -} \ No newline at end of file +} + +List +*gen_grantschema_subcmds(const char *schema, const char *rolname, bool is_grant, bool with_grant_option, const char *privilege) +{ + StringInfoData query; + List *stmt_list; + Node *stmt; + int expected_stmts = 2; + int i = 0; + initStringInfo(&query); + if (is_grant) + { + if (strcmp(privilege, "execute") == 0) + { + 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 (strcmp(privilege, "execute") == 0) + { + 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); + + stmt = parsetree_nth_stmt(stmt_list, i++); + if (strcmp(privilege, "execute") == 0) + update_GrantStmt(stmt, schema, NULL, rolname, privilege); + else + update_AlterDefaultPrivilegesStmt(stmt, schema, rolname, privilege); + + return stmt_list; +} diff --git a/contrib/babelfishpg_tsql/src/stmt_walker.c b/contrib/babelfishpg_tsql/src/stmt_walker.c index 6ecbcaf08f1..b33cb422349 100644 --- a/contrib/babelfishpg_tsql/src/stmt_walker.c +++ b/contrib/babelfishpg_tsql/src/stmt_walker.c @@ -107,6 +107,7 @@ stmt_walker(PLtsql_stmt *stmt, WalkerFunc walker, void *context) case PLTSQL_STMT_INSERT_BULK: case PLTSQL_STMT_SET_EXPLAIN_MODE: case PLTSQL_STMT_GRANTDB: + case PLTSQL_STMT_GRANTSCHEMA: break; /* TSQL-only executable node */ case PLTSQL_STMT_SAVE_CTX: @@ -205,6 +206,7 @@ general_walker_func(PLtsql_stmt *stmt, void *context) DISPATCH(INSERT_BULK, insert_bulk) DISPATCH(SET_EXPLAIN_MODE, set_explain_mode) DISPATCH(GRANTDB, grantdb) + 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 54b6db96970..98f143c5ebd 100644 --- a/contrib/babelfishpg_tsql/src/stmt_walker.h +++ b/contrib/babelfishpg_tsql/src/stmt_walker.h @@ -87,6 +87,7 @@ typedef bool (*Stmt_usedb_act) ACTION_SIGNITURE(usedb); typedef bool (*Stmt_insert_bulk_act) ACTION_SIGNITURE(insert_bulk); typedef bool (*Stmt_set_explain_mode) ACTION_SIGNITURE(set_explain_mode); typedef bool (*Stmt_grantdb_act) ACTION_SIGNITURE(grantdb); +typedef bool (*Stmt_grantschema_act) ACTION_SIGNITURE(grantschema); /* TSQL-only executable node */ typedef bool (*Stmt_save_ctx) ACTION_SIGNITURE(save_ctx); @@ -137,6 +138,7 @@ typedef struct Walker_context Stmt_insert_bulk_act insert_bulk_act; Stmt_set_explain_mode set_explain_mode_act; Stmt_grantdb_act grantdb_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 2efe330c623..ee0336cf78e 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -1851,6 +1851,52 @@ class tsqlBuilder : public tsqlCommonMutator } } } + else 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()) + { + for (auto perm: ctx->grant_statement()->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()) + { + clear_rewritten_query_fragment(); + return; + } + } + } + } + + else 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()) + { + for (auto perm: ctx->revoke_statement()->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()) + { + clear_rewritten_query_fragment(); + return; + } + } + } + } + PLtsql_stmt_execsql *stmt = (PLtsql_stmt_execsql *) getPLtsql_fragment(ctx); Assert(stmt); @@ -5357,6 +5403,108 @@ makeGrantdbStatement(TSqlParser::Security_statementContext *ctx) } } } + 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); + } + } + 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); + } + } + 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/tsqlNodes.h b/contrib/babelfishpg_tsql/src/tsqlNodes.h index 2bdc6b4fdae..cb0195dce00 100644 --- a/contrib/babelfishpg_tsql/src/tsqlNodes.h +++ b/contrib/babelfishpg_tsql/src/tsqlNodes.h @@ -48,7 +48,8 @@ typedef enum pltsql_stmt_type PLTSQL_STMT_ASSIGN_CURVAR, PLTSQL_STMT_DEALLOCATE, PLTSQL_STMT_INSERT_BULK, - PLTSQL_STMT_GRANTDB + PLTSQL_STMT_GRANTDB, + 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 2ce6d3ed40a..a6897b15984 100644 --- a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp @@ -1676,7 +1676,6 @@ void TsqlUnsupportedFeatureHandlerImpl::checkSupportedGrantStmt(TSqlParser::Gran unsupported_feature = "GRANT PERMISSION " + perm->getText(); handle(INSTR_UNSUPPORTED_TSQL_REVOKE_STMT, unsupported_feature.c_str(), getLineAndPos(perm)); } - } } @@ -1684,7 +1683,9 @@ 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(); handle(INSTR_UNSUPPORTED_TSQL_REVOKE_STMT, unsupported_feature.c_str(), getLineAndPos(obj_type)); @@ -1769,7 +1770,6 @@ void TsqlUnsupportedFeatureHandlerImpl::checkSupportedRevokeStmt(TSqlParser::Rev unsupported_feature = "REVOKE PERMISSION " + perm->getText(); handle(INSTR_UNSUPPORTED_TSQL_REVOKE_STMT, unsupported_feature.c_str(), getLineAndPos(perm)); } - } } @@ -1777,7 +1777,9 @@ 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(); handle(INSTR_UNSUPPORTED_TSQL_REVOKE_STMT, unsupported_feature.c_str(), getLineAndPos(obj_type)); diff --git a/test/JDBC/expected/BABEL-CROSS-DB.out b/test/JDBC/expected/BABEL-CROSS-DB.out index bf13b5f26f5..2273c92e4f2 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 e1c4007985f..4e8a1695a1c 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,12 @@ GO --- --- Basic Grant / Revoke --- +GRANT SELECT ON SCHEMA::scm TO guest; +GO + +GRANT INSERT ON SCHEMA::scm TO guest; +GO + GRANT ALL ON OBJECT::t1 TO guest WITH GRANT OPTION; GO @@ -143,6 +153,9 @@ GO ~~ERROR (Message: 'REVOKE ALL on Database' is not currently supported in Babelfish)~~ +REVOKE SELECT ON SCHEMA::scm FROM guest; -- unsupported permission +GO + GRANT SHOWPLAN ON OBJECT::t1 TO guest; -- unsupported permission GO ~~ERROR (Code: 33557097)~~ @@ -161,14 +174,14 @@ GRANT ALL ON SCHEMA::scm TO guest; -- unsupported class 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 GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: 'REVOKE 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.)~~ GRANT ALL ON OBJECT::t1 TO guest WITH GRANT OPTION AS superuser; @@ -189,6 +202,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 87d51024a55..6e9888edd58 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 00000000000..af83d2ea36d --- /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 00000000000..069a323b573 --- /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 00000000000..16a45233e29 --- /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 00000000000..efa0a7e4288 --- /dev/null +++ b/test/JDBC/expected/GRANT_SCHEMA.out @@ -0,0 +1,631 @@ +-- 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 schema babel_4344_s1; +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 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 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 + +-- 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 +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 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 + +-- 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~~ + +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 find the schema "babel_4344_s1", because it does not exist or you do not have permission.)~~ + +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 + +-- 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 +10 +~~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; -- TODO: should be accessible +go +~~START~~ +int +2 +~~END~~ + +select * from babel_4344_s1.babel_4344_f1(); -- TODO: should be accessible +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 +14 +~~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 +14 +~~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 + +-- 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 + +-- 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 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 user babel_4344_u1; +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 diff --git a/test/JDBC/input/BABEL-CROSS-DB.mix b/test/JDBC/input/BABEL-CROSS-DB.mix index 594fcd1b0e8..630af3bad34 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 fb53d932099..76909fb8e4f 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,12 @@ GO --- Basic Grant / Revoke --- +GRANT SELECT ON SCHEMA::scm TO guest; +GO + +GRANT INSERT ON SCHEMA::scm TO guest; +GO + GRANT ALL ON OBJECT::t1 TO guest WITH GRANT OPTION; GO @@ -133,6 +143,9 @@ GO REVOKE ALL TO alogin; -- database permission GO +REVOKE SELECT ON SCHEMA::scm FROM guest; -- unsupported permission +GO + GRANT SHOWPLAN ON OBJECT::t1 TO guest; -- unsupported permission GO @@ -155,6 +168,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 41c1c853985..d9f7be4a8ca 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 00000000000..156b92c61e6 --- /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 00000000000..306cd64d582 --- /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 00000000000..09e9a233360 --- /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 00000000000..1572bea803b --- /dev/null +++ b/test/JDBC/input/GRANT_SCHEMA.mix @@ -0,0 +1,386 @@ +-- 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 schema babel_4344_s1; +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 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 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 + +-- 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 +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 + +-- 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 +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 + +-- 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; -- TODO: should be accessible +go +select * from babel_4344_s1.babel_4344_f1(); -- TODO: should be accessible +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 + +-- 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 + +-- 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 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 user babel_4344_u1; +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 diff --git a/test/JDBC/jdbc_schedule b/test/JDBC/jdbc_schedule index 520643ad735..77de12cacd3 100644 --- a/test/JDBC/jdbc_schedule +++ b/test/JDBC/jdbc_schedule @@ -33,6 +33,9 @@ ignore#!#BABEL-3117-vu-prepare ignore#!#BABEL-3117-vu-verify ignore#!#BABEL-3655-vu-prepare ignore#!#BABEL-3655-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 c9d7237f726..3943bbadbbe 100644 --- a/test/JDBC/upgrade/13_6/schedule +++ b/test/JDBC/upgrade/13_6/schedule @@ -324,3 +324,4 @@ triggers_with_transaction BABEL-4046 getdate BABEL-4410 +GRANT_SCHEMA diff --git a/test/JDBC/upgrade/13_9/schedule b/test/JDBC/upgrade/13_9/schedule index 07d859c0532..c606176c9ad 100644 --- a/test/JDBC/upgrade/13_9/schedule +++ b/test/JDBC/upgrade/13_9/schedule @@ -320,3 +320,4 @@ triggers_with_transaction BABEL-4046 getdate BABEL-4410 +GRANT_SCHEMA diff --git a/test/JDBC/upgrade/14_10/schedule b/test/JDBC/upgrade/14_10/schedule index 0ac25aa2284..a9897f774c3 100644 --- a/test/JDBC/upgrade/14_10/schedule +++ b/test/JDBC/upgrade/14_10/schedule @@ -410,3 +410,4 @@ smalldatetimefromparts-dep BABEL_4330 BABEL-4231 BABEL-4384 +GRANT_SCHEMA diff --git a/test/JDBC/upgrade/14_3/schedule b/test/JDBC/upgrade/14_3/schedule index 1526f6e5414..f68c4e41fe2 100644 --- a/test/JDBC/upgrade/14_3/schedule +++ b/test/JDBC/upgrade/14_3/schedule @@ -338,3 +338,4 @@ BABEL-4046 BABEL_4330 BABEL-2619 BABEL-4410 +GRANT_SCHEMA \ No newline at end of file diff --git a/test/JDBC/upgrade/14_5/schedule b/test/JDBC/upgrade/14_5/schedule index 9fad0e16367..c78b90e8828 100644 --- a/test/JDBC/upgrade/14_5/schedule +++ b/test/JDBC/upgrade/14_5/schedule @@ -353,3 +353,4 @@ getdate BABEL_4330 BABEL-2619 BABEL-4410 +GRANT_SCHEMA diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index 30bd32bf353..0d4c2bfe149 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -387,3 +387,4 @@ getdate BABEL_4330 BABEL-2619 BABEL-4410 +GRANT_SCHEMA diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index 01f241a2125..ff7db62fd1b 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -415,3 +415,4 @@ BABEL-4046 getdate BABEL_4330 BABEL-4410 +GRANT_SCHEMA diff --git a/test/JDBC/upgrade/15_4/schedule b/test/JDBC/upgrade/15_4/schedule index fd5244d648b..e7f12532e6c 100644 --- a/test/JDBC/upgrade/15_4/schedule +++ b/test/JDBC/upgrade/15_4/schedule @@ -449,4 +449,4 @@ BABEL-4175 sp_who BABEL_4330 BABEL-4410 - +GRANT_SCHEMA diff --git a/test/python/expected/sql_validation_framework/expected_create.out b/test/python/expected/sql_validation_framework/expected_create.out index 6259aefdfdd..0bd142e4ac6 100644 --- a/test/python/expected/sql_validation_framework/expected_create.out +++ b/test/python/expected/sql_validation_framework/expected_create.out @@ -72,6 +72,7 @@ Could not find tests for procedure sys.printarg Could not find tests for procedure sys.sp_cursor_list Could not find tests for procedure sys.sp_describe_cursor Could not find tests for table sys.babelfish_helpcollation +Could not find tests for table sys.babelfish_schema_permissions Could not find tests for table sys.babelfish_syslanguages Could not find tests for table sys.service_settings Could not find tests for table sys.spt_datatype_info_table @@ -199,6 +200,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