diff --git a/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 b/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 index d52ea2f0a8..53707785c5 100644 --- a/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 +++ b/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 @@ -155,16 +155,22 @@ CHANGETABLE: C H A N G E T A B L E; CHANGE_RETENTION: C H A N G E UNDERLINE R E T E N T I O N; CHANGE_TRACKING: C H A N G E UNDERLINE T R A C K I N G; CHECK: C H E C K; +CHECKDB: C H E C K D B; +CHECKFILEGROUP: C H E C K F I L E G R O U P; +CHECKIDENT: C H E C K I D E N T; CHECKPOINT: C H E C K P O I N T; CHECKSUM: C H E C K S U M; CHECKSUM_AGG: C H E C K S U M UNDERLINE A G G; +CHECKTABLE: C H E C K T A B L E; CHECK_EXPIRATION: C H E C K UNDERLINE E X P I R A T I O N; CHECK_POLICY: C H E C K UNDERLINE P O L I C Y; CLASSIFIER: C L A S S I F I E R; CLASSIFIER_FUNCTION: C L A S S I F I E R UNDERLINE F U N C T I O N; CLEANUP: C L E A N U P; +CLEANTABLE: C L E A N T A B L E; CLEANUP_POLICY: C L E A N U P UNDERLINE P O L I C Y; CLEAR: C L E A R; +CLONEDATABASE: C L O N E D A T A B A S E; CLOSE: C L O S E; CLUSTER: C L U S T E R; CLUSTERED: C L U S T E R E D; @@ -248,6 +254,7 @@ DATE_CORRELATION_OPTIMIZATION: D A T E UNDERLINE C O R R E L DAY: D A Y; DAYS: D A Y S; DBCC: D B C C; +DBREINDEX: D B R E I N D E X; DB_CHAINING: D B UNDERLINE C H A I N I N G; DB_FAILOVER: D B UNDERLINE F A I L O V E R; DDL: D D L; @@ -298,6 +305,7 @@ DOLLAR_ROWGUID: DOLLAR R O W G U I D; DOLLAR_TO_ID: DOLLAR T O UNDERLINE I D; // graph DOUBLE: D O U B L E; DROP: D R O P; +DROPCLEANBUFFERS: D R O P C L E A N B U F F E R S; DTC_SUPPORT: D T C UNDERLINE S U P P O R T; DUMP: D U M P; DYNAMIC: D Y N A M I C; @@ -387,6 +395,9 @@ FORMAT: F O R M A T; FORWARD_ONLY: F O R W A R D UNDERLINE O N L Y; FORMAT_OPTIONS: F O R M A T UNDERLINE O P T I O N S; FORMAT_TYPE: F O R M A T UNDERLINE T Y P E; +FREEPROCCACHE: F R E E P R O C C A C H E; +FREESESSIONCACHE: F R E E S E S S I O N C A C H E; +FREESYSTEMCACHE: F R E E S Y S T E M C A C H E; FREETEXT: F R E E T E X T; FREETEXTTABLE: F R E E T E X T T A B L E; FROM: F R O M; @@ -424,6 +435,7 @@ HASHED: H A S H E D; HAVING: H A V I N G; HEALTHCHECKTIMEOUT: H E A L T H C H E C K T I M E O U T; HEALTH_CHECK_TIMEOUT: H E A L T H UNDERLINE C H E C K UNDERLINE T I M E O U T; +HELP: H E L P; HIDDEN_RENAMED: H I D D E N; HIGH: H I G H; HINT: H I N T; @@ -433,6 +445,7 @@ HOLDLOCK: H O L D L O C K; HONOR_BROKER_PRIORITY: H O N O R UNDERLINE B R O K E R UNDERLINE P R I O R I T Y; HOUR: H O U R; HOURS: H O U R S; +INDEXDEFRAG: I N D E X D E F R A G; IDENTITY: I D E N T I T Y; IDENTITYCOL: I D E N T I T Y C O L; IDENTITY_INSERT: I D E N T I T Y UNDERLINE I N S E R T; @@ -455,6 +468,7 @@ INIT: I N I T; INITIATOR: I N I T I A T O R; INNER: I N N E R; INPUT: I N P U T; +INPUTBUFFER: I N P U T B U F F E R; INSENSITIVE: I N S E N S I T I V E; INSERT: I N S E R T; INSERTED: I N S E R T E D; @@ -603,6 +617,7 @@ NONE: N O N E; NON_TRANSACTED_ACCESS: N O N UNDERLINE T R A N S A C T E D UNDERLINE A C C E S S; NORECOMPUTE: N O R E C O M P U T E; NORECOVERY: N O R E C O V E R Y; +NORESEED: N O R E S E E D; NOREWIND: N O R E W I N D; NOSKIP: N O S K I P; NOT: N O T; @@ -643,6 +658,7 @@ OPENDATASOURCE: O P E N D A T A S O U R C E; OPENJSON: O P E N J S O N; OPENQUERY: O P E N Q U E R Y; OPENROWSET: O P E N R O W S E T; +OPENTRAN: O P E N T R A N; OPENXML: O P E N X M L; OPEN_EXISTING: O P E N UNDERLINE E X I S T I N G; OPERATIONS: O P E R A T I O N S; @@ -655,6 +671,7 @@ ORDER: O R D E R; OUT: O U T; OUTER: O U T E R; OUTPUT: O U T P U T; +OUTPUTBUFFER: O U T P U T B U F F E R; OVER: O V E R; OVERRIDE: O V E R R I D E; OWNER: O W N E R; @@ -711,6 +728,7 @@ PRIVATE: P R I V A T E; PRIVATE_KEY: P R I V A T E UNDERLINE K E Y; PRIVILEGES: P R I V I L E G E S; PROC: P R O C; +PROCCACHE: P R O C C A C H E; PROCEDURE: P R O C E D U R E; PROCEDURE_CACHE: P R O C E D U R E UNDERLINE C A C H E; PROCEDURE_NAME: P R O C E D U R E UNDERLINE N A M E; @@ -781,6 +799,7 @@ REQUEST_MEMORY_GRANT_TIMEOUT_SEC: R E Q U E S T UNDERLINE M E M REQUIRED: R E Q U I R E D; REQUIRED_SYNCHRONIZED_SECONDARIES_TO_COMMIT: R E Q U I R E D UNDERLINE S Y N C H R O N I Z E D UNDERLINE S E C O N D A R I E S UNDERLINE T O UNDERLINE C O M M I T; RESAMPLE: R E S A M P L E; +RESEED: R E S E E D; RESERVE_DISK_SPACE: R E S E R V E UNDERLINE D I S K UNDERLINE S P A C E; RESET: R E S E T; RESOURCE: R E S O U R C E; @@ -871,10 +890,14 @@ SETS: S E T S; SETTINGS: S E T T I N G S; SETUSER: S E T U S E R; SHARE: S H A R E; +SHOWCONTIG: S H O W C O N T I G; SHOWPLAN: S H O W P L A N; SHOWPLAN_ALL: S H O W P L A N UNDERLINE A L L; SHOWPLAN_TEXT: S H O W P L A N UNDERLINE T E X T; SHOWPLAN_XML: S H O W P L A N UNDERLINE X M L; +SHOW_STATISTICS: S H O W UNDERLINE S T A T I S T I C S; +SHRINKDATABASE: S H R I N K D A T A B A S E; +SHRINKFILE: S H R I N K F I L E; SHRINKLOG: S H R I N K L O G; SHUTDOWN: S H U T D O W N; SID: S I D; @@ -899,6 +922,7 @@ SQL: S Q L; SQLDUMPERFLAGS: S Q L D U M P E R F L A G S; SQLDUMPERPATH: S Q L D U M P E R P A T H; SQLDUMPERTIMEOUT: S Q L D U M P E R T I M E O U T S; +SQLPERF: S Q L P E R F; STALE_CAPTURE_POLICY_THRESHOLD: S T A L E UNDERLINE C A P T U R E UNDERLINE P O L I C Y UNDERLINE T H R E S H O L D; STALE_QUERY_THRESHOLD_DAYS: S T A L E UNDERLINE Q U E R Y UNDERLINE T H R E S H O L D UNDERLINE D A Y S; STANDBY: S T A N D B Y; @@ -970,7 +994,10 @@ TOSTRING: T O S T R I N G; TOTAL_COMPILE_CPU_TIME_MS: T O T A L UNDERLINE C O M P I L E UNDERLINE C P U UNDERLINE T I M E UNDERLINE M S; TOTAL_EXECUTION_CPU_TIME_MS: T O T A L UNDERLINE E X E C U T I O N UNDERLINE C P U UNDERLINE T I M E UNDERLINE M S; TRACE: T R A C E; +TRACEOFF: T R A C E O F F; +TRACEON: T R A C E O N; TRACKING: T R A C K I N G; +TRACESTATUS: T R A C E S T A T U S; TRACK_CAUSALITY: T R A C K UNDERLINE C A U S A L I T Y; TRACK_COLUMNS_UPDATED: T R A C K UNDERLINE C O L U M N S UNDERLINE U P D A T E D; TRAN: T R A N; @@ -1009,6 +1036,7 @@ UNPIVOT: U N P I V O T; UNSAFE: U N S A F E; UOW: U O W; UPDATE: U P D A T E; +UPDATEUSAGE: U P D A T E U S A G E; UPDATETEXT: U P D A T E T E X T; UPDLOCK: U P D L O C K; URL: U R L; @@ -1016,6 +1044,7 @@ USE: U S E; USE_TYPE_DEFAULT: U S E UNDERLINE T Y P E UNDERLINE D E F A U L T; USED: U S E D; USER: U S E R; +USEROPTIONS: U S E R O P T I O N S; USING: U S I N G; VALIDATION: V A L I D A T I O N; VALID_XML: V A L I D UNDERLINE X M L; diff --git a/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 b/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 index 93267cdeaa..58b6428f33 100644 --- a/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 +++ b/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 @@ -3094,19 +3094,53 @@ shutdown_statement ; dbcc_statement - : DBCC name=dbcc_command ( LR_BRACKET expression_list RR_BRACKET )? (WITH dbcc_options)? SEMI? + : DBCC CHECKIDENT ( LR_BRACKET table_name_string ( (COMMA NORESEED) | (COMMA RESEED (COMMA MINUS? new_value=(DECIMAL | FLOAT))?) )? RR_BRACKET ) (WITH dbcc_options)? SEMI? + | DBCC name=dbcc_command ( LR_BRACKET expression_list RR_BRACKET )? (WITH dbcc_options)? SEMI? //These are dbcc commands with strange syntax that doesn't fit the regular dbcc syntax | DBCC SHRINKLOG ( LR_BRACKET SIZE EQUAL (constant_expression| id | DEFAULT) (KB | MB | GB | TB)? RR_BRACKET )? (WITH dbcc_options)? SEMI? - ; + ; dbcc_command - : ID | keyword + : ID + | CHECKDB + | CHECKFILEGROUP + | CHECKTABLE + | CLEANTABLE + | CLONEDATABASE + | DBREINDEX + | DROPCLEANBUFFERS + | FREEPROCCACHE + | FREESESSIONCACHE + | FREESYSTEMCACHE + | HELP + | INDEXDEFRAG + | INPUTBUFFER + | OPENTRAN + | OUTPUTBUFFER + | PROCCACHE + | SHOW_STATISTICS + | SHOWCONTIG + | SHRINKDATABASE + | SHRINKFILE + | SQLPERF + | TRACEOFF + | TRACEON + | TRACESTATUS + | UPDATEUSAGE + | USEROPTIONS ; dbcc_options : ID (COMMA ID)? ; + +table_name_string + : table = id + | char_string + ; + + execute_as_clause : (EXECUTE|EXEC) AS (CALLER | SELF | OWNER | char_string) ; @@ -4271,15 +4305,20 @@ keyword | CHANGETABLE | CHANGE_RETENTION | CHANGE_TRACKING + | CHECKDB + | CHECKFILEGROUP | CHECKSUM | CHECKSUM_AGG + | CHECKTABLE | CHECK_EXPIRATION | CHECK_POLICY | CLASSIFIER | CLASSIFIER_FUNCTION + | CLEANTABLE | CLEANUP | CLEANUP_POLICY - | CLEAR + | CLEAR + | CLONEDATABASE | CLUSTER | COALESCE | COLLECTION @@ -4343,6 +4382,7 @@ keyword | DATE_FORMAT | DAY | DAYS + | DBREINDEX | DB_CHAINING | DB_FAILOVER | DDL @@ -4376,6 +4416,7 @@ keyword | DISTRIBUTED_AGG | DISTRIBUTION | DOCUMENT + | DROPCLEANBUFFERS | DTC_SUPPORT | DYNAMIC | EDGE @@ -4449,6 +4490,9 @@ keyword | FORMAT_OPTIONS | FORMAT_TYPE | FORWARD_ONLY + | FREEPROCCACHE + | FREESESSIONCACHE + | FREESYSTEMCACHE | FULLSCAN | FULLTEXT | GB @@ -4477,6 +4521,7 @@ keyword | HASHED | HEALTHCHECKTIMEOUT | HEALTH_CHECK_TIMEOUT + | HELP | HIDDEN_RENAMED | HIGH | HINT @@ -4499,10 +4544,12 @@ keyword | INCLUDE_NULL_VALUES | INCREMENT | INCREMENTAL + | INDEXDEFRAG | INFINITE | INIT | INITIATOR | INPUT + | INPUTBUFFER | INSENSITIVE | INSERTED | INSTEAD @@ -4668,6 +4715,7 @@ keyword | ONLY | ON_FAILURE | OPENJSON + | OPENTRAN | OPEN_EXISTING | OPERATIONS | OPERATION_MODE @@ -4675,6 +4723,7 @@ keyword | OPTIMIZE | OUT | OUTPUT + | OUTPUTBUFFER | OVERRIDE | OWNER | OWNERSHIP @@ -4722,6 +4771,7 @@ keyword | PRIVATE | PRIVATE_KEY | PRIVILEGES + | PROCCACHE | PROCEDURE_CACHE | PROCEDURE_NAME | PROCESS @@ -4850,10 +4900,14 @@ keyword | SETS | SETTINGS | SHARE + | SHOWCONTIG | SHOWPLAN | SHOWPLAN_ALL | SHOWPLAN_TEXT | SHOWPLAN_XML + | SHOW_STATISTICS + | SHRINKDATABASE + | SHRINKFILE | SHRINKLOG | SID | SIGNATURE @@ -4876,6 +4930,7 @@ keyword | SQLDUMPERFLAGS | SQLDUMPERPATH | SQLDUMPERTIMEOUT + | SQLPERF | STALE_CAPTURE_POLICY_THRESHOLD | STALE_QUERY_THRESHOLD_DAYS | STANDBY @@ -4937,6 +4992,9 @@ keyword | TOTAL_COMPILE_CPU_TIME_MS | TOTAL_EXECUTION_CPU_TIME_MS | TRACE + | TRACEOFF + | TRACEON + | TRACESTATUS | TRACKING | TRACK_CAUSALITY | TRACK_COLUMNS_UPDATED @@ -4966,8 +5024,10 @@ keyword | UNMASK | UNSAFE | UOW + | UPDATEUSAGE | URL | USED + | USEROPTIONS | USE_TYPE_DEFAULT | USING | VALIDATION @@ -5103,8 +5163,8 @@ id | DOUBLE_QUOTE_ID // this is a double-quoted identifier in case of SET QUOTED_IDENTIFIER ON | SQUARE_BRACKET_ID | keyword - | DOLLAR_IDENTITY - | DOLLAR_ROWGUID + | DOLLAR_IDENTITY + | DOLLAR_ROWGUID | id colon_colon id ; diff --git a/contrib/babelfishpg_tsql/src/codegen.c b/contrib/babelfishpg_tsql/src/codegen.c index c6726ba373..d039264383 100644 --- a/contrib/babelfishpg_tsql/src/codegen.c +++ b/contrib/babelfishpg_tsql/src/codegen.c @@ -302,6 +302,7 @@ stmt_default_act(Walker_context *ctx, PLtsql_stmt *stmt) case PLTSQL_STMT_GRANTDB: case PLTSQL_STMT_GRANTSCHEMA: case PLTSQL_STMT_INSERT_BULK: + case PLTSQL_STMT_DBCC: case PLTSQL_STMT_SET_EXPLAIN_MODE: /* TSQL-only executable node */ case PLTSQL_STMT_SAVE_CTX: diff --git a/contrib/babelfishpg_tsql/src/iterative_exec.c b/contrib/babelfishpg_tsql/src/iterative_exec.c index 24ca677e44..6b0be3f33b 100644 --- a/contrib/babelfishpg_tsql/src/iterative_exec.c +++ b/contrib/babelfishpg_tsql/src/iterative_exec.c @@ -837,6 +837,9 @@ dispatch_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt) } exec_stmt_restore_ctx_partial(estate, (PLtsql_stmt_restore_ctx_partial *) stmt); break; + case PLTSQL_STMT_DBCC: + exec_stmt_dbcc(estate, (PLtsql_stmt_dbcc *) stmt); + break; case PLTSQL_STMT_KILL: exec_stmt_kill(estate, (PLtsql_stmt_kill *) stmt); break; diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index ef9c40a9e4..a30afeb1f4 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -10,6 +10,7 @@ #include "executor/tstoreReceiver.h" #include "nodes/parsenodes.h" #include "utils/acl.h" +#include "storage/lmgr.h" #include "storage/procarray.h" #include "pltsql_bulkcopy.h" #include "table_variable_mvcc.h" @@ -53,6 +54,7 @@ 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); +static int exec_stmt_dbcc(PLtsql_execstate *estate, PLtsql_stmt_dbcc *stmt); extern Datum pltsql_inline_handler(PG_FUNCTION_ARGS); static char *transform_tsql_temp_tables(char *dynstmt); @@ -91,7 +93,7 @@ extern void pltsql_commit_not_required_impl_txn(PLtsql_execstate *estate); int execute_batch(PLtsql_execstate *estate, char *batch, InlineCodeBlockArgs *args, List *params); Oid get_role_oid(const char *rolename, bool missing_ok); bool is_member_of_role(Oid member, Oid role); - +void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt); extern PLtsql_function *find_cached_batch(int handle); extern SPIPlanPtr prepare_stmt_exec(PLtsql_execstate *estate, PLtsql_function *func, PLtsql_stmt_exec *stmt, bool keepplan); @@ -235,6 +237,9 @@ exec_tsql_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt, PLtsql_stmt *save_es rc = exec_stmt_insert_bulk(estate, (PLtsql_stmt_insert_bulk *) stmt); break; + case PLTSQL_STMT_DBCC: + rc = exec_stmt_dbcc(estate, (PLtsql_stmt_dbcc *) stmt); + break; default: estate->err_stmt = save_estmt; elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type); @@ -3113,6 +3118,359 @@ exec_stmt_insert_bulk(PLtsql_execstate *estate, PLtsql_stmt_insert_bulk *stmt) return PLTSQL_RC_OK; } + +int exec_stmt_dbcc(PLtsql_execstate *estate, PLtsql_stmt_dbcc *stmt) +{ + switch (stmt->dbcc_stmt_type) + { + case PLTSQL_DBCC_CHECKIDENT: + exec_stmt_dbcc_checkident(stmt); + break; + default: + Assert(0); + } + return PLTSQL_RC_OK; +} + + +void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) +{ + struct dbcc_checkident dbcc_stmt = stmt->dbcc_stmt_data.dbcc_checkident; + Relation rel; + TupleDesc tupdesc; + char *db_name = NULL; + char *max_identity_value_str = NULL; + char *query = NULL; + char *attname; + char *token; + const char *schema_name; + const char *nsp_name; + const char *user; + const char *guest_role_name; + const char *dbo_role_name; + const char *login; + int64 max_identity_value = 0; + int64 cur_identity_value = 0; + int attnum; + int rc = 0; + int64 reseed_value = 0; + Oid nsp_oid; + Oid table_oid; + Oid seqid = InvalidOid; + Oid current_user_id = GetUserId(); + volatile bool cur_value_is_null = true; + bool login_is_db_owner; + char message[200]; + bool is_float_value; + bool is_cross_db = false; + + + if(dbcc_stmt.new_reseed_value) + { + /* If float value is passed as reseed_value, only part before decimal is considered */ + is_float_value = strchr(dbcc_stmt.new_reseed_value, '.') != NULL; + + if (is_float_value) + { + if (dbcc_stmt.new_reseed_value[0] == '.' || + (dbcc_stmt.new_reseed_value[0] == '-' && dbcc_stmt.new_reseed_value[1] == '.')) + reseed_value = 0; + else + { + token = strtok(dbcc_stmt.new_reseed_value, "."); + reseed_value = pg_strtoint64(token); + pfree(token); + } + } + else + reseed_value = pg_strtoint64(dbcc_stmt.new_reseed_value); + } + + db_name = get_cur_db_name(); + if (dbcc_stmt.db_name) + { + if (!DbidIsValid(get_db_id(dbcc_stmt.db_name))) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("database \"%s\" does not exist", dbcc_stmt.db_name))); + } + if (pg_strncasecmp(db_name, dbcc_stmt.db_name, NAMEDATALEN) != 0) + { + is_cross_db = true; + pfree(db_name); + db_name = pstrdup(dbcc_stmt.db_name); + } + } + + user = get_user_for_database(db_name); + login_is_db_owner = 0 == strncmp(GetUserNameFromId(GetSessionUserId(), false), + get_owner_of_db(db_name), NAMEDATALEN); + + /* Raise an error if the login does not have access to the database */ + if(is_cross_db) + { + if (user) + SetCurrentRoleId(GetSessionUserId(), false); + else + { + login = GetUserNameFromId(GetSessionUserId(), false); + pfree(db_name); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("The server principal \"%s\" is not able to access " + "the database \"%s\" under the current security context", + login, dbcc_stmt.db_name))); + } + } + + /* get physical schema name from logical schema name */ + if (dbcc_stmt.schema_name) + { + schema_name = dbcc_stmt.schema_name; + nsp_name = get_physical_schema_name(db_name, dbcc_stmt.schema_name); + } + else + { + /* + * If schema_name is not provided, find default schema for current user + * and get physical schema name + */ + guest_role_name = get_guest_role_name(db_name); + dbo_role_name = get_dbo_role_name(db_name); + + /* user will never be null here as cross-db calls are already handled */ + Assert(user != NULL); + + schema_name = get_authid_user_ext_schema_name((const char *) db_name, user); + if ((dbo_role_name && strcmp(user, dbo_role_name) == 0)) + { + nsp_name = get_dbo_schema_name(db_name); + } + else if ((guest_role_name && strcmp(user, guest_role_name) == 0)) + { + nsp_name = get_guest_schema_name(db_name); + } + else + { + nsp_name = get_physical_schema_name(db_name, schema_name); + } + } + pfree(db_name); + + /* + * get schema oid from physical schema name, it will return InvalidOid if + * user don't have lookup access + */ + nsp_oid = get_namespace_oid(nsp_name, false); + + if(!OidIsValid(nsp_oid)) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("schema \"%s\" does not exist", schema_name))); + } + + /* Permission check */ + if (!(pg_namespace_ownercheck(nsp_oid, GetUserId()) || + has_privs_of_role(GetSessionUserId(), get_role_oid("sysadmin", false)) || + login_is_db_owner)) + aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SCHEMA, nsp_name); + + table_oid = get_relname_relid(dbcc_stmt.table_name, nsp_oid); + if(!OidIsValid(table_oid)) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("relation \"%s\" does not exist", dbcc_stmt.table_name))); + } + + rel = RelationIdGetRelation(table_oid); + tupdesc = RelationGetDescr(rel); + + /* Find Identity column in table and associated sequence */ + for (attnum = 0; attnum < tupdesc->natts; attnum++) + { + Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum); + + if (attr->attidentity) + { + attname = NameStr(attr->attname); + seqid = getIdentitySequence(table_oid, attnum + 1, false); + break; + } + } + + RelationClose(rel); + + if (!OidIsValid(seqid)) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("'%s.%s' does not contain an identity column.", + nsp_name, dbcc_stmt.table_name))); + } + + PG_TRY(); + { + cur_identity_value = DirectFunctionCall1(pg_sequence_last_value, + ObjectIdGetDatum(seqid)); + cur_value_is_null = false; + } + PG_CATCH(); + { + FlushErrorState(); + } + PG_END_TRY(); + + PG_TRY(); + { + /* + * Acquiring an AccessExclusiveLock on the table is essential when + * reseeding the identity current value to new_ressed_value to + * ensure concurrency control. + */ + if(dbcc_stmt.new_reseed_value) + { + LockRelationOid(table_oid, AccessExclusiveLock); + } + else + { + LockRelationOid(table_oid, ShareLock); + } + + /* + * If cur_value_is_null is true, then the function pg_sequence_last_value + * has returned a NULL value, which means either no rows have been + * inserted into the table yet, or TRUNCATE TABLE command has been used + * to delete all rows. In this case, after DBCC CHECKIDENT the next + * row inserted will have new_reseed_value as the identity value. + */ + if (cur_value_is_null) + { + if (dbcc_stmt.new_reseed_value) + { + snprintf(message, sizeof(message), "Checking identity information: current identity value 'NULL'.\n"); + + DirectFunctionCall3(setval3_oid, + ObjectIdGetDatum(seqid), + Int64GetDatum(reseed_value), + BoolGetDatum(false)); + } + else + { + snprintf(message, sizeof(message), "Checking identity information: current identity value 'NULL', current column value 'NULL'.\n"); + } + } + + else + { + if (dbcc_stmt.new_reseed_value) + { + /* + * Print informational messages if NO_INFOMSGS is not passed as a + * DBCC command option. + */ + if (!dbcc_stmt.no_infomsgs) + snprintf(message, sizeof(message), "Checking identity information: current identity value '%ld'.\n", cur_identity_value); + + DirectFunctionCall2(setval_oid, + ObjectIdGetDatum(seqid), + Int64GetDatum(reseed_value)); + } + else + { + SPI_connect(); + query = psprintf("SELECT MAX(%s) FROM %s.%s", attname, + schema_name, dbcc_stmt.table_name); + rc = SPI_execute(query, true, 0); + + if (rc != SPI_OK_SELECT) + elog(ERROR, "SPI_execute failed: %s", SPI_result_code_string(rc)); + + max_identity_value_str = SPI_getvalue(SPI_tuptable->vals[0], + SPI_tuptable->tupdesc, 1); + + SPI_freetuptable(SPI_tuptable); + + if(max_identity_value_str) + max_identity_value = pg_strtoint64(max_identity_value_str); + + if (!dbcc_stmt.no_infomsgs) + snprintf(message, sizeof(message), "Checking identity information: current identity value '%ld', current column value '%s'.\n", + cur_identity_value, + max_identity_value_str ? max_identity_value_str : "NULL"); + + /* + * RESEED option only resets the identity column value if the + * current identity value for a table is less than the maximum + * identity value stored in the identity column. + */ + if (dbcc_stmt.is_reseed && max_identity_value_str && + cur_identity_value < max_identity_value) + { + DirectFunctionCall2(setval_oid, + ObjectIdGetDatum(seqid), + Int64GetDatum(max_identity_value)); + } + } + } + + if (is_cross_db) + SetCurrentRoleId(current_user_id, false); + } + PG_CATCH(); + { + if (is_cross_db) + SetCurrentRoleId(current_user_id, false); + + if(query) + pfree(query); + if (max_identity_value_str) + pfree(max_identity_value_str); + + if(rc != 0) + { + SPI_finish(); + /* running 'SELECT MAX' query above holds a AccessShareLock on table, we want to unlock that as well */ + UnlockRelationOid(table_oid, AccessShareLock); + } + if(!dbcc_stmt.new_reseed_value) + { + UnlockRelationOid(table_oid, ShareLock); + } + + PG_RE_THROW(); + } + PG_END_TRY(); + + if(query) + pfree(query); + if (max_identity_value_str) + pfree(max_identity_value_str); + if(rc != 0) + { + SPI_finish(); + /* running 'SELECT MAX' query above holds a AccessShareLock on table, we want to unlock that as well */ + UnlockRelationOid(table_oid, AccessShareLock); + } + + if(!dbcc_stmt.new_reseed_value) + { + UnlockRelationOid(table_oid, ShareLock); + } + + if (!dbcc_stmt.no_infomsgs) + { + strcat(message, "DBCC execution completed. If DBCC printed error messages, contact your system administrator."); + /* send message to user */ + if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->send_info) + ((*pltsql_protocol_plugin_ptr)->send_info) (0, 1, 0, message, 0); + } + +} + + uint64 execute_bulk_load_insert(int ncol, int nrow, Datum *Values, bool *Nulls) diff --git a/contrib/babelfishpg_tsql/src/pl_funcs-2.c b/contrib/babelfishpg_tsql/src/pl_funcs-2.c index c095a74a9f..bc8975d0a9 100644 --- a/contrib/babelfishpg_tsql/src/pl_funcs-2.c +++ b/contrib/babelfishpg_tsql/src/pl_funcs-2.c @@ -513,6 +513,11 @@ free_stmt2(PLtsql_stmt *stmt) { break; } + case PLTSQL_STMT_DBCC: + { + /* Nothing to free */ + break; + } default: elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type); break; @@ -541,6 +546,7 @@ void dump_stmt_try_catch(PLtsql_stmt_try_catch *stmt_try_catch); void dump_stmt_query_set(PLtsql_stmt_query_set *query_set); void dump_stmt_exec_batch(PLtsql_stmt_exec_batch *exec_batch); void get_grantees_names(List *grantees, StringInfo grantees_names); +void dump_stmt_dbcc(PLtsql_stmt_dbcc *stmt_dbcc); void dump_stmt_print(PLtsql_stmt_print *stmt_print) @@ -679,6 +685,22 @@ dump_stmt_insert_bulk(PLtsql_stmt_insert_bulk *stmt_insert_bulk) printf("INSERT BULK %s\n", stmt_insert_bulk->table_name); } +void +dump_stmt_dbcc(PLtsql_stmt_dbcc *stmt_dbcc) +{ + printf("DBCC "); + switch (stmt_dbcc->dbcc_stmt_type) + { + case PLTSQL_DBCC_CHECKIDENT: + printf("CHECKIDENT"); + break; + default: + elog(ERROR, "unrecognized dbcc statement type: %d", stmt_dbcc->dbcc_stmt_type); + break; + } + printf(" STATEMENT\n"); +} + void dump_stmt_try_catch(PLtsql_stmt_try_catch *stmt_try_catch) { @@ -811,6 +833,11 @@ dump_stmt2(PLtsql_stmt *stmt) dump_stmt_insert_bulk((PLtsql_stmt_insert_bulk *) stmt); break; } + case PLTSQL_STMT_DBCC: + { + dump_stmt_dbcc((PLtsql_stmt_dbcc *) stmt); + break; + } default: elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type); break; diff --git a/contrib/babelfishpg_tsql/src/pl_funcs.c b/contrib/babelfishpg_tsql/src/pl_funcs.c index a6cf523b03..9bf8a20010 100644 --- a/contrib/babelfishpg_tsql/src/pl_funcs.c +++ b/contrib/babelfishpg_tsql/src/pl_funcs.c @@ -344,6 +344,8 @@ pltsql_stmt_typename(PLtsql_stmt *stmt) return "RESTORE_CONTEXT_FULL"; case PLTSQL_STMT_RESTORE_CTX_PARTIAL: return "RESTORE_CONTEXT_PARTIAL"; + case PLTSQL_STMT_DBCC: + return "DBCC"; default: return "Add try catch"; } diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index e5cc3adfcb..622a57a2ec 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -116,6 +116,12 @@ typedef enum PLtsql_promise_type PLTSQL_PROMISE_TG_TAG } PLtsql_promise_type; + +typedef enum PLtsql_dbcc_stmt_type +{ + PLTSQL_DBCC_CHECKIDENT +} PLtsql_dbcc_stmt_type; + /* * Variants distinguished in PLtsql_type structs */ @@ -186,6 +192,7 @@ typedef enum PLtsql_stmt_type PLTSQL_STMT_RESTORE_CTX_PARTIAL, PLTSQL_STMT_INSERT_BULK, PLTSQL_STMT_GRANTDB, + PLTSQL_STMT_DBCC, PLTSQL_STMT_GRANTSCHEMA } PLtsql_stmt_type; @@ -933,6 +940,34 @@ typedef struct PLtsql_stmt_insert_bulk bool keep_nulls; } PLtsql_stmt_insert_bulk; +/* + * DBCC statement type + */ +typedef union PLtsql_dbcc_stmt_data +{ + struct dbcc_checkident + { + char *db_name; + char *schema_name; + char *table_name; + bool is_reseed; + char *new_reseed_value; + bool no_infomsgs; + } dbcc_checkident; + +} PLtsql_dbcc_stmt_data; + +/* + * DBCC statement + */ +typedef struct PLtsql_stmt_dbcc +{ + PLtsql_stmt_type cmd_type; + int lineno; + PLtsql_dbcc_stmt_type dbcc_stmt_type; + PLtsql_dbcc_stmt_data dbcc_stmt_data; +} PLtsql_stmt_dbcc; + /* * RETURN statement */ diff --git a/contrib/babelfishpg_tsql/src/stmt_walker.c b/contrib/babelfishpg_tsql/src/stmt_walker.c index b33cb42234..7bc1bbd01b 100644 --- a/contrib/babelfishpg_tsql/src/stmt_walker.c +++ b/contrib/babelfishpg_tsql/src/stmt_walker.c @@ -108,6 +108,7 @@ stmt_walker(PLtsql_stmt *stmt, WalkerFunc walker, void *context) case PLTSQL_STMT_SET_EXPLAIN_MODE: case PLTSQL_STMT_GRANTDB: case PLTSQL_STMT_GRANTSCHEMA: + case PLTSQL_STMT_DBCC: break; /* TSQL-only executable node */ case PLTSQL_STMT_SAVE_CTX: @@ -206,6 +207,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(DBCC, dbcc) DISPATCH(GRANTSCHEMA, grantschema) /* TSQL-only executable node */ diff --git a/contrib/babelfishpg_tsql/src/stmt_walker.h b/contrib/babelfishpg_tsql/src/stmt_walker.h index 98f143c5eb..36efeeb289 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_dbcc_act) ACTION_SIGNITURE(dbcc); typedef bool (*Stmt_grantschema_act) ACTION_SIGNITURE(grantschema); /* TSQL-only executable node */ @@ -138,6 +139,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_dbcc_act dbcc_act; Stmt_grantschema_act grantschema_act; /* TSQL-only executable node */ diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index db21d4f1b1..aa2a12d2c8 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -112,6 +112,7 @@ std::vector makeAnother(TSqlParser::Another_statementContext *ctx PLtsql_stmt *makeExecBodyBatch(TSqlParser::Execute_body_batchContext *ctx); PLtsql_stmt *makeExecuteProcedure(ParserRuleContext *ctx, std::string call_type); PLtsql_stmt *makeInsertBulkStatement(TSqlParser::Dml_statementContext *ctx); +PLtsql_stmt *makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx); PLtsql_stmt *makeSetExplainModeStatement(TSqlParser::Set_statementContext *ctx, bool is_explain_only); PLtsql_expr *makeTsqlExpr(const std::string &fragment, bool addSelect); PLtsql_expr *makeTsqlExpr(ParserRuleContext *ctx, bool addSelect); @@ -2118,6 +2119,19 @@ class tsqlBuilder : public tsqlCommonMutator clear_rewritten_query_fragment(); } + void enterDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) override + { + if (ctx->CHECKIDENT()) + graft(makeDbccCheckidentStatement(ctx), peekContainer()); + + clear_rewritten_query_fragment(); + } + + void exitDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) override + { + // TO-DO + } + ////////////////////////////////////////////////////////////////////////////// // Special handling of non-statement context ////////////////////////////////////////////////////////////////////////////// @@ -5089,7 +5103,6 @@ makeInsertBulkStatement(TSqlParser::Dml_statementContext *ctx) } } } - attachPLtsql_fragment(ctx, (PLtsql_stmt *) stmt); return (PLtsql_stmt *) stmt; } @@ -5870,6 +5883,108 @@ makeExecuteProcedure(ParserRuleContext *ctx, std::string call_type) return (PLtsql_stmt *) result; } +PLtsql_stmt* +makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx) +{ + PLtsql_stmt_dbcc *stmt = (PLtsql_stmt_dbcc *) palloc0(sizeof(*stmt)); + + std::string new_reseed_value; + std::string input_str; + int i; + char *db_name = NULL; + char *schema_name = NULL; + char *table_name = NULL; + char *input_str_to_split; + char **splited_object_name; + bool is_reseed = true; + bool no_infomsgs = false; + + stmt->cmd_type = PLTSQL_STMT_DBCC; + stmt->dbcc_stmt_type = PLTSQL_DBCC_CHECKIDENT; + + if (ctx->table_name_string()) + { + if(ctx->table_name_string()->table) + { + input_str = stripQuoteFromId(ctx->table_name_string()->table); + } + if (ctx->table_name_string()->char_string()) + { + input_str = ctx->table_name_string()->char_string()->STRING()->getSymbol()->getText(); + if (input_str.length() <= 2) + throw PGErrorWrapperException(ERROR, ERRCODE_INVALID_PARAMETER_VALUE, + "Parameter 1 is incorrect for this DBCC statement", + getLineAndPos(ctx->table_name_string())); + input_str = input_str.substr(1, input_str.length()-2); + } + if (ctx->RESEED()) + { + if (ctx->new_value) + { + if(ctx->MINUS()) + stmt->dbcc_stmt_data.dbcc_checkident.new_reseed_value = pstrdup((ctx->new_value->getText().insert(0,"-")).c_str()); + else + stmt->dbcc_stmt_data.dbcc_checkident.new_reseed_value = pstrdup((ctx->new_value->getText()).c_str()); + } + } + else if (ctx->NORESEED()) + { + is_reseed = false; + } + + if(ctx->dbcc_options()) + { + if (pg_strcasecmp(::getFullText(ctx->dbcc_options()).c_str(), "NO_INFOMSGS") == 0) + { + no_infomsgs = true; + } + else + { + throw PGErrorWrapperException(ERROR, ERRCODE_SYNTAX_ERROR, + format_errmsg("\'%s\' is not a recognized option", + ::getFullText(ctx->dbcc_options()).c_str()), + getLineAndPos(ctx->dbcc_options())); + } + } + } + + input_str_to_split = pstrdup(input_str.c_str()); + + /* strip trailing whitespace from input string */ + i = strlen(input_str_to_split); + while (i > 0 && isspace((unsigned char) input_str_to_split[i - 1])) + input_str_to_split[--i] = '\0'; + + splited_object_name = split_object_name(input_str_to_split); + db_name = !strcmp(splited_object_name[1], "")? NULL : splited_object_name[1]; + schema_name = !strcmp(splited_object_name[2], "")? NULL : splited_object_name[2]; + table_name = !strcmp(splited_object_name[3], "")? NULL : splited_object_name[3]; + + if(db_name) + { + stmt->dbcc_stmt_data.dbcc_checkident.db_name = pstrdup(downcase_truncate_identifier(db_name, strlen(db_name), true)); + pfree(db_name); + } + if(schema_name) + { + stmt->dbcc_stmt_data.dbcc_checkident.schema_name = pstrdup(downcase_truncate_identifier(schema_name, strlen(schema_name), true)); + pfree(schema_name); + } + if(table_name) + { + stmt->dbcc_stmt_data.dbcc_checkident.table_name = pstrdup(downcase_truncate_identifier(table_name, strlen(table_name), true)); + pfree(table_name); + } + stmt->dbcc_stmt_data.dbcc_checkident.is_reseed = is_reseed; + stmt->dbcc_stmt_data.dbcc_checkident.no_infomsgs = no_infomsgs; + + pfree(splited_object_name); + pfree(input_str_to_split); + + attachPLtsql_fragment(ctx, (PLtsql_stmt *) stmt); + return (PLtsql_stmt *) stmt; +} + // helper function to create target row PLtsql_row * create_select_target_row(const char *refname, size_t nfields, int lineno) diff --git a/contrib/babelfishpg_tsql/src/tsqlNodes.h b/contrib/babelfishpg_tsql/src/tsqlNodes.h index cb0195dce0..14139a7273 100644 --- a/contrib/babelfishpg_tsql/src/tsqlNodes.h +++ b/contrib/babelfishpg_tsql/src/tsqlNodes.h @@ -49,6 +49,7 @@ typedef enum pltsql_stmt_type PLTSQL_STMT_DEALLOCATE, PLTSQL_STMT_INSERT_BULK, PLTSQL_STMT_GRANTDB, + PLTSQL_STMT_DBCC, PLTSQL_STMT_GRANTSCHEMA } PLtsql_stmt_type; diff --git a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp index a6897b1598..81cae20279 100644 --- a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp @@ -150,7 +150,7 @@ class TsqlUnsupportedFeatureHandlerImpl : public TsqlUnsupportedFeatureHandler antlrcpp::Any visitReconfigure_statement(TSqlParser::Reconfigure_statementContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_RECONFIGURE, "RECONFIGURE", getLineAndPos(ctx)); return visitChildren(ctx); } antlrcpp::Any visitShutdown_statement(TSqlParser::Shutdown_statementContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_SHUTDOWN, "SHUTDOWN", getLineAndPos(ctx)); return visitChildren(ctx); } - antlrcpp::Any visitDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_DBCC, "DBCC", getLineAndPos(ctx)); return visitChildren(ctx); } + antlrcpp::Any visitDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) override; antlrcpp::Any visitBackup_statement(TSqlParser::Backup_statementContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_BACKUP, "BACKUP", getLineAndPos(ctx)); return visitChildren(ctx); } antlrcpp::Any visitRestore_statement(TSqlParser::Restore_statementContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_RESTORE, "RESTORE", getLineAndPos(ctx)); return visitChildren(ctx); } antlrcpp::Any visitCheckpoint_statement(TSqlParser::Checkpoint_statementContext *ctx) override; @@ -1255,6 +1255,29 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitTransaction_statement(TSql return visitChildren(ctx); } +antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) +{ + + if (ctx->dbcc_command()) + { + if (ctx->dbcc_command()->ID()) + { + throw PGErrorWrapperException(ERROR, ERRCODE_SYNTAX_ERROR, + "Incorrect DBCC statement. Check the documentation for the " + "correct DBCC syntax and options.", + getLineAndPos(ctx->dbcc_command())); + } + else + { + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, + format_errmsg("DBCC %s is not yet supported in Babelfish", + ::getFullText(ctx->dbcc_command()).c_str()), + getLineAndPos(ctx->dbcc_command())); + } + } + return visitChildren(ctx); +} + antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitSecurity_statement(TSqlParser::Security_statementContext *ctx) { if (ctx->execute_as_statement()) diff --git a/test/JDBC/expected/BABEL-3201-vu-cleanup.out b/test/JDBC/expected/BABEL-3201-vu-cleanup.out new file mode 100644 index 0000000000..455056962a --- /dev/null +++ b/test/JDBC/expected/BABEL-3201-vu-cleanup.out @@ -0,0 +1,59 @@ +DROP TABLE babel_3201_t_int; +GO + +DROP TABLE babel_dbcc_check_t1; +GO + +DROP TABLE [babel_dbcc_check_t2 .with .dot_an_spaces]; +GO + +DROP TABLE [babel_dbcc_check_schema .with .dot_and_spaces]."babel_dbcc_check_t3 .with .dot_and_spaces"; +GO + +DROP SCHEMA [babel_dbcc_check_schema .with .dot_and_spaces] +GO + +DROP TABLE babel_3201_t_tinyint; +GO + +DROP TABLE babel_3201_t_smallint; +GO + +DROP TABLE babel_3201_t_bigint; +GO + +DROP TABLE babel_3201_t_numeric; +GO + +DROP TABLE babel_3201_t_decimal; +GO + +DROP TABLE babel_3201_t1; +GO + +DROP TABLE babel_3201_t2; +GO + +DROP TABLE babel_3201_sch1.babel_3201_t2; +GO + +DROP TABLE babel_3201_test_locks; +GO + +DROP PROCEDURE babel_3201_proc1; +GO + +DROP PROCEDURE babel_3201_proc2; +GO + +DROP LOGIN babel_3201_log1; +GO + +DROP LOGIN babel_3201_test_locks; +GO + +DROP SCHEMA babel_3201_sch1; +GO + +DROP DATABASE babel_3201_db1; +GO diff --git a/test/JDBC/expected/BABEL-3201-vu-prepare.out b/test/JDBC/expected/BABEL-3201-vu-prepare.out new file mode 100644 index 0000000000..4bef6e6006 --- /dev/null +++ b/test/JDBC/expected/BABEL-3201-vu-prepare.out @@ -0,0 +1,163 @@ +CREATE SCHEMA babel_3201_sch1; +GO + +CREATE TABLE babel_3201_sch1.babel_3201_t2(a varchar(20), b int identity); +GO + +CREATE TABLE babel_3201_t_int( a int identity, b int); +GO + +CREATE TABLE babel_dbcc_check_t1 (a int identity, b int); +GO + +CREATE TABLE [babel_dbcc_check_t2 .with .dot_an_spaces] (a int identity, b int); +GO + +CREATE SCHEMA [babel_dbcc_check_schema .with .dot_and_spaces] +GO + +CREATE TABLE [babel_dbcc_check_schema .with .dot_and_spaces]."babel_dbcc_check_t3 .with .dot_and_spaces" (a int identity, b int); +GO + +CREATE TABLE babel_3201_t_tinyint( a tinyint identity(5,1), b int); +GO + +CREATE TABLE babel_3201_t_smallint( a smallint identity(10,10), b int); +GO + +CREATE TABLE babel_3201_t_bigint( a bigint identity(3,3), b int); +GO + +CREATE TABLE babel_3201_t_numeric( a numeric identity(4,2), b int); +GO + +CREATE TABLE babel_3201_t_decimal( a decimal identity(7,3), b int); +GO + +CREATE TABLE babel_3201_t1( a int identity, b int); +GO + +CREATE TABLE babel_3201_t2( a int, b int); +GO + +CREATE TABLE babel_3201_test_locks (a int identity, b int); +GO + +INSERT INTO babel_3201_test_locks VALUES (10); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_sch1.babel_3201_t2 VALUES ('string 1'); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_tinyint VALUES (5); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_tinyint VALUES (6); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_tinyint VALUES (7); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_smallint VALUES (5); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_smallint VALUES (6); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_smallint VALUES (7); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_int VALUES (5); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_int VALUES (6); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_int VALUES (7); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_bigint VALUES (5); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_bigint VALUES (6); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_bigint VALUES (6); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_numeric VALUES (5); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_numeric VALUES (6); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_numeric VALUES (7); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_decimal VALUES (5); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_decimal VALUES (6); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_decimal VALUES (7); +GO +~~ROW COUNT: 1~~ + + +CREATE PROCEDURE babel_3201_proc1 +AS +DBCC CHECKIDENT(babel_3201_t_tinyint, RESEED, 30) +GO + +CREATE PROCEDURE babel_3201_proc2 +AS +DBCC CHECKIDENT(babel_3201_t_tinyint, RESEED, 257) +GO + +CREATE LOGIN babel_3201_log1 WITH PASSWORD='12345678'; +GO + +CREATE LOGIN babel_3201_test_locks WITH PASSWORD='123456'; +GO + +ALTER SERVER ROLE sysadmin ADD MEMBER babel_3201_test_locks +GO diff --git a/test/JDBC/expected/BABEL-3201-vu-verify.out b/test/JDBC/expected/BABEL-3201-vu-verify.out new file mode 100644 index 0000000000..762aed89fd --- /dev/null +++ b/test/JDBC/expected/BABEL-3201-vu-verify.out @@ -0,0 +1,813 @@ +DBCC CHECKIDENT(babel_3201_t_int, NORESEED); +GO + +-- test with mixed case in table name +DBCC CHECKIDENT(BABEL_3201_t_iNt, NORESEED); +GO +DBCC CHECKIDENT(BABEL_3201_T_INT, NORESEED); +GO + +-- test with table in quotes (+mixed cases) +DBCC CHECKIDENT('babel_3201_t_int', NORESEED); +GO +DBCC CHECKIDENT('baBEl_3201_T_inT', NORESEED); +GO + +-- test with table in brackets (+mixed case) +DBCC CHECKIDENT([babel_3201_t_int], NORESEED); +GO +DBCC CHECKIDENT([baBEL_3201_t_InT], NORESEED); +GO + +-- test with table in brackets with quotes (+mixed case) +DBCC CHECKIDENT('[babel_3201_t_int]', NORESEED); +GO +DBCC CHECKIDENT('[BABEL_3201_t_int]', NORESEED); +GO + +-- test when trailing space - should work +DBCC CHECKIDENT('babel_3201_t_int ', NORESEED); +GO +DBCC CHECKIDENT('babel_3201_T_INT ', NORESEED); +GO + +-- test when leading space - should throw error +DBCC CHECKIDENT(' babel_3201_t_int ', NORESEED); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation " babel_3201_t_int" does not exist)~~ + + +-- test when table name is empty in quotes +DBCC CHECKIDENT('', NORESEED); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Parameter 1 is incorrect for this DBCC statement)~~ + + +-- same as DBCC CHECKIDENT(, RESEED), identity value is not changed +-- if current identity value for a table is less than the maximum identity value +-- stored in the identity column +DBCC CHECKIDENT(babel_3201_t_int); +GO + + +DBCC CHECKIDENT(babel_3201_t_int, RESEED); +GO + +INSERT INTO babel_3201_t_int VALUES (8); +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM babel_3201_t_int; +GO +~~START~~ +int#!#int +1#!#5 +2#!#6 +3#!#7 +4#!#8 +~~END~~ + + +DBCC CHECKIDENT('babel_3201_sch1.babel_3201_t2'); +GO + +-- Set identity value to 5 which is less than the maximum value(which is 9) of the identity +-- column, using RESEED option in this case should will reset the identity value +-- to maximum value of the identity column. Value inserted in next insert will +-- be (max_identity_col_value + increament). +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, 5); +GO +INSERT INTO babel_3201_t_bigint VALUES (8); +GO +~~ROW COUNT: 1~~ + +SELECT * from babel_3201_t_bigint; +GO +~~START~~ +bigint#!#int +3#!#5 +6#!#6 +9#!#6 +8#!#8 +~~END~~ + + +-- This will reset the current identity value(currently 8) to the maximum value of the identity column (currently 9) +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED); +GO +INSERT INTO babel_3201_t_bigint VALUES (9); +GO +~~ROW COUNT: 1~~ + +SELECT * from babel_3201_t_bigint; +GO +~~START~~ +bigint#!#int +3#!#5 +6#!#6 +9#!#6 +8#!#8 +12#!#9 +~~END~~ + + +-- no rows have been inserted in the table; both current identity value current +-- column value should be NULL (TO-DO) +BEGIN TRAN; +DBCC CHECKIDENT(babel_3201_t1, NORESEED); +SELECT * FROM babel_3201_t1; +COMMIT; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value 'NULL', current column value 'NULL'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~START~~ +int#!#int +~~END~~ + + +BEGIN TRAN; +DBCC CHECKIDENT(babel_3201_t1, RESEED); +SELECT * FROM babel_3201_t1; +COMMIT; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value 'NULL', current column value 'NULL'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~START~~ +int#!#int +~~END~~ + + +-- current identity value should be NULL (TO-DO), identity value inserted in +-- next INSERT operation should be new_reseed_value. +BEGIN TRAN; +DBCC CHECKIDENT(babel_3201_t1, RESEED, 5); +INSERT INTO babel_3201_t1 VALUES (50); +COMMIT; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value 'NULL'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~ROW COUNT: 1~~ + + +BEGIN TRAN; +DBCC CHECKIDENT(babel_3201_t1, NORESEED); +select * from babel_3201_t1; +COMMIT; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value '5', current column value '5'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~START~~ +int#!#int +5#!#50 +~~END~~ + + +-- Remove all rows in table using TRUNCATE TABLE, Identity value will become NULL +-- next insert operation should be default identity value if no new_reseed_value is provided. +TRUNCATE TABLE babel_3201_t_int; +GO +dbcc checkident(babel_3201_t_int, NORESEED); +GO +INSERT INTO babel_3201_t_int values(15); +GO +~~ROW COUNT: 1~~ + + +select * from babel_3201_t_int; +-- Remove all rows in table using TRUNCATE TABLE, identity value inserted in +-- next INSERT operation should be new_reseed_value. +TRUNCATE TABLE babel_3201_t_int; +GO +~~START~~ +int#!#int +1#!#15 +~~END~~ + +DBCC CHECKIDENT(babel_3201_t_int, RESEED, 10); +GO +INSERT INTO babel_3201_t_int VALUES (5); +GO +~~ROW COUNT: 1~~ + +SELECT * FROM babel_3201_t_int; +GO +~~START~~ +int#!#int +10#!#5 +~~END~~ + + + +-- Remove all rows in table using DELETE TABLE, identity value inserted in next +-- INSERT operation should be (new_reseed_value + increment). +DELETE FROM babel_3201_t_bigint; +GO +~~ROW COUNT: 5~~ + +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, 10); +GO +INSERT INTO babel_3201_t_bigint VALUES (5); +GO +~~ROW COUNT: 1~~ + +SELECT * FROM babel_3201_t_bigint; +GO +~~START~~ +bigint#!#int +13#!#5 +~~END~~ + + +-- Remove all rows in table using DELETE TABLE current identity will not become default identity value, +-- identity value inserted in next operation should use (default identity value + increament) if no new_reseed_value is provided. +DELETE FROM babel_3201_t_bigint; +GO +~~ROW COUNT: 1~~ + +dbcc checkident(babel_3201_t_bigint, NORESEED); +GO +INSERT INTO babel_3201_t_bigint VALUES (5); +GO +~~ROW COUNT: 1~~ + +SELECT * FROM babel_3201_t_bigint; +GO +~~START~~ +bigint#!#int +16#!#5 +~~END~~ + + +-- If some rows are present already in the table, identity value inserted in next +-- INSERT operation should be (new_reseed_value + increament) +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, 27); +GO +INSERT INTO babel_3201_t_bigint VALUES (32); +GO +~~ROW COUNT: 1~~ + +SELECT * FROM babel_3201_t_bigint; +GO +~~START~~ +bigint#!#int +16#!#5 +30#!#32 +~~END~~ + + +-- Incorrect DBCC command option +DBCC CHECKIDENT(babel_3201_t1) WITH NO_INFO; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'NO_INFO' is not a recognized option)~~ + + +-- Invalid parameter 1 +DBCC CHECKIDENT(5); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '5' at line 2 and character position 16)~~ + + +DBCC CHECKIDENT(babel_3201_t_int, RESEED, ) WITH NO_INFOMSGS; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near ')' at line 1 and character position 42)~~ + + +-- Invalid keyword +DBCC CHECKIDENT(babel_3201_t1, RESEE); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'RESEE' at line 2 and character position 31)~~ + + +-- Invalid datatype +DBCC CHECKIDENT(babel_3201_t1, RESEED, 1313abc); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'abc' at line 2 and character position 43)~~ + + +-- Unsupported DBCC command +DBCC CHECKTABLE(babel_3201_t1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: DBCC CHECKTABLE is not yet supported in Babelfish)~~ + + +-- Invalid DBCC command +DBCC FAKE_COMMAND(t1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Incorrect DBCC statement. Check the documentation for the correct DBCC syntax and options.)~~ + + +-- Database undefined +DBCC CHECKIDENT('fake_db.dbo.babel_3201_t1', NORESEED); +GO +~~ERROR (Code: 911)~~ + +~~ERROR (Message: database "fake_db" does not exist)~~ + + +-- Schema undefined +DBCC CHECKIDENT('fake_schema.babel_3201_t1', NORESEED); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: schema "master_fake_schema" does not exist)~~ + + +-- Table undefined +DBCC CHECKIDENT(fake_babel_3201_t1, RESEED); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "fake_babel_3201_t1" does not exist)~~ + + +-- Table does not have identity column +DBCC CHECKIDENT(babel_3201_t2, RESEED); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'master_dbo.babel_3201_t2' does not contain an identity column.)~~ + + +-- new_reseed_value as expression is not allowed +DBCC CHECKIDENT(babel_3201_t2, RESEED, 4+5); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '+' at line 2 and character position 40)~~ + + +-- new_reseed_value is out of tinyint datatype range +DBCC CHECKIDENT(babel_3201_t_tinyint, RESEED, 256); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value 256 is out of bounds for sequence "babel_3201_t_tinyint_a_seq" (5..255))~~ + + +DBCC CHECKIDENT(babel_3201_t_tinyint, RESEED, -1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value -1 is out of bounds for sequence "babel_3201_t_tinyint_a_seq" (5..255))~~ + + +-- new_reseed_value is out of smallint datatype range +DBCC CHECKIDENT(babel_3201_t_smallint, RESEED, 32768); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value 32768 is out of bounds for sequence "babel_3201_t_smallint_a_seq" (10..32767))~~ + + +DBCC CHECKIDENT(babel_3201_t_smallint, RESEED, -32769); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value -32769 is out of bounds for sequence "babel_3201_t_smallint_a_seq" (10..32767))~~ + + + +-- new_reseed_value is out of int datatype range +DBCC CHECKIDENT(babel_3201_t_int, RESEED, 2147483648); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value 2147483648 is out of bounds for sequence "babel_3201_t_int_a_seq" (1..2147483647))~~ + + +DBCC CHECKIDENT(babel_3201_t_int, RESEED, -2147483649); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value -2147483649 is out of bounds for sequence "babel_3201_t_int_a_seq" (1..2147483647))~~ + + +-- new_reseed_value is out of bigint datatype range +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, 9223372036854775808); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: value "9223372036854775808" is out of range for type bigint)~~ + + +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, -9223372036854775809); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: value "-9223372036854775809" is out of range for type bigint)~~ + + +-- numeric/decimal datatypes are internally converted to bigint, so allowed +-- range is same as that of bigint +DBCC CHECKIDENT(babel_3201_t_numeric, RESEED, 9223372036854775808); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: value "9223372036854775808" is out of range for type bigint)~~ + + +-- When new_reseed_value is a float value, only value before the decimal is used +DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 15.65); +GO + +-- When reseed_value is negative and zero, bbf currently does not support reseed to negative/zero value +dbcc checkident(babel_3201_t_decimal, reseed, -10) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value -10 is out of bounds for sequence "babel_3201_t_decimal_a_seq" (7..9223372036854775807))~~ + +dbcc checkident(babel_3201_t_decimal, reseed, 0) +Go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value 0 is out of bounds for sequence "babel_3201_t_decimal_a_seq" (7..9223372036854775807))~~ + +dbcc checkident(babel_3201_t_decimal, reseed, .123) +Go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value 0 is out of bounds for sequence "babel_3201_t_decimal_a_seq" (7..9223372036854775807))~~ + +dbcc checkident(babel_3201_t_decimal, reseed, -.123) +Go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value 0 is out of bounds for sequence "babel_3201_t_decimal_a_seq" (7..9223372036854775807))~~ + +dbcc checkident(babel_3201_t_decimal, reseed, .) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '.' at line 1 and character position 46)~~ + +dbcc checkident(babel_3201_t_decimal, reseed, -) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near ')' at line 1 and character position 47)~~ + +dbcc checkident(babel_3201_t_decimal, reseed, .-); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '.' at line 1 and character position 46)~~ + + +SELECT * FROM babel_3201_t_decimal; +GO +~~START~~ +bigint#!#int +7#!#5 +10#!#6 +13#!#7 +~~END~~ + + +begin tran; +DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 10); +INSERT INTO babel_3201_t_decimal VALUES (9); +commit; +go +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value '15'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~ROW COUNT: 1~~ + + +SELECT * FROM babel_3201_t_decimal; +GO +~~START~~ +bigint#!#int +7#!#5 +10#!#6 +13#!#7 +13#!#9 +~~END~~ + + +BEGIN TRAN; + DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 133ac); + INSERT INTO babel_3201_t_decimal VALUES (10); +COMMIT; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'ac' at line 2 and character position 53)~~ + + +SELECT * FROM babel_3201_t_decimal; +GO +~~START~~ +bigint#!#int +7#!#5 +10#!#6 +13#!#7 +13#!#9 +~~END~~ + + +BEGIN TRAN; + DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 20); + INSERT INTO babel_3201_t_decimal VALUES (11); +ROLLBACK; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value '13'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~ROW COUNT: 1~~ + + +-- Check current_identity value after tran rollback +-- babelfish does not support rolling-back dbcc changes after transection rollback. +-- Current identity value will be = reseed_value inside the rollbacked transection + increament = 20+3=23 +BEGIN TRAN; +dbcc checkident(babel_3201_t_decimal, noreseed); +SELECT * FROM babel_3201_t_decimal; +COMMIT; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value '23', current column value '13'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~START~~ +bigint#!#int +7#!#5 +10#!#6 +13#!#7 +13#!#9 +~~END~~ + + +EXEC babel_3201_proc1; +GO + +INSERT INTO babel_3201_t_tinyint VALUES (10); +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM babel_3201_t_tinyint; +GO +~~START~~ +smallint#!#int +5#!#5 +6#!#6 +7#!#7 +31#!#10 +~~END~~ + + +EXEC babel_3201_proc2; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value 257 is out of bounds for sequence "babel_3201_t_tinyint_a_seq" (5..255))~~ + + +-- testing different scenarios of 3-part name +DBCC CHECKIDENT('dbo.babel_dbcc_check_t1') +GO + +DBCC CHECKIDENT('..babel_dbcc_check_t1') +GO + +DBCC CHECKIDENT('master.dbo.babel_dbcc_check_t1') +GO + +DBCC CHECKIDENT('[master]."dbo".[babel_dbcc_check_t1]') +GO + +DBCC CHECKIDENT('"master".[dbo]."babel_dbcc_check_t1"') +GO + +DBCC CHECKIDENT('master..babel_dbcc_check_t1') +GO + +-- with mixed case names of db, schema, and table. +DBCC CHECKIDENT('dbo.BABEL_DBCC_check_t1') +GO +DBCC CHECKIDENT('master.DBO.BABEL_dbcc_check_t1') +GO +DBCC CHECKIDENT('[MASTER]."dBo".[babel_dbcc_CHECK_t1]') +GO + +-- schema and object name containing spaces and dots +DBCC CHECKIDENT('[babel_dbcc_check_t2 .with .dot_an_spaces]'); +GO + +DBCC CHECKIDENT('master.."babel_dbcc_check_t2 .with .dot_an_spaces"'); +GO + +DBCC CHECKIDENT('[babel_dbcc_check_schema .with .dot_and_spaces]."babel_dbcc_check_t3 .with .dot_and_spaces"'); +GO + +-- schema and object name containing spaces and dots + mixed case +DBCC CHECKIDENT('[BABEL_DBCC_CHECK_T2 .with .dOT_AN_SPACES]'); +GO + +DBCC CHECKIDENT('MASTer.."babel_dbcc_CHECK_T2 .with .dot_an_SPACES"'); +GO + +DBCC CHECKIDENT('[babel_DBCC_CHECK_schema .with .DOT_and_spaces]."babel_dbcc_CHECK_T3 .with .dot_and_spaces"'); +GO + +-- db name longer then 63 and doing cross db call +CREATE DATABASE babel_dbcc_checkident_database_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij +GO + +USE babel_dbcc_checkident_database_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij +GO + +CREATE TABLE babel_3201_longer__name_db_table (a int identity, b int); +GO + +USE master; +go + +DBCC CHECKIDENT('babel_dbcc_checkident_database_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.dbo.babel_3201_longer__name_db_table', noreseed); +GO + +-- db name longer and mixed case as well. +DBCC CHECKIDENT('bAbEl_dBcC_ChEcKiDeNt_dAtAbAsE_LoNgEr_tHaN_63_0AbCdEfGiJ1AbCdEfGiJ2AbCdEfGiJ3AbCdEfGiJ4AbCdEfGiJ5AbCdEfGiJ6AbCdEfGiJ7AbCdEfGiJ8AbCdEfGhIj9aBcDeFgHiJ.dbo.babel_3201_longer__name_db_table', noreseed); +GO + +-- drop this db because of single_db mode +DROP DATABASE babel_dbcc_checkident_database_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij +GO + +-- create database to test cross db behavior. +CREATE DATABASE babel_3201_db1; +GO + +USE babel_3201_db1 +GO + +CREATE TABLE babel_3201_db1_database_table1(a int identity, b int); +GO + +CREATE USER babel_3201_db1_log1_usr1 FOR LOGIN babel_3201_log1 +GO + +-- tsql user=babel_3201_log1 password=12345678 +-- Should throw - must be owner of schema dbo +DBCC CHECKIDENT('babel_3201_db1..babel_3201_db1_database_table1', NORESEED); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of schema dbo)~~ + + +-- tsql +USE babel_3201_db1 +GO +DROP USER babel_3201_db1_log1_usr1 +GO + + +-- tsql user=babel_3201_log1 password=12345678 +-- Should throw - The server principal "babel_3201_log1" is not able to access the database "babel_3201_db1" under the current security context +DBCC CHECKIDENT('babel_3201_db1..babel_3201_db1_database_table1', NORESEED); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The server principal "babel_3201_log1" is not able to access the database "babel_3201_db1" under the current security context)~~ + + +-- tsql +USE babel_3201_db1 +GO +GRANT CONNECT TO GUEST; +GO + +-- tsql user=babel_3201_log1 password=12345678 +-- Permission Check +USE babel_3201_db1; +GO + +-- should throw error - must be owner of schema master_dbo +DBCC CHECKIDENT('master.dbo.babel_3201_t_tinyint', RESEED, 10) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of schema master_dbo)~~ + + +-- tsql +USE master; +GO + +ALTER SERVER ROLE sysadmin ADD MEMBER babel_3201_log1; +GO + +-- tsql user=babel_3201_log1 password=12345678 +USE babel_3201_db1; +GO + +-- This should work correctly +DBCC CHECKIDENT('master.dbo.babel_3201_t_tinyint', RESEED, 10) +GO + +-- tsql +-- test locks in two connections transaction. +BEGIN TRAN +DBCC CHECKIDENT('babel_3201_test_locks', noreseed) +GO + + +-- tsql user=babel_3201_test_locks password=123456 +-- This reseed the identity values while the other transaction is not yet completed. +BEGIN TRAN +DBCC CHECKIDENT('babel_3201_test_locks', reseed, 101); +SELECT * FROM babel_3201_test_locks; +COMMIT; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value '1'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~START~~ +int#!#int +1#!#10 +~~END~~ + + +-- tsql +-- This will show the changed values of ident +DBCC CHECKIDENT('babel_3201_test_locks', noreseed); +SELECT * FROM babel_3201_test_locks; +COMMIT; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value '101', current column value '1'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~START~~ +int#!#int +1#!#10 +~~END~~ + + +-- tsql +-- test with user name longer then 64 chars. +USE MASTER +GO +CREATE USER babel_3201_db1_log1_user_name_longer_then_64_char_abdhcdjddjdhskdsh FOR LOGIN babel_3201_log1 +GO + +-- tsql user=babel_3201_log1 password=12345678 +USE babel_3201_db1; +GO +CREATE SCHEMA [babel_3201_user_schema] +GO +CREATE TABLE [babel_3201_db1].[babel_3201_user_schema].[babel_3201_user_table] (a int identity, b int); +GO +-- This should work correctly +DBCC CHECKIDENT('[babel_3201_db1].[babel_3201_user_schema].[babel_3201_user_table]', NORESEED); +GO +DBCC CHECKIDENT('master.dbo.babel_3201_t_tinyint', RESEED, 10) +GO + +-- tsql +USE master; +GO +DROP USER babel_3201_db1_log1_user_name_longer_then_64_char_abdhcdjddjdhskdsh +GO diff --git a/test/JDBC/expected/BABEL-UNSUPPORTED.out b/test/JDBC/expected/BABEL-UNSUPPORTED.out index 6306a0b153..bfdd35f053 100644 --- a/test/JDBC/expected/BABEL-UNSUPPORTED.out +++ b/test/JDBC/expected/BABEL-UNSUPPORTED.out @@ -2537,7 +2537,7 @@ DBCC CLONEDATABASE (d12608, d12608_clone); GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: 'DBCC' is not currently supported in Babelfish)~~ +~~ERROR (Message: DBCC CLONEDATABASE is not yet supported in Babelfish)~~ DROP DATABASE d12608; GO diff --git a/test/JDBC/input/BABEL-3201-vu-cleanup.sql b/test/JDBC/input/BABEL-3201-vu-cleanup.sql new file mode 100644 index 0000000000..455056962a --- /dev/null +++ b/test/JDBC/input/BABEL-3201-vu-cleanup.sql @@ -0,0 +1,59 @@ +DROP TABLE babel_3201_t_int; +GO + +DROP TABLE babel_dbcc_check_t1; +GO + +DROP TABLE [babel_dbcc_check_t2 .with .dot_an_spaces]; +GO + +DROP TABLE [babel_dbcc_check_schema .with .dot_and_spaces]."babel_dbcc_check_t3 .with .dot_and_spaces"; +GO + +DROP SCHEMA [babel_dbcc_check_schema .with .dot_and_spaces] +GO + +DROP TABLE babel_3201_t_tinyint; +GO + +DROP TABLE babel_3201_t_smallint; +GO + +DROP TABLE babel_3201_t_bigint; +GO + +DROP TABLE babel_3201_t_numeric; +GO + +DROP TABLE babel_3201_t_decimal; +GO + +DROP TABLE babel_3201_t1; +GO + +DROP TABLE babel_3201_t2; +GO + +DROP TABLE babel_3201_sch1.babel_3201_t2; +GO + +DROP TABLE babel_3201_test_locks; +GO + +DROP PROCEDURE babel_3201_proc1; +GO + +DROP PROCEDURE babel_3201_proc2; +GO + +DROP LOGIN babel_3201_log1; +GO + +DROP LOGIN babel_3201_test_locks; +GO + +DROP SCHEMA babel_3201_sch1; +GO + +DROP DATABASE babel_3201_db1; +GO diff --git a/test/JDBC/input/BABEL-3201-vu-prepare.sql b/test/JDBC/input/BABEL-3201-vu-prepare.sql new file mode 100644 index 0000000000..0a033d32e1 --- /dev/null +++ b/test/JDBC/input/BABEL-3201-vu-prepare.sql @@ -0,0 +1,123 @@ +CREATE SCHEMA babel_3201_sch1; +GO + +CREATE TABLE babel_3201_sch1.babel_3201_t2(a varchar(20), b int identity); +GO + +CREATE TABLE babel_3201_t_int( a int identity, b int); +GO + +CREATE TABLE babel_dbcc_check_t1 (a int identity, b int); +GO + +CREATE TABLE [babel_dbcc_check_t2 .with .dot_an_spaces] (a int identity, b int); +GO + +CREATE SCHEMA [babel_dbcc_check_schema .with .dot_and_spaces] +GO + +CREATE TABLE [babel_dbcc_check_schema .with .dot_and_spaces]."babel_dbcc_check_t3 .with .dot_and_spaces" (a int identity, b int); +GO + +CREATE TABLE babel_3201_t_tinyint( a tinyint identity(5,1), b int); +GO + +CREATE TABLE babel_3201_t_smallint( a smallint identity(10,10), b int); +GO + +CREATE TABLE babel_3201_t_bigint( a bigint identity(3,3), b int); +GO + +CREATE TABLE babel_3201_t_numeric( a numeric identity(4,2), b int); +GO + +CREATE TABLE babel_3201_t_decimal( a decimal identity(7,3), b int); +GO + +CREATE TABLE babel_3201_t1( a int identity, b int); +GO + +CREATE TABLE babel_3201_t2( a int, b int); +GO + +CREATE TABLE babel_3201_test_locks (a int identity, b int); +GO + +INSERT INTO babel_3201_test_locks VALUES (10); +GO + +INSERT INTO babel_3201_sch1.babel_3201_t2 VALUES ('string 1'); +GO + +INSERT INTO babel_3201_t_tinyint VALUES (5); +GO + +INSERT INTO babel_3201_t_tinyint VALUES (6); +GO + +INSERT INTO babel_3201_t_tinyint VALUES (7); +GO + +INSERT INTO babel_3201_t_smallint VALUES (5); +GO + +INSERT INTO babel_3201_t_smallint VALUES (6); +GO + +INSERT INTO babel_3201_t_smallint VALUES (7); +GO + +INSERT INTO babel_3201_t_int VALUES (5); +GO + +INSERT INTO babel_3201_t_int VALUES (6); +GO + +INSERT INTO babel_3201_t_int VALUES (7); +GO + +INSERT INTO babel_3201_t_bigint VALUES (5); +GO + +INSERT INTO babel_3201_t_bigint VALUES (6); +GO + +INSERT INTO babel_3201_t_bigint VALUES (6); +GO + +INSERT INTO babel_3201_t_numeric VALUES (5); +GO + +INSERT INTO babel_3201_t_numeric VALUES (6); +GO + +INSERT INTO babel_3201_t_numeric VALUES (7); +GO + +INSERT INTO babel_3201_t_decimal VALUES (5); +GO + +INSERT INTO babel_3201_t_decimal VALUES (6); +GO + +INSERT INTO babel_3201_t_decimal VALUES (7); +GO + +CREATE PROCEDURE babel_3201_proc1 +AS +DBCC CHECKIDENT(babel_3201_t_tinyint, RESEED, 30) +GO + +CREATE PROCEDURE babel_3201_proc2 +AS +DBCC CHECKIDENT(babel_3201_t_tinyint, RESEED, 257) +GO + +CREATE LOGIN babel_3201_log1 WITH PASSWORD='12345678'; +GO + +CREATE LOGIN babel_3201_test_locks WITH PASSWORD='123456'; +GO + +ALTER SERVER ROLE sysadmin ADD MEMBER babel_3201_test_locks +GO diff --git a/test/JDBC/input/BABEL-3201-vu-verify.mix b/test/JDBC/input/BABEL-3201-vu-verify.mix new file mode 100644 index 0000000000..bb3bf5124b --- /dev/null +++ b/test/JDBC/input/BABEL-3201-vu-verify.mix @@ -0,0 +1,487 @@ +DBCC CHECKIDENT(babel_3201_t_int, NORESEED); +GO + +-- test with mixed case in table name +DBCC CHECKIDENT(BABEL_3201_t_iNt, NORESEED); +GO +DBCC CHECKIDENT(BABEL_3201_T_INT, NORESEED); +GO + +-- test with table in quotes (+mixed cases) +DBCC CHECKIDENT('babel_3201_t_int', NORESEED); +GO +DBCC CHECKIDENT('baBEl_3201_T_inT', NORESEED); +GO + +-- test with table in brackets (+mixed case) +DBCC CHECKIDENT([babel_3201_t_int], NORESEED); +GO +DBCC CHECKIDENT([baBEL_3201_t_InT], NORESEED); +GO + +-- test with table in brackets with quotes (+mixed case) +DBCC CHECKIDENT('[babel_3201_t_int]', NORESEED); +GO +DBCC CHECKIDENT('[BABEL_3201_t_int]', NORESEED); +GO + +-- test when trailing space - should work +DBCC CHECKIDENT('babel_3201_t_int ', NORESEED); +GO +DBCC CHECKIDENT('babel_3201_T_INT ', NORESEED); +GO + +-- test when leading space - should throw error +DBCC CHECKIDENT(' babel_3201_t_int ', NORESEED); +GO + +-- test when table name is empty in quotes +DBCC CHECKIDENT('', NORESEED); +GO + +-- same as DBCC CHECKIDENT(, RESEED), identity value is not changed +-- if current identity value for a table is less than the maximum identity value +-- stored in the identity column +DBCC CHECKIDENT(babel_3201_t_int); +GO + + +DBCC CHECKIDENT(babel_3201_t_int, RESEED); +GO + +INSERT INTO babel_3201_t_int VALUES (8); +GO + +SELECT * FROM babel_3201_t_int; +GO + +DBCC CHECKIDENT('babel_3201_sch1.babel_3201_t2'); +GO + +-- Set identity value to 5 which is less than the maximum value(which is 9) of the identity +-- column, using RESEED option in this case should will reset the identity value +-- to maximum value of the identity column. Value inserted in next insert will +-- be (max_identity_col_value + increament). +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, 5); +GO +INSERT INTO babel_3201_t_bigint VALUES (8); +GO +SELECT * from babel_3201_t_bigint; +GO + +-- This will reset the current identity value(currently 8) to the maximum value of the identity column (currently 9) +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED); +GO +INSERT INTO babel_3201_t_bigint VALUES (9); +GO +SELECT * from babel_3201_t_bigint; +GO + +-- no rows have been inserted in the table; both current identity value current +-- column value should be NULL (TO-DO) +BEGIN TRAN; +DBCC CHECKIDENT(babel_3201_t1, NORESEED); +SELECT * FROM babel_3201_t1; +COMMIT; +GO + +BEGIN TRAN; +DBCC CHECKIDENT(babel_3201_t1, RESEED); +SELECT * FROM babel_3201_t1; +COMMIT; +GO + +-- current identity value should be NULL (TO-DO), identity value inserted in +-- next INSERT operation should be new_reseed_value. +BEGIN TRAN; +DBCC CHECKIDENT(babel_3201_t1, RESEED, 5); +INSERT INTO babel_3201_t1 VALUES (50); +COMMIT; +GO + +BEGIN TRAN; +DBCC CHECKIDENT(babel_3201_t1, NORESEED); +select * from babel_3201_t1; +COMMIT; +GO + +-- Remove all rows in table using TRUNCATE TABLE, Identity value will become NULL +-- next insert operation should be default identity value if no new_reseed_value is provided. +TRUNCATE TABLE babel_3201_t_int; +GO +dbcc checkident(babel_3201_t_int, NORESEED); +GO +INSERT INTO babel_3201_t_int values(15); +GO +select * from babel_3201_t_int; + +-- Remove all rows in table using TRUNCATE TABLE, identity value inserted in +-- next INSERT operation should be new_reseed_value. +TRUNCATE TABLE babel_3201_t_int; +GO +DBCC CHECKIDENT(babel_3201_t_int, RESEED, 10); +GO +INSERT INTO babel_3201_t_int VALUES (5); +GO +SELECT * FROM babel_3201_t_int; +GO + + +-- Remove all rows in table using DELETE TABLE, identity value inserted in next +-- INSERT operation should be (new_reseed_value + increment). +DELETE FROM babel_3201_t_bigint; +GO +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, 10); +GO +INSERT INTO babel_3201_t_bigint VALUES (5); +GO +SELECT * FROM babel_3201_t_bigint; +GO + +-- Remove all rows in table using DELETE TABLE current identity will not become default identity value, +-- identity value inserted in next operation should use (default identity value + increament) if no new_reseed_value is provided. +DELETE FROM babel_3201_t_bigint; +GO +dbcc checkident(babel_3201_t_bigint, NORESEED); +GO +INSERT INTO babel_3201_t_bigint VALUES (5); +GO +SELECT * FROM babel_3201_t_bigint; +GO + +-- If some rows are present already in the table, identity value inserted in next +-- INSERT operation should be (new_reseed_value + increament) +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, 27); +GO +INSERT INTO babel_3201_t_bigint VALUES (32); +GO +SELECT * FROM babel_3201_t_bigint; +GO + +-- Incorrect DBCC command option +DBCC CHECKIDENT(babel_3201_t1) WITH NO_INFO; +GO + +-- Invalid parameter 1 +DBCC CHECKIDENT(5); +GO + +DBCC CHECKIDENT(babel_3201_t_int, RESEED, ) WITH NO_INFOMSGS; +GO + +-- Invalid keyword +DBCC CHECKIDENT(babel_3201_t1, RESEE); +GO + +-- Invalid datatype +DBCC CHECKIDENT(babel_3201_t1, RESEED, 1313abc); +GO + +-- Unsupported DBCC command +DBCC CHECKTABLE(babel_3201_t1); +GO + +-- Invalid DBCC command +DBCC FAKE_COMMAND(t1); +GO + +-- Database undefined +DBCC CHECKIDENT('fake_db.dbo.babel_3201_t1', NORESEED); +GO + +-- Schema undefined +DBCC CHECKIDENT('fake_schema.babel_3201_t1', NORESEED); +GO + +-- Table undefined +DBCC CHECKIDENT(fake_babel_3201_t1, RESEED); +GO + +-- Table does not have identity column +DBCC CHECKIDENT(babel_3201_t2, RESEED); +GO + +-- new_reseed_value as expression is not allowed +DBCC CHECKIDENT(babel_3201_t2, RESEED, 4+5); +GO + +-- new_reseed_value is out of tinyint datatype range +DBCC CHECKIDENT(babel_3201_t_tinyint, RESEED, 256); +GO + +DBCC CHECKIDENT(babel_3201_t_tinyint, RESEED, -1); +GO + +-- new_reseed_value is out of smallint datatype range +DBCC CHECKIDENT(babel_3201_t_smallint, RESEED, 32768); +GO + +DBCC CHECKIDENT(babel_3201_t_smallint, RESEED, -32769); +GO + + +-- new_reseed_value is out of int datatype range +DBCC CHECKIDENT(babel_3201_t_int, RESEED, 2147483648); +GO + +DBCC CHECKIDENT(babel_3201_t_int, RESEED, -2147483649); +GO + +-- new_reseed_value is out of bigint datatype range +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, 9223372036854775808); +GO + +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, -9223372036854775809); +GO + +-- numeric/decimal datatypes are internally converted to bigint, so allowed +-- range is same as that of bigint +DBCC CHECKIDENT(babel_3201_t_numeric, RESEED, 9223372036854775808); +GO + +-- When new_reseed_value is a float value, only value before the decimal is used +DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 15.65); +GO + +-- When reseed_value is negative and zero, bbf currently does not support reseed to negative/zero value +dbcc checkident(babel_3201_t_decimal, reseed, -10) +GO +dbcc checkident(babel_3201_t_decimal, reseed, 0) +Go +dbcc checkident(babel_3201_t_decimal, reseed, .123) +Go +dbcc checkident(babel_3201_t_decimal, reseed, -.123) +Go +dbcc checkident(babel_3201_t_decimal, reseed, .) +GO +dbcc checkident(babel_3201_t_decimal, reseed, -) +GO +dbcc checkident(babel_3201_t_decimal, reseed, .-); +GO + +SELECT * FROM babel_3201_t_decimal; +GO + +begin tran; +DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 10); +INSERT INTO babel_3201_t_decimal VALUES (9); +commit; +go + +SELECT * FROM babel_3201_t_decimal; +GO + +BEGIN TRAN; + DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 133ac); + INSERT INTO babel_3201_t_decimal VALUES (10); +COMMIT; +GO + +SELECT * FROM babel_3201_t_decimal; +GO + +BEGIN TRAN; + DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 20); + INSERT INTO babel_3201_t_decimal VALUES (11); +ROLLBACK; +GO + +-- Check current_identity value after tran rollback +-- babelfish does not support rolling-back dbcc changes after transection rollback. +-- Current identity value will be = reseed_value inside the rollbacked transection + increament = 20+3=23 +BEGIN TRAN; +dbcc checkident(babel_3201_t_decimal, noreseed); +SELECT * FROM babel_3201_t_decimal; +COMMIT; +GO + +EXEC babel_3201_proc1; +GO + +INSERT INTO babel_3201_t_tinyint VALUES (10); +GO + +SELECT * FROM babel_3201_t_tinyint; +GO + +EXEC babel_3201_proc2; +GO + +-- testing different scenarios of 3-part name +DBCC CHECKIDENT('dbo.babel_dbcc_check_t1') +GO + +DBCC CHECKIDENT('..babel_dbcc_check_t1') +GO + +DBCC CHECKIDENT('master.dbo.babel_dbcc_check_t1') +GO + +DBCC CHECKIDENT('[master]."dbo".[babel_dbcc_check_t1]') +GO + +DBCC CHECKIDENT('"master".[dbo]."babel_dbcc_check_t1"') +GO + +DBCC CHECKIDENT('master..babel_dbcc_check_t1') +GO + +-- with mixed case names of db, schema, and table. +DBCC CHECKIDENT('dbo.BABEL_DBCC_check_t1') +GO +DBCC CHECKIDENT('master.DBO.BABEL_dbcc_check_t1') +GO +DBCC CHECKIDENT('[MASTER]."dBo".[babel_dbcc_CHECK_t1]') +GO + +-- schema and object name containing spaces and dots +DBCC CHECKIDENT('[babel_dbcc_check_t2 .with .dot_an_spaces]'); +GO + +DBCC CHECKIDENT('master.."babel_dbcc_check_t2 .with .dot_an_spaces"'); +GO + +DBCC CHECKIDENT('[babel_dbcc_check_schema .with .dot_and_spaces]."babel_dbcc_check_t3 .with .dot_and_spaces"'); +GO + +-- schema and object name containing spaces and dots + mixed case +DBCC CHECKIDENT('[BABEL_DBCC_CHECK_T2 .with .dOT_AN_SPACES]'); +GO + +DBCC CHECKIDENT('MASTer.."babel_dbcc_CHECK_T2 .with .dot_an_SPACES"'); +GO + +DBCC CHECKIDENT('[babel_DBCC_CHECK_schema .with .DOT_and_spaces]."babel_dbcc_CHECK_T3 .with .dot_and_spaces"'); +GO + +-- db name longer then 63 and doing cross db call +CREATE DATABASE babel_dbcc_checkident_database_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij +GO + +USE babel_dbcc_checkident_database_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij +GO + +CREATE TABLE babel_3201_longer__name_db_table (a int identity, b int); +GO + +USE master; +go + +DBCC CHECKIDENT('babel_dbcc_checkident_database_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.dbo.babel_3201_longer__name_db_table', noreseed); +GO + +-- db name longer and mixed case as well. +DBCC CHECKIDENT('bAbEl_dBcC_ChEcKiDeNt_dAtAbAsE_LoNgEr_tHaN_63_0AbCdEfGiJ1AbCdEfGiJ2AbCdEfGiJ3AbCdEfGiJ4AbCdEfGiJ5AbCdEfGiJ6AbCdEfGiJ7AbCdEfGiJ8AbCdEfGhIj9aBcDeFgHiJ.dbo.babel_3201_longer__name_db_table', noreseed); +GO + +-- drop this db because of single_db mode +DROP DATABASE babel_dbcc_checkident_database_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij +GO + +-- create database to test cross db behavior. +CREATE DATABASE babel_3201_db1; +GO + +USE babel_3201_db1 +GO + +CREATE TABLE babel_3201_db1_database_table1(a int identity, b int); +GO + +CREATE USER babel_3201_db1_log1_usr1 FOR LOGIN babel_3201_log1 +GO + +-- Should throw - must be owner of schema dbo +-- tsql user=babel_3201_log1 password=12345678 +DBCC CHECKIDENT('babel_3201_db1..babel_3201_db1_database_table1', NORESEED); +GO + +-- tsql +USE babel_3201_db1 +GO +DROP USER babel_3201_db1_log1_usr1 +GO + + +-- Should throw - The server principal "babel_3201_log1" is not able to access the database "babel_3201_db1" under the current security context +-- tsql user=babel_3201_log1 password=12345678 +DBCC CHECKIDENT('babel_3201_db1..babel_3201_db1_database_table1', NORESEED); +GO + +-- tsql +USE babel_3201_db1 +GO +GRANT CONNECT TO GUEST; +GO + +-- Permission Check +-- tsql user=babel_3201_log1 password=12345678 +USE babel_3201_db1; +GO + +-- should throw error - must be owner of schema master_dbo +DBCC CHECKIDENT('master.dbo.babel_3201_t_tinyint', RESEED, 10) +GO + +-- tsql +USE master; +GO + +ALTER SERVER ROLE sysadmin ADD MEMBER babel_3201_log1; +GO + +-- tsql user=babel_3201_log1 password=12345678 +USE babel_3201_db1; +GO + +-- This should work correctly +DBCC CHECKIDENT('master.dbo.babel_3201_t_tinyint', RESEED, 10) +GO + +-- test locks in two connections transaction. +-- tsql +BEGIN TRAN +DBCC CHECKIDENT('babel_3201_test_locks', noreseed) +GO + + +-- tsql user=babel_3201_test_locks password=123456 +-- This reseed the identity values while the other transaction is not yet completed. +BEGIN TRAN +DBCC CHECKIDENT('babel_3201_test_locks', reseed, 101); +SELECT * FROM babel_3201_test_locks; +COMMIT; +GO + +-- tsql +-- This will show the changed values of ident +DBCC CHECKIDENT('babel_3201_test_locks', noreseed); +SELECT * FROM babel_3201_test_locks; +COMMIT; +GO + +-- test with user name longer then 64 chars. +-- tsql +USE MASTER +GO +CREATE USER babel_3201_db1_log1_user_name_longer_then_64_char_abdhcdjddjdhskdsh FOR LOGIN babel_3201_log1 +GO + +-- tsql user=babel_3201_log1 password=12345678 +USE babel_3201_db1; +GO +CREATE SCHEMA [babel_3201_user_schema] +GO +CREATE TABLE [babel_3201_db1].[babel_3201_user_schema].[babel_3201_user_table] (a int identity, b int); +GO +-- This should work correctly +DBCC CHECKIDENT('[babel_3201_db1].[babel_3201_user_schema].[babel_3201_user_table]', NORESEED); +GO +DBCC CHECKIDENT('master.dbo.babel_3201_t_tinyint', RESEED, 10) +GO + +-- tsql +USE master; +GO +DROP USER babel_3201_db1_log1_user_name_longer_then_64_char_abdhcdjddjdhskdsh +GO diff --git a/test/python/expected/pyodbc/BABEL-3201.out b/test/python/expected/pyodbc/BABEL-3201.out new file mode 100644 index 0000000000..8135cf099f --- /dev/null +++ b/test/python/expected/pyodbc/BABEL-3201.out @@ -0,0 +1,56 @@ + +starting permutation : { s1dbcc_noreseed s2i s2s s1c s2c } +step s1dbcc_noreseed: dbcc checkident(dbcc_test_locks, NORESEED) +step s2i: INSERT INTO dbcc_test_locks VALUES (9); +~~ROW COUNT: 1~~ + +step s2s: SELECT * from dbcc_test_locks; +~~START~~ +int#!#int +1#!#5 +2#!#7 +3#!#9 +~~END~~ + +step s1c: COMMIT; +step s2c: COMMIT; + +starting permutation : { s1dbcc_reseed_without_new_reseed_value s2i s2s s1c s2c } +step s1dbcc_reseed_without_new_reseed_value: dbcc checkident(dbcc_test_locks, RESEED) +step s2i: INSERT INTO dbcc_test_locks VALUES (9); +~~ROW COUNT: 1~~ + +step s2s: SELECT * from dbcc_test_locks; +~~START~~ +int#!#int +1#!#5 +2#!#7 +3#!#9 +~~END~~ + +step s1c: COMMIT; +step s2c: COMMIT; + +starting permutation : { s1dbcc_reseed_with_new_value s2s s1c s2i s2s s2c } +step s1dbcc_reseed_with_new_value: dbcc checkident(dbcc_test_locks, RESEED, 10) +step s2s: SELECT * from dbcc_test_locks; +step s1c: COMMIT; +step s2s: <... completed> +~~START~~ +int#!#int +1#!#5 +2#!#7 +~~END~~ + +step s2i: INSERT INTO dbcc_test_locks VALUES (9); +~~ROW COUNT: 1~~ + +step s2s: SELECT * from dbcc_test_locks; +~~START~~ +int#!#int +1#!#5 +2#!#7 +11#!#9 +~~END~~ + +step s2c: COMMIT; diff --git a/test/python/input/isolation/BABEL-3201.spec b/test/python/input/isolation/BABEL-3201.spec new file mode 100644 index 0000000000..4ebe71dc3e --- /dev/null +++ b/test/python/input/isolation/BABEL-3201.spec @@ -0,0 +1,42 @@ +setup +{ + + create table dbcc_test_locks (a int identity, b int); + INSERT INTO dbcc_test_locks VALUES (5); + INSERT INTO dbcc_test_locks VALUES (7); + +} + +teardown +{ + drop table dbcc_test_locks; +} + +session s1 +setup { + BEGIN TRAN TR1; + } +step s1dbcc_noreseed { dbcc checkident(dbcc_test_locks, NORESEED) } +step s1dbcc_reseed_without_new_reseed_value { dbcc checkident(dbcc_test_locks, RESEED) } +step s1dbcc_reseed_with_new_value { dbcc checkident(dbcc_test_locks, RESEED, 10) } +step s1i { INSERT INTO dbcc_test_locks VALUES (8); } +step s1s { SELECT * FROM dbcc_test_locks; } +step s1c { COMMIT; } + +session s2 +setup { + BEGIN TRAN TR2; + } +step s2s { SELECT * from dbcc_test_locks; } +step s2i { INSERT INTO dbcc_test_locks VALUES (9); } +step s2c { COMMIT; } + +# till TR1 is commited, TR2 should be able to insert/read data from table t2 in case of noreeseed +permutation s1dbcc_noreseed s2i s2s s1c s2c + +# till TR1 is commited, TR-2 should be able to insert/read data from table t2 in case of reeseed without new value. +permutation s1dbcc_reseed_without_new_reseed_value s2i s2s s1c s2c + +# till TR1 is commited, TR-2 should NOT be able to read data from table t2 in case of reeseed with new value. +permutation s1dbcc_reseed_with_new_value s2s s1c s2i s2s s2c +