From 9309443003c9f5457f2d29edbb0fa9b324b3b476 Mon Sep 17 00:00:00 2001 From: Aditya Verma Date: Tue, 25 Jul 2023 15:41:17 +0000 Subject: [PATCH 01/17] Parser support for BABEL-3201 Signed-off-by: Aditya Verma --- contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 | 30 ++++ contrib/babelfishpg_tsql/antlr/TSqlParser.g4 | 64 ++++++- contrib/babelfishpg_tsql/src/codegen.c | 1 + contrib/babelfishpg_tsql/src/iterative_exec.c | 9 + contrib/babelfishpg_tsql/src/pl_exec-2.c | 10 ++ contrib/babelfishpg_tsql/src/pl_funcs-2.c | 17 ++ contrib/babelfishpg_tsql/src/pl_funcs.c | 2 + contrib/babelfishpg_tsql/src/pltsql.h | 27 ++- contrib/babelfishpg_tsql/src/stmt_walker.c | 3 + contrib/babelfishpg_tsql/src/stmt_walker.h | 3 + contrib/babelfishpg_tsql/src/tsqlIface.cpp | 156 +++++++++++++++++- contrib/babelfishpg_tsql/src/tsqlNodes.h | 3 +- .../src/tsqlUnsupportedFeatureHandler.cpp | 46 +++++- 13 files changed, 363 insertions(+), 8 deletions(-) diff --git a/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 b/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 index be9ddfa269..75a5757ecb 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; @@ -246,6 +252,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; @@ -296,6 +303,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; @@ -385,6 +393,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; @@ -422,6 +433,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; @@ -431,6 +443,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; @@ -453,6 +466,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; @@ -594,6 +608,7 @@ NODES: N O D E S; NOEXEC: N O E X E C; NOEXPAND: N O E X P A N D; NOFORMAT: N O F O R M A T; +// NO_INFOMSGS: N O UNDERLINE I N F O M S G S; NOINIT: N O I N I T; NOLOCK: N O L O C K; NONCLUSTERED: N O N C L U S T E R E D; @@ -601,6 +616,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; @@ -641,6 +657,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; @@ -653,6 +670,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; @@ -709,6 +727,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; @@ -779,6 +798,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; @@ -869,10 +889,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; @@ -897,6 +921,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; @@ -968,7 +993,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; @@ -1007,6 +1035,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; @@ -1014,6 +1043,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 623526b0a2..b51964f5a6 100644 --- a/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 +++ b/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 @@ -3094,13 +3094,41 @@ shutdown_statement ; dbcc_statement - : DBCC name=dbcc_command ( LR_BRACKET expression_list RR_BRACKET )? (WITH dbcc_options)? SEMI? + : DBCC dbcc_command ( LR_BRACKET table_name ( (COMMA NORESEED) | (COMMA RESEED (COMMA new_value=(ID | 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 + | CHECKIDENT + | 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 @@ -4266,15 +4294,21 @@ keyword | CHANGETABLE | CHANGE_RETENTION | CHANGE_TRACKING + | CHECKDB + | CHECKFILEGROUP + | CHECKIDENT | CHECKSUM | CHECKSUM_AGG + | CHECKTABLE | CHECK_EXPIRATION | CHECK_POLICY | CLASSIFIER | CLASSIFIER_FUNCTION + | CLEANTABLE | CLEANUP | CLEANUP_POLICY - | CLEAR + | CLEAR + | CLONEDATABASE | CLUSTER | COALESCE | COLLECTION @@ -4336,6 +4370,7 @@ keyword | DATE_FORMAT | DAY | DAYS + | DBREINDEX | DB_CHAINING | DB_FAILOVER | DDL @@ -4369,6 +4404,7 @@ keyword | DISTRIBUTED_AGG | DISTRIBUTION | DOCUMENT + | DROPCLEANBUFFERS | DTC_SUPPORT | DYNAMIC | EDGE @@ -4442,6 +4478,9 @@ keyword | FORMAT_OPTIONS | FORMAT_TYPE | FORWARD_ONLY + | FREEPROCCACHE + | FREESESSIONCACHE + | FREESYSTEMCACHE | FULLSCAN | FULLTEXT | GB @@ -4470,6 +4509,7 @@ keyword | HASHED | HEALTHCHECKTIMEOUT | HEALTH_CHECK_TIMEOUT + | HELP | HIDDEN_RENAMED | HIGH | HINT @@ -4492,10 +4532,12 @@ keyword | INCLUDE_NULL_VALUES | INCREMENT | INCREMENTAL + | INDEXDEFRAG | INFINITE | INIT | INITIATOR | INPUT + | INPUTBUFFER | INSENSITIVE | INSERTED | INSTEAD @@ -4626,6 +4668,7 @@ keyword | NOEXEC | NOEXPAND | NOFORMAT + // | NO_INFOMSGS | NOINIT | NONE | NON_TRANSACTED_ACCESS @@ -4661,6 +4704,7 @@ keyword | ONLY | ON_FAILURE | OPENJSON + | OPENTRAN | OPEN_EXISTING | OPERATIONS | OPERATION_MODE @@ -4668,6 +4712,7 @@ keyword | OPTIMIZE | OUT | OUTPUT + | OUTPUTBUFFER | OVERRIDE | OWNER | OWNERSHIP @@ -4715,6 +4760,7 @@ keyword | PRIVATE | PRIVATE_KEY | PRIVILEGES + | PROCCACHE | PROCEDURE_CACHE | PROCEDURE_NAME | PROCESS @@ -4843,10 +4889,14 @@ keyword | SETS | SETTINGS | SHARE + | SHOWCONTIG | SHOWPLAN | SHOWPLAN_ALL | SHOWPLAN_TEXT | SHOWPLAN_XML + | SHOW_STATISTICS + | SHRINKDATABASE + | SHRINKFILE | SHRINKLOG | SID | SIGNATURE @@ -4869,6 +4919,7 @@ keyword | SQLDUMPERFLAGS | SQLDUMPERPATH | SQLDUMPERTIMEOUT + | SQLPERF | STALE_CAPTURE_POLICY_THRESHOLD | STALE_QUERY_THRESHOLD_DAYS | STANDBY @@ -4930,6 +4981,9 @@ keyword | TOTAL_COMPILE_CPU_TIME_MS | TOTAL_EXECUTION_CPU_TIME_MS | TRACE + | TRACEOFF + | TRACEON + | TRACESTATUS | TRACKING | TRACK_CAUSALITY | TRACK_COLUMNS_UPDATED @@ -4959,8 +5013,10 @@ keyword | UNMASK | UNSAFE | UOW + | UPDATEUSAGE | URL | USED + | USEROPTIONS | USE_TYPE_DEFAULT | USING | VALIDATION diff --git a/contrib/babelfishpg_tsql/src/codegen.c b/contrib/babelfishpg_tsql/src/codegen.c index 61a7657131..42ff66ae9a 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_USEDB: case PLTSQL_STMT_GRANTDB: 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 6f82aceefc..6ad588b9a9 100644 --- a/contrib/babelfishpg_tsql/src/iterative_exec.c +++ b/contrib/babelfishpg_tsql/src/iterative_exec.c @@ -828,6 +828,15 @@ 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: + if (pltsql_explain_only) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Showing Estimated Execution Plan for INSERT BULK statment is not yet supported"))); + } + exec_stmt_dbcc(estate, (PLtsql_stmt_dbcc *) stmt); + break; default: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index 96e4d4c862..cae7350883 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_stmt_usedb_explain(PLtsql_execstate *estate, PLtsql_stmt_usedb * static int exec_stmt_grantdb(PLtsql_execstate *estate, PLtsql_stmt_grantdb *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); @@ -228,6 +229,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); @@ -3130,3 +3134,9 @@ get_insert_bulk_kilobytes_per_batch() { return insert_bulk_kilobytes_per_batch; } + +int exec_stmt_dbcc(PLtsql_execstate *estate, PLtsql_stmt_dbcc *stmt) +{ + // TODO implement + 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 5347259266..1864f6dced 100644 --- a/contrib/babelfishpg_tsql/src/pl_funcs-2.c +++ b/contrib/babelfishpg_tsql/src/pl_funcs-2.c @@ -558,6 +558,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; @@ -585,6 +590,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) @@ -717,6 +723,12 @@ 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 STATEMENT %s\n", stmt_dbcc->table_name); +} + void dump_stmt_try_catch(PLtsql_stmt_try_catch *stmt_try_catch) { @@ -844,6 +856,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 658d0b7143..020eb840df 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 dcfde38c93..97ea9b1d05 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_type +{ + PLTSQL_DBCC_CHECKIDENT +} PLtsql_dbcc_type; + /* * Variants distinguished in PLtsql_type structs */ @@ -184,7 +190,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_DBCC } PLtsql_stmt_type; /* @@ -931,6 +938,24 @@ typedef struct PLtsql_stmt_insert_bulk bool keep_nulls; } PLtsql_stmt_insert_bulk; +/* + * INSERT BULK statement + */ +typedef struct PLtsql_stmt_dbcc +{ + PLtsql_stmt_type cmd_type; + // PLtsql_dbcc_type dbcc_cmd_type; + int lineno; + char *table_name; + char *schema_name; + char *db_name; + + /* CHECKIDENT Options. */ + bool is_reseed; + char *new_reseed_value; + bool no_infomsgs; +} PLtsql_stmt_dbcc; + /* * RETURN statement */ diff --git a/contrib/babelfishpg_tsql/src/stmt_walker.c b/contrib/babelfishpg_tsql/src/stmt_walker.c index 7fa14f5263..b6f2ee580b 100644 --- a/contrib/babelfishpg_tsql/src/stmt_walker.c +++ b/contrib/babelfishpg_tsql/src/stmt_walker.c @@ -105,6 +105,8 @@ 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_DBCC: + break; /* TSQL-only executable node */ case PLTSQL_STMT_SAVE_CTX: @@ -202,6 +204,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) /* 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 8dc7db0983..8223d6d428 100644 --- a/contrib/babelfishpg_tsql/src/stmt_walker.h +++ b/contrib/babelfishpg_tsql/src/stmt_walker.h @@ -86,6 +86,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); /* TSQL-only executable node */ typedef bool (*Stmt_save_ctx) ACTION_SIGNITURE(save_ctx); @@ -135,6 +136,8 @@ 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; + /* 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 9ffe11eefb..b7509417e4 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -111,6 +111,7 @@ PLtsql_stmt *makeSQL(ParserRuleContext *ctx); std::vector makeAnother(TSqlParser::Another_statementContext *ctx, tsqlBuilder &builder); PLtsql_stmt *makeExecBodyBatch(TSqlParser::Execute_body_batchContext *ctx); 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); @@ -1796,6 +1797,23 @@ class tsqlBuilder : public tsqlCommonMutator clear_rewritten_query_fragment(); } + void enterDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) override + { + if (ctx->dbcc_command() && ctx->dbcc_command()->CHECKIDENT()) + // if (ctx->CHECKIDENT()) + graft(makeDbccCheckidentStatement(ctx), peekContainer()); + + clear_rewritten_query_fragment(); + PLtsql_stmt_execsql *stmt = (PLtsql_stmt_execsql *) getPLtsql_fragment(ctx); + Assert(stmt); + statementMutator = std::make_unique(stmt->sqlstmt, ctx); + } + + void exitDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) override + { + // TO-DO + } + ////////////////////////////////////////////////////////////////////////////// // Special handling of non-statement context ////////////////////////////////////////////////////////////////////////////// @@ -4634,7 +4652,6 @@ makeInsertBulkStatement(TSqlParser::Dml_statementContext *ctx) } } } - attachPLtsql_fragment(ctx, (PLtsql_stmt *) stmt); return (PLtsql_stmt *) stmt; } @@ -5209,6 +5226,143 @@ makeExecBodyBatch(TSqlParser::Execute_body_batchContext *ctx) return (PLtsql_stmt *) result; } +PLtsql_stmt* +makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx) +{ + PLtsql_stmt_dbcc *stmt = (PLtsql_stmt_dbcc *) palloc0(sizeof(*stmt)); + + std::string db_name; + std::string schema_name; + std::string table_name; + std::string new_reseed_value; + bool is_reseed = true; + bool no_infomsgs = false; + + stmt->cmd_type = PLTSQL_STMT_DBCC; + // stmt->dbcc_cmd_type = PLTSQL_DBCC_CHECKIDENT; + if (ctx->table_name()) + { + if (ctx->table_name()->database) + db_name = stripQuoteFromId(ctx->table_name()->database); + if (ctx->table_name()->schema) + schema_name = stripQuoteFromId(ctx->table_name()->schema); + if (ctx->table_name()->table) + table_name = stripQuoteFromId(ctx->table_name()->table); + + if (!db_name.empty()) + stmt->table_name = pstrdup(downcase_truncate_identifier(db_name.c_str(), db_name.length(), true)); + if (!schema_name.empty()) + stmt->schema_name = pstrdup(downcase_truncate_identifier(schema_name.c_str(), schema_name.length(), true)); + if (!table_name.empty()) + stmt->table_name = pstrdup(downcase_truncate_identifier(table_name.c_str(), table_name.length(), true)); + + switch (ctx->COMMA().size()) + { + case 0: + { + // CHECKIDENT () + break; + } + case 1: + { + if (ctx->RESEED()) + { + // CHECKIDENT (, RESEED) + } + else if (ctx->NORESEED()) + { + // CHECKIDENT (, NORESEED) + is_reseed = false; + } + else + { + throw PGErrorWrapperException(ERROR, + ERRCODE_INVALID_PARAMETER_VALUE, + "Parameter 2 is incorrect for this DBCC statement", + getLineAndPos(ctx->COMMA(1))); + } + break; + } + case 2: + { + // CHECKIDENT (, RESEED, ) + if (ctx->new_value) + { + stmt->new_reseed_value = pstrdup((ctx->new_value->getText()).c_str()); + } + else + { + + } + break; + } + default: + { + throw PGErrorWrapperException(ERROR, ERRCODE_SYNTAX_ERROR, + "An incorrect number of parameters was given to the" + "DBCC statement", getLineAndPos(ctx)); + break; + } + } + + // if (ctx->RESEED()) + // { + // // CHECKIDENT (, RESEED, ) + // if (ctx->new_value) + // { + // stmt->new_reseed_value = pstrdup((ctx->new_value->getText()).c_str()); + // } + + // else + // { + // // table_name = ::getFullText(ctx->expression_list()->expression()).c_str(); + // // throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "RESEED", getLineAndPos(ctx)); + // } + // } + // // CHECKIDENT (, NORESEED) + // else if (ctx->NORESEED()) + // { + // is_reseed = false; + // // throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "NORESEED", getLineAndPos(ctx)); + // } + // // CHECKIDENT () + // else + // { + // // throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "only table_name", getLineAndPos(ctx)); + // } + + if(ctx->dbcc_options()) + { + // if(ctx->dbcc_options()->keyword()NO_INFOMSGS()) + if (pg_strcasecmp(::getFullText(ctx->dbcc_options()).c_str(), "NO_INFOMSGS") == 0){ + no_infomsgs = true; + throw PGErrorWrapperException(ERROR, + ERRCODE_FEATURE_NOT_SUPPORTED, + "NO_INFOMSGS", getLineAndPos(ctx)); + } + 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())); + } + } + } + // else + // { + // throw PGErrorWrapperException(ERROR, + // ERRCODE_INVALID_PARAMETER_VALUE, + // "Parameter 1 is incorrect for this DBCC statement", + // getLineAndPos(ctx->dbcc_command())); + // // getLineAndPos(ctx->CHECKIDENT())); + // } + stmt->is_reseed = is_reseed; + stmt->no_infomsgs = no_infomsgs; + 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 2bdc6b4fda..0c0dda0ec3 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_DBCC } PLtsql_stmt_type; typedef struct PLtsql_expr diff --git a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp index 8e107c03fe..0ec566f588 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; @@ -1239,6 +1239,50 @@ 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 + { + if (ctx->dbcc_command()->CHECKIDENT()) + { + if (!ctx->table_name()) + throw PGErrorWrapperException(ERROR, + ERRCODE_INVALID_PARAMETER_VALUE, + "Parameter 1 is incorrect for this DBCC statement", + getLineAndPos(ctx->COMMA(1))); + else if (ctx->COMMA().size() == 1 && (!ctx->RESEED() && !ctx->NORESEED())) + throw PGErrorWrapperException(ERROR, + ERRCODE_INVALID_PARAMETER_VALUE, + "Parameter 2 is incorrect for this DBCC statement", + getLineAndPos(ctx->COMMA(1))); + else if (ctx->COMMA().size() == 2 && ctx->ID()) + throw PGErrorWrapperException(ERROR, + ERRCODE_INVALID_PARAMETER_VALUE, + "Parameter 3 is incorrect for this DBCC statement", + getLineAndPos(ctx->COMMA(1))); + } + 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()) From c7131307661705ceb26fe3617c6658ea7d71b77f Mon Sep 17 00:00:00 2001 From: Aditya Verma Date: Tue, 25 Jul 2023 22:35:47 +0000 Subject: [PATCH 02/17] change dbcc_command to CHECKIDENT in newly added grammar Signed-off-by: Aditya Verma --- contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 | 1 - contrib/babelfishpg_tsql/antlr/TSqlParser.g4 | 6 +- contrib/babelfishpg_tsql/src/iterative_exec.c | 2 +- contrib/babelfishpg_tsql/src/pltsql.h | 2 +- contrib/babelfishpg_tsql/src/tsqlIface.cpp | 145 ++++++++---------- .../src/tsqlUnsupportedFeatureHandler.cpp | 29 +--- test/JDBC/expected/BABEL-3201-vu-cleanup.out | 11 ++ test/JDBC/expected/BABEL-3201-vu-prepare.out | 21 +++ test/JDBC/expected/BABEL-3201-vu-verify.out | 59 +++++++ test/JDBC/input/BABEL-3201-vu-cleanup.sql | 11 ++ test/JDBC/input/BABEL-3201-vu-prepare.sql | 17 ++ test/JDBC/input/BABEL-3201-vu-verify.sql | 35 +++++ 12 files changed, 226 insertions(+), 113 deletions(-) create mode 100644 test/JDBC/expected/BABEL-3201-vu-cleanup.out create mode 100644 test/JDBC/expected/BABEL-3201-vu-prepare.out create mode 100644 test/JDBC/expected/BABEL-3201-vu-verify.out create mode 100644 test/JDBC/input/BABEL-3201-vu-cleanup.sql create mode 100644 test/JDBC/input/BABEL-3201-vu-prepare.sql create mode 100644 test/JDBC/input/BABEL-3201-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 b/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 index 75a5757ecb..1096dca4cb 100644 --- a/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 +++ b/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 @@ -608,7 +608,6 @@ NODES: N O D E S; NOEXEC: N O E X E C; NOEXPAND: N O E X P A N D; NOFORMAT: N O F O R M A T; -// NO_INFOMSGS: N O UNDERLINE I N F O M S G S; NOINIT: N O I N I T; NOLOCK: N O L O C K; NONCLUSTERED: N O N C L U S T E R E D; diff --git a/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 b/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 index b51964f5a6..ba663def04 100644 --- a/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 +++ b/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 @@ -3094,7 +3094,7 @@ shutdown_statement ; dbcc_statement - : DBCC dbcc_command ( LR_BRACKET table_name ( (COMMA NORESEED) | (COMMA RESEED (COMMA new_value=(ID | DECIMAL | FLOAT))?) )? RR_BRACKET ) (WITH dbcc_options)? SEMI? + : DBCC CHECKIDENT ( LR_BRACKET table_name ( (COMMA NORESEED) | (COMMA RESEED (COMMA 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? @@ -3105,7 +3105,6 @@ dbcc_command | CHECKDB | CHECKFILEGROUP | CHECKTABLE - | CHECKIDENT | CLEANTABLE | CLONEDATABASE | DBREINDEX @@ -4307,7 +4306,7 @@ keyword | CLEANTABLE | CLEANUP | CLEANUP_POLICY - | CLEAR + | CLEAR | CLONEDATABASE | CLUSTER | COALESCE @@ -4668,7 +4667,6 @@ keyword | NOEXEC | NOEXPAND | NOFORMAT - // | NO_INFOMSGS | NOINIT | NONE | NON_TRANSACTED_ACCESS diff --git a/contrib/babelfishpg_tsql/src/iterative_exec.c b/contrib/babelfishpg_tsql/src/iterative_exec.c index 6ad588b9a9..9e369fac62 100644 --- a/contrib/babelfishpg_tsql/src/iterative_exec.c +++ b/contrib/babelfishpg_tsql/src/iterative_exec.c @@ -833,7 +833,7 @@ dispatch_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for INSERT BULK statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for DBCC statment is not yet supported"))); } exec_stmt_dbcc(estate, (PLtsql_stmt_dbcc *) stmt); break; diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index 97ea9b1d05..a5e6144920 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -939,7 +939,7 @@ typedef struct PLtsql_stmt_insert_bulk } PLtsql_stmt_insert_bulk; /* - * INSERT BULK statement + * DBCC statement */ typedef struct PLtsql_stmt_dbcc { diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index b7509417e4..c0ca4cd60b 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -1799,8 +1799,7 @@ class tsqlBuilder : public tsqlCommonMutator void enterDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) override { - if (ctx->dbcc_command() && ctx->dbcc_command()->CHECKIDENT()) - // if (ctx->CHECKIDENT()) + if (ctx->CHECKIDENT()) graft(makeDbccCheckidentStatement(ctx), peekContainer()); clear_rewritten_query_fragment(); @@ -5256,89 +5255,81 @@ makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx) if (!table_name.empty()) stmt->table_name = pstrdup(downcase_truncate_identifier(table_name.c_str(), table_name.length(), true)); - switch (ctx->COMMA().size()) + // switch (ctx->COMMA().size()) + // { + // case 0: + // { + // // CHECKIDENT () + // break; + // } + // case 1: + // { + // if (ctx->RESEED()) + // { + // // CHECKIDENT (, RESEED) + // } + // else if (ctx->NORESEED()) + // { + // // CHECKIDENT (, NORESEED) + // is_reseed = false; + // } + // else + // { + // throw PGErrorWrapperException(ERROR, + // ERRCODE_INVALID_PARAMETER_VALUE, + // "Parameter 2 is incorrect for this DBCC statement", + // getLineAndPos(ctx->COMMA(1))); + // } + // break; + // } + // case 2: + // { + // // CHECKIDENT (, RESEED, ) + // if (ctx->new_value) + // { + // stmt->new_reseed_value = pstrdup((ctx->new_value->getText()).c_str()); + // } + // else + // { + + // } + // break; + // } + // default: + // { + // throw PGErrorWrapperException(ERROR, ERRCODE_SYNTAX_ERROR, + // "An incorrect number of parameters was given to the" + // "DBCC statement", getLineAndPos(ctx)); + // break; + // } + // } + + if (ctx->RESEED()) { - case 0: - { - // CHECKIDENT () - break; - } - case 1: - { - if (ctx->RESEED()) - { - // CHECKIDENT (, RESEED) - } - else if (ctx->NORESEED()) - { - // CHECKIDENT (, NORESEED) - is_reseed = false; - } - else - { - throw PGErrorWrapperException(ERROR, - ERRCODE_INVALID_PARAMETER_VALUE, - "Parameter 2 is incorrect for this DBCC statement", - getLineAndPos(ctx->COMMA(1))); - } - break; - } - case 2: + if (ctx->new_value) { // CHECKIDENT (, RESEED, ) - if (ctx->new_value) - { - stmt->new_reseed_value = pstrdup((ctx->new_value->getText()).c_str()); - } - else - { - - } - break; + stmt->new_reseed_value = pstrdup((ctx->new_value->getText()).c_str()); } - default: + else { - throw PGErrorWrapperException(ERROR, ERRCODE_SYNTAX_ERROR, - "An incorrect number of parameters was given to the" - "DBCC statement", getLineAndPos(ctx)); - break; + // CHECKIDENT (, RESEED) } } - - // if (ctx->RESEED()) - // { - // // CHECKIDENT (, RESEED, ) - // if (ctx->new_value) - // { - // stmt->new_reseed_value = pstrdup((ctx->new_value->getText()).c_str()); - // } - - // else - // { - // // table_name = ::getFullText(ctx->expression_list()->expression()).c_str(); - // // throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "RESEED", getLineAndPos(ctx)); - // } - // } - // // CHECKIDENT (, NORESEED) - // else if (ctx->NORESEED()) - // { - // is_reseed = false; - // // throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "NORESEED", getLineAndPos(ctx)); - // } - // // CHECKIDENT () - // else - // { - // // throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "only table_name", getLineAndPos(ctx)); - // } + else if (ctx->NORESEED()) + { + // CHECKIDENT (, NORESEED) + is_reseed = false; + } + else + { + // CHECKIDENT () + } if(ctx->dbcc_options()) { - // if(ctx->dbcc_options()->keyword()NO_INFOMSGS()) if (pg_strcasecmp(::getFullText(ctx->dbcc_options()).c_str(), "NO_INFOMSGS") == 0){ no_infomsgs = true; - throw PGErrorWrapperException(ERROR, - ERRCODE_FEATURE_NOT_SUPPORTED, - "NO_INFOMSGS", getLineAndPos(ctx)); } else { @@ -5349,14 +5340,6 @@ makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx) } } } - // else - // { - // throw PGErrorWrapperException(ERROR, - // ERRCODE_INVALID_PARAMETER_VALUE, - // "Parameter 1 is incorrect for this DBCC statement", - // getLineAndPos(ctx->dbcc_command())); - // // getLineAndPos(ctx->CHECKIDENT())); - // } stmt->is_reseed = is_reseed; stmt->no_infomsgs = no_infomsgs; attachPLtsql_fragment(ctx, (PLtsql_stmt *) stmt); diff --git a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp index 0ec566f588..1fe71b5078 100644 --- a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp @@ -1253,31 +1253,10 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitDbcc_statement(TSqlParser: } else { - if (ctx->dbcc_command()->CHECKIDENT()) - { - if (!ctx->table_name()) - throw PGErrorWrapperException(ERROR, - ERRCODE_INVALID_PARAMETER_VALUE, - "Parameter 1 is incorrect for this DBCC statement", - getLineAndPos(ctx->COMMA(1))); - else if (ctx->COMMA().size() == 1 && (!ctx->RESEED() && !ctx->NORESEED())) - throw PGErrorWrapperException(ERROR, - ERRCODE_INVALID_PARAMETER_VALUE, - "Parameter 2 is incorrect for this DBCC statement", - getLineAndPos(ctx->COMMA(1))); - else if (ctx->COMMA().size() == 2 && ctx->ID()) - throw PGErrorWrapperException(ERROR, - ERRCODE_INVALID_PARAMETER_VALUE, - "Parameter 3 is incorrect for this DBCC statement", - getLineAndPos(ctx->COMMA(1))); - } - 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())); - } + 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); 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..a0808acee8 --- /dev/null +++ b/test/JDBC/expected/BABEL-3201-vu-cleanup.out @@ -0,0 +1,11 @@ +DROP TABLE babel_3201_t1; +GO + +DROP TABLE babel_3201_sch1.babel_3201_t2; +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..0f7d031d15 --- /dev/null +++ b/test/JDBC/expected/BABEL-3201-vu-prepare.out @@ -0,0 +1,21 @@ +CREATE DATABASE babel_3201_db1; +GO + +CREATE SCHEMA babel_3201_sch1; +GO + +CREATE TABLE babel_3201_t1( a int identity, b int); +GO + +CREATE TABLE babel_3201_sch1.babel_3201_t2(a varchar(20), b int identity); +GO + +INSERT INTO babel_3201_t1 VALUES (1); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_sch1.babel_3201_t2 VALUES ('string 1'); +GO +~~ROW COUNT: 1~~ + 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..a1fa4b5a1c --- /dev/null +++ b/test/JDBC/expected/BABEL-3201-vu-verify.out @@ -0,0 +1,59 @@ +DBCC CHECKIDENT(babel_3201_t1); +GO + +DBCC CHECKIDENT(babel_3201_sch1.babel_3201_t2); +GO + +DBCC CHECKIDENT(babel_3201_t1, NORESEED); +GO + +DBCC CHECKIDENT(babel_3201_t1, RESEED); +GO + +DBCC CHECKIDENT(babel_3201_t1, RESEED, 5); +GO + +DBCC CHECKIDENT(babel_3201_t1) WITH NO_INFOMSGS; +GO + +DBCC CHECKIDENT(babel_3201_t1) WITH NO_INFO; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'NO_INFO' is not a recognized option)~~ + + +DBCC CHECKIDENT(5); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '5' at line 1 and character position 16)~~ + + +DBCC CHECKIDENT(babel_3201_t1, RESEE); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'RESEE' at line 1 and character position 31)~~ + + +DBCC CHECKIDENT(babel_3201_t1, RESEED, abc); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'abc' at line 1 and character position 39)~~ + + +DBCC CHECKTABLE(babel_3201_t1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: DBCC CHECKTABLE is not yet supported in Babelfish)~~ + + +DBCC FAKE_COMMAND(t1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Incorrect DBCC statement. Check the documentation for the correct DBCC syntax and options.)~~ + 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..a0808acee8 --- /dev/null +++ b/test/JDBC/input/BABEL-3201-vu-cleanup.sql @@ -0,0 +1,11 @@ +DROP TABLE babel_3201_t1; +GO + +DROP TABLE babel_3201_sch1.babel_3201_t2; +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..d91421b5a2 --- /dev/null +++ b/test/JDBC/input/BABEL-3201-vu-prepare.sql @@ -0,0 +1,17 @@ +CREATE DATABASE babel_3201_db1; +GO + +CREATE SCHEMA babel_3201_sch1; +GO + +CREATE TABLE babel_3201_t1( a int identity, b int); +GO + +CREATE TABLE babel_3201_sch1.babel_3201_t2(a varchar(20), b int identity); +GO + +INSERT INTO babel_3201_t1 VALUES (1); +GO + +INSERT INTO babel_3201_sch1.babel_3201_t2 VALUES ('string 1'); +GO diff --git a/test/JDBC/input/BABEL-3201-vu-verify.sql b/test/JDBC/input/BABEL-3201-vu-verify.sql new file mode 100644 index 0000000000..7b6759cafd --- /dev/null +++ b/test/JDBC/input/BABEL-3201-vu-verify.sql @@ -0,0 +1,35 @@ +DBCC CHECKIDENT(babel_3201_t1); +GO + +DBCC CHECKIDENT(babel_3201_sch1.babel_3201_t2); +GO + +DBCC CHECKIDENT(babel_3201_t1, NORESEED); +GO + +DBCC CHECKIDENT(babel_3201_t1, RESEED); +GO + +DBCC CHECKIDENT(babel_3201_t1, RESEED, 5); +GO + +DBCC CHECKIDENT(babel_3201_t1) WITH NO_INFOMSGS; +GO + +DBCC CHECKIDENT(babel_3201_t1) WITH NO_INFO; +GO + +DBCC CHECKIDENT(5); +GO + +DBCC CHECKIDENT(babel_3201_t1, RESEE); +GO + +DBCC CHECKIDENT(babel_3201_t1, RESEED, abc); +GO + +DBCC CHECKTABLE(babel_3201_t1); +GO + +DBCC FAKE_COMMAND(t1); +GO From b96e1b798a072ed4afc1b3ba2e46fb0e487c0aaa Mon Sep 17 00:00:00 2001 From: Aditya Verma Date: Tue, 25 Jul 2023 22:52:54 +0000 Subject: [PATCH 03/17] remove commented code Signed-off-by: Aditya Verma --- contrib/babelfishpg_tsql/src/tsqlIface.cpp | 49 ---------------------- 1 file changed, 49 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index c0ca4cd60b..4a8caf250f 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -5255,55 +5255,6 @@ makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx) if (!table_name.empty()) stmt->table_name = pstrdup(downcase_truncate_identifier(table_name.c_str(), table_name.length(), true)); - // switch (ctx->COMMA().size()) - // { - // case 0: - // { - // // CHECKIDENT () - // break; - // } - // case 1: - // { - // if (ctx->RESEED()) - // { - // // CHECKIDENT (, RESEED) - // } - // else if (ctx->NORESEED()) - // { - // // CHECKIDENT (, NORESEED) - // is_reseed = false; - // } - // else - // { - // throw PGErrorWrapperException(ERROR, - // ERRCODE_INVALID_PARAMETER_VALUE, - // "Parameter 2 is incorrect for this DBCC statement", - // getLineAndPos(ctx->COMMA(1))); - // } - // break; - // } - // case 2: - // { - // // CHECKIDENT (, RESEED, ) - // if (ctx->new_value) - // { - // stmt->new_reseed_value = pstrdup((ctx->new_value->getText()).c_str()); - // } - // else - // { - - // } - // break; - // } - // default: - // { - // throw PGErrorWrapperException(ERROR, ERRCODE_SYNTAX_ERROR, - // "An incorrect number of parameters was given to the" - // "DBCC statement", getLineAndPos(ctx)); - // break; - // } - // } - if (ctx->RESEED()) { if (ctx->new_value) From afc6dbccac31eaf6d4a7e0b65f17081f6700962f Mon Sep 17 00:00:00 2001 From: Aditya Verma Date: Wed, 9 Aug 2023 22:41:18 +0000 Subject: [PATCH 04/17] implementation for NORESEED and RESEED option Signed-off-by: Aditya Verma --- contrib/babelfishpg_tsql/src/pl_exec-2.c | 204 ++++++++++++++++++++- contrib/babelfishpg_tsql/src/pl_funcs-2.c | 2 +- contrib/babelfishpg_tsql/src/pltsql.h | 32 ++-- contrib/babelfishpg_tsql/src/tsqlIface.cpp | 22 +-- 4 files changed, 230 insertions(+), 30 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index cae7350883..eac889748e 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -89,7 +89,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); @@ -2959,6 +2959,202 @@ 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; + } + 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; + TableScanDesc scan; + HeapTuple tuple; + char *db_name = NULL; + char *schema_name = NULL; + char *nsp_name = NULL; + const char *user; + const char *guest_role_name; + int64 max_identity_value = 0; + int64 cur_identity_value = 0; + int attnum; + int64 reseed_value = 0; + Oid nsp_oid; + Oid table_oid; + Oid seqid; + bool is_null; + bool has_identity = false; + bool is_empty = false; + + if (dbcc_stmt.db_name) + db_name = pstrdup(dbcc_stmt.db_name); + else + db_name = get_cur_db_name(); + + if (!DbidIsValid(get_db_id(db_name))) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("database \"%s\" does not exist", db_name))); + pfree(db_name); + } + + user = get_user_for_database(db_name); + guest_role_name = get_guest_role_name(db_name); + + if(dbcc_stmt.new_reseed_value) + reseed_value = pg_strtoint64(dbcc_stmt.new_reseed_value); + + ereport(WARNING, (errmsg("reseed_value: %ld", reseed_value))); // to remove + + if (dbcc_stmt.schema_name) + { + schema_name = pstrdup(dbcc_stmt.schema_name); + nsp_name = get_physical_schema_name(db_name, schema_name); + } + else + { + if (!user) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("user does not exist"))); + } + else if ((guest_role_name && strcmp(user, guest_role_name) == 0)) + { + nsp_name = pstrdup(get_guest_schema_name(db_name)); + } + else + { + schema_name = get_authid_user_ext_schema_name((const char *) db_name, user); + nsp_name = get_physical_schema_name(db_name, schema_name); + } + } + + pfree(db_name); + + 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))); + } + pfree(schema_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))); + } + + /* Permission check */ + if (pg_class_aclcheck(table_oid, GetUserId(), ACL_SELECT | ACL_USAGE) != ACLCHECK_OK) + { + aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_TABLE, 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) + { + has_identity = true; + seqid = getIdentitySequence(table_oid, attnum + 1, false); + break; + } + } + + if (!has_identity) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("'%s.%s' does not contain an identity column.", + nsp_name, dbcc_stmt.table_name))); + + pfree(nsp_name); + scan = table_beginscan_catalog(rel, 0, NULL); + tuple = heap_getnext(scan, BackwardScanDirection); + + if (HeapTupleIsValid(tuple)) + { + max_identity_value = DatumGetInt64(heap_getattr(tuple, attnum+1, + tupdesc, &is_null)); + } + else + is_empty = true; + + RelationClose(rel); + table_endscan(scan); + + if (!is_empty) + cur_identity_value = DirectFunctionCall1(pg_sequence_last_value, + ObjectIdGetDatum(seqid)); + + if (dbcc_stmt.is_reseed) + { + if (dbcc_stmt.new_reseed_value) + { + if (is_empty) + DirectFunctionCall3(setval3_oid, + ObjectIdGetDatum(seqid), + CStringGetDatum(dbcc_stmt.new_reseed_value), + BoolGetDatum(false)); + else + DirectFunctionCall2(setval_oid, + ObjectIdGetDatum(seqid), + CStringGetDatum(dbcc_stmt.new_reseed_value)); + } + else + { + if (cur_identity_value < max_identity_value) + { + DirectFunctionCall2(setval_oid, + ObjectIdGetDatum(seqid), + Int64GetDatum(cur_identity_value)); + } + } + } + + if (!dbcc_stmt.no_infomsgs) + { + // print output + if (!dbcc_stmt.is_reseed || + (dbcc_stmt.is_reseed && + dbcc_stmt.new_reseed_value == NULL)) + { + ereport(WARNING, + (errmsg("Checking identity information: current identity value " + "'%ld', current column value '%ld'.\n" + "DBCC execution completed. If DBCC printed error messages, " + "contact your system administrator." + , cur_identity_value, max_identity_value))); + } + else + { + ereport(WARNING, + (errmsg("Checking identity information: current identity value " + "'%ld'.\n DBCC execution completed. If DBCC printed error " + "messages, contact your system administrator." + , cur_identity_value))); + } + } +} + + uint64 execute_bulk_load_insert(int ncol, int nrow, Datum *Values, bool *Nulls) @@ -3134,9 +3330,3 @@ get_insert_bulk_kilobytes_per_batch() { return insert_bulk_kilobytes_per_batch; } - -int exec_stmt_dbcc(PLtsql_execstate *estate, PLtsql_stmt_dbcc *stmt) -{ - // TODO implement - 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 1864f6dced..5d930e3ad9 100644 --- a/contrib/babelfishpg_tsql/src/pl_funcs-2.c +++ b/contrib/babelfishpg_tsql/src/pl_funcs-2.c @@ -726,7 +726,7 @@ dump_stmt_insert_bulk(PLtsql_stmt_insert_bulk *stmt_insert_bulk) void dump_stmt_dbcc(PLtsql_stmt_dbcc *stmt_dbcc) { - printf("DBCC STATEMENT %s\n", stmt_dbcc->table_name); + printf("DBCC STATEMENT\n"); } void diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index a5e6144920..d5bc82982e 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -117,10 +117,10 @@ typedef enum PLtsql_promise_type } PLtsql_promise_type; -typedef enum PLtsql_dbcc_type +typedef enum PLtsql_dbcc_stmt_type { PLTSQL_DBCC_CHECKIDENT -} PLtsql_dbcc_type; +} PLtsql_dbcc_stmt_type; /* * Variants distinguished in PLtsql_type structs @@ -938,22 +938,32 @@ 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; - // PLtsql_dbcc_type dbcc_cmd_type; int lineno; - char *table_name; - char *schema_name; - char *db_name; - - /* CHECKIDENT Options. */ - bool is_reseed; - char *new_reseed_value; - bool no_infomsgs; + PLtsql_dbcc_stmt_type dbcc_stmt_type; + PLtsql_dbcc_stmt_data dbcc_stmt_data; } PLtsql_stmt_dbcc; /* diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index 4a8caf250f..b7e26754af 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -1803,9 +1803,9 @@ class tsqlBuilder : public tsqlCommonMutator graft(makeDbccCheckidentStatement(ctx), peekContainer()); clear_rewritten_query_fragment(); - PLtsql_stmt_execsql *stmt = (PLtsql_stmt_execsql *) getPLtsql_fragment(ctx); - Assert(stmt); - statementMutator = std::make_unique(stmt->sqlstmt, ctx); + // PLtsql_stmt_execsql *stmt = (PLtsql_stmt_execsql *) getPLtsql_fragment(ctx); + // Assert(stmt); + // statementMutator = std::make_unique(stmt->sqlstmt, ctx); } void exitDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) override @@ -5238,7 +5238,7 @@ makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx) bool no_infomsgs = false; stmt->cmd_type = PLTSQL_STMT_DBCC; - // stmt->dbcc_cmd_type = PLTSQL_DBCC_CHECKIDENT; + stmt->dbcc_stmt_type = PLTSQL_DBCC_CHECKIDENT; if (ctx->table_name()) { if (ctx->table_name()->database) @@ -5249,18 +5249,18 @@ makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx) table_name = stripQuoteFromId(ctx->table_name()->table); if (!db_name.empty()) - stmt->table_name = pstrdup(downcase_truncate_identifier(db_name.c_str(), db_name.length(), true)); + stmt->dbcc_stmt_data.dbcc_checkident.db_name = pstrdup(downcase_truncate_identifier(db_name.c_str(), db_name.length(), true)); if (!schema_name.empty()) - stmt->schema_name = pstrdup(downcase_truncate_identifier(schema_name.c_str(), schema_name.length(), true)); + stmt->dbcc_stmt_data.dbcc_checkident.schema_name = pstrdup(downcase_truncate_identifier(schema_name.c_str(), schema_name.length(), true)); if (!table_name.empty()) - stmt->table_name = pstrdup(downcase_truncate_identifier(table_name.c_str(), table_name.length(), true)); + stmt->dbcc_stmt_data.dbcc_checkident.table_name = pstrdup(downcase_truncate_identifier(table_name.c_str(), table_name.length(), true)); if (ctx->RESEED()) { if (ctx->new_value) { // CHECKIDENT (, RESEED, ) - stmt->new_reseed_value = pstrdup((ctx->new_value->getText()).c_str()); + stmt->dbcc_stmt_data.dbcc_checkident.new_reseed_value = pstrdup((ctx->new_value->getText()).c_str()); } else { @@ -5270,7 +5270,7 @@ makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx) else if (ctx->NORESEED()) { // CHECKIDENT (, NORESEED) - is_reseed = false; + stmt->dbcc_stmt_data.dbcc_checkident.is_reseed = false; } else { @@ -5291,8 +5291,8 @@ makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx) } } } - stmt->is_reseed = is_reseed; - stmt->no_infomsgs = no_infomsgs; + stmt->dbcc_stmt_data.dbcc_checkident.is_reseed = is_reseed; + stmt->dbcc_stmt_data.dbcc_checkident.no_infomsgs = no_infomsgs; attachPLtsql_fragment(ctx, (PLtsql_stmt *) stmt); return (PLtsql_stmt *) stmt; } From 1836d4019a039873f4f6037e9d2d6a5aafe9544a Mon Sep 17 00:00:00 2001 From: Aditya Verma Date: Wed, 9 Aug 2023 22:48:13 +0000 Subject: [PATCH 05/17] remove not required comments Signed-off-by: Aditya Verma --- contrib/babelfishpg_tsql/src/tsqlIface.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index b7e26754af..ea08619885 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -5259,23 +5259,13 @@ makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx) { if (ctx->new_value) { - // CHECKIDENT (, RESEED, ) stmt->dbcc_stmt_data.dbcc_checkident.new_reseed_value = pstrdup((ctx->new_value->getText()).c_str()); } - else - { - // CHECKIDENT (, RESEED) - } } else if (ctx->NORESEED()) { - // CHECKIDENT (, NORESEED) stmt->dbcc_stmt_data.dbcc_checkident.is_reseed = false; } - else - { - // CHECKIDENT () - } if(ctx->dbcc_options()) { From a71eab148581c18b864561f863612f8e456fec66 Mon Sep 17 00:00:00 2001 From: Aditya Verma Date: Thu, 10 Aug 2023 22:48:44 +0000 Subject: [PATCH 06/17] handle cases where table has no values, added comments Signed-off-by: Aditya Verma --- contrib/babelfishpg_tsql/src/pl_exec-2.c | 83 +++++++++++++++--------- 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index eac889748e..b31404ff28 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -2988,10 +2988,9 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) int64 reseed_value = 0; Oid nsp_oid; Oid table_oid; - Oid seqid; + Oid seqid = InvalidOid; bool is_null; - bool has_identity = false; - bool is_empty = false; + volatile bool cur_value_is_null = true; if (dbcc_stmt.db_name) db_name = pstrdup(dbcc_stmt.db_name); @@ -3021,6 +3020,10 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) } else { + /* + * If schema_name is not provided, find default schema for current user + * and get physical schema name + */ if (!user) { ereport(ERROR, @@ -3073,19 +3076,24 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) if (attr->attidentity) { - has_identity = true; seqid = getIdentitySequence(table_oid, attnum + 1, false); break; } } - if (!has_identity) + if (!OidIsValid(seqid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("'%s.%s' does not contain an identity column.", nsp_name, dbcc_stmt.table_name))); - + pfree(nsp_name); + + /* + * We need to find out the last value of the identity column in the table + * and last value of the identity sequence to compare and decide on the + * action that needs to be taken. + */ scan = table_beginscan_catalog(rel, 0, NULL); tuple = heap_getnext(scan, BackwardScanDirection); @@ -3094,47 +3102,62 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) max_identity_value = DatumGetInt64(heap_getattr(tuple, attnum+1, tupdesc, &is_null)); } - else - is_empty = true; RelationClose(rel); table_endscan(scan); - if (!is_empty) + PG_TRY(); + { cur_identity_value = DirectFunctionCall1(pg_sequence_last_value, ObjectIdGetDatum(seqid)); + cur_value_is_null = false; - if (dbcc_stmt.is_reseed) - { - if (dbcc_stmt.new_reseed_value) - { - if (is_empty) - DirectFunctionCall3(setval3_oid, - ObjectIdGetDatum(seqid), - CStringGetDatum(dbcc_stmt.new_reseed_value), - BoolGetDatum(false)); - else - DirectFunctionCall2(setval_oid, - ObjectIdGetDatum(seqid), - CStringGetDatum(dbcc_stmt.new_reseed_value)); - } - else + if (dbcc_stmt.is_reseed) { - if (cur_identity_value < max_identity_value) + if (dbcc_stmt.new_reseed_value) { DirectFunctionCall2(setval_oid, ObjectIdGetDatum(seqid), - Int64GetDatum(cur_identity_value)); + Int64GetDatum(reseed_value)); + } + else + { + + /* + * 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 (cur_identity_value < max_identity_value) + { + DirectFunctionCall2(setval_oid, + ObjectIdGetDatum(seqid), + Int64GetDatum(max_identity_value)); + } } } } + PG_CATCH(); + { + /* + * 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) + DirectFunctionCall3(setval3_oid, + ObjectIdGetDatum(seqid), + Int64GetDatum(reseed_value), + BoolGetDatum(false)); + } + PG_END_TRY(); + /* Do not print output if NO_INFOMSGS is provided */ if (!dbcc_stmt.no_infomsgs) { - // print output - if (!dbcc_stmt.is_reseed || - (dbcc_stmt.is_reseed && - dbcc_stmt.new_reseed_value == NULL)) + if (!dbcc_stmt.new_reseed_value) { ereport(WARNING, (errmsg("Checking identity information: current identity value " From fe32536ec1a13cd4ef78d113c5fa7b5053b945a1 Mon Sep 17 00:00:00 2001 From: Aditya Verma Date: Tue, 22 Aug 2023 06:05:43 +0000 Subject: [PATCH 07/17] addressed review comments - addreseed review comments - negative input parameter showed error, fixed - updated permission checks - use max(id) to find current identity value - updated testcases - fix crash if reseed is used on empty table - Signed-off-by: Aditya Verma --- contrib/babelfishpg_tsql/antlr/TSqlParser.g4 | 2 +- contrib/babelfishpg_tsql/src/pl_exec-2.c | 195 ++++++---- contrib/babelfishpg_tsql/src/pl_funcs-2.c | 12 +- contrib/babelfishpg_tsql/src/tsqlIface.cpp | 6 +- test/JDBC/expected/BABEL-3201-vu-cleanup.out | 28 ++ test/JDBC/expected/BABEL-3201-vu-prepare.out | 114 +++++- test/JDBC/expected/BABEL-3201-vu-verify.out | 358 ++++++++++++++++++- test/JDBC/input/BABEL-3201-vu-cleanup.sql | 24 ++ test/JDBC/input/BABEL-3201-vu-prepare.sql | 78 +++- test/JDBC/input/BABEL-3201-vu-verify.sql | 189 +++++++++- 10 files changed, 916 insertions(+), 90 deletions(-) diff --git a/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 b/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 index ba663def04..98fc240a54 100644 --- a/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 +++ b/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 @@ -3094,7 +3094,7 @@ shutdown_statement ; dbcc_statement - : DBCC CHECKIDENT ( LR_BRACKET table_name ( (COMMA NORESEED) | (COMMA RESEED (COMMA new_value=(DECIMAL | FLOAT))?) )? RR_BRACKET ) (WITH dbcc_options)? SEMI? + : DBCC CHECKIDENT ( LR_BRACKET table_name ( (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? diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index b31404ff28..de80323011 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -18,6 +18,8 @@ #include "pl_explain.h" #include "session.h" +#include + /* helper function to get current T-SQL estate */ PLtsql_execstate *get_current_tsql_estate(void); PLtsql_execstate *get_outermost_tsql_estate(int *nestlevel); @@ -2959,6 +2961,7 @@ 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) @@ -2966,31 +2969,51 @@ int exec_stmt_dbcc(PLtsql_execstate *estate, PLtsql_stmt_dbcc *stmt) 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; - TableScanDesc scan; - HeapTuple tuple; char *db_name = NULL; char *schema_name = NULL; char *nsp_name = NULL; + char *table_name; + char *query; + char *attname; const char *user; const char *guest_role_name; int64 max_identity_value = 0; int64 cur_identity_value = 0; + char *max_identity_value_str = NULL; + char *token; int attnum; + int rc; int64 reseed_value = 0; Oid nsp_oid; Oid table_oid; Oid seqid = InvalidOid; - bool is_null; + Oid userid = GetUserId(); volatile bool cur_value_is_null = true; + bool login_is_db_owner; + + if(dbcc_stmt.new_reseed_value) + { + /* If float value is passed as reseed_value, only decimal part is considered.*/ + token = strtok(dbcc_stmt.new_reseed_value, "."); + reseed_value = pg_strtoint64(token); + if(reseed_value >= 0) + reseed_value = floor(reseed_value); + else + reseed_value = -floor(-reseed_value); + pfree(token); + } if (dbcc_stmt.db_name) db_name = pstrdup(dbcc_stmt.db_name); @@ -3005,14 +3028,11 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) pfree(db_name); } + login_is_db_owner = 0 == strncmp(GetUserNameFromId(userid, false), + get_owner_of_db(db_name), NAMEDATALEN); user = get_user_for_database(db_name); guest_role_name = get_guest_role_name(db_name); - if(dbcc_stmt.new_reseed_value) - reseed_value = pg_strtoint64(dbcc_stmt.new_reseed_value); - - ereport(WARNING, (errmsg("reseed_value: %ld", reseed_value))); // to remove - if (dbcc_stmt.schema_name) { schema_name = pstrdup(dbcc_stmt.schema_name); @@ -3050,21 +3070,21 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) (errcode(ERRCODE_UNDEFINED_SCHEMA), errmsg("schema \"%s\" does not exist", schema_name))); } - pfree(schema_name); - table_oid = get_relname_relid(dbcc_stmt.table_name, nsp_oid); + table_name = pstrdup(dbcc_stmt.table_name); + table_oid = get_relname_relid(table_name, nsp_oid); if(!OidIsValid(table_oid)) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), - errmsg("relation \"%s\" does not exist", dbcc_stmt.table_name))); + errmsg("relation \"%s\" does not exist", table_name))); } /* Permission check */ - if (pg_class_aclcheck(table_oid, GetUserId(), ACL_SELECT | ACL_USAGE) != ACLCHECK_OK) - { - aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_TABLE, dbcc_stmt.table_name); - } + if (!pg_namespace_ownercheck(nsp_oid, userid) || + !(has_privs_of_role(userid, get_role_oid("sysadmin", false)) || + !login_is_db_owner)) + aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SCHEMA, nsp_name); rel = RelationIdGetRelation(table_oid); tupdesc = RelationGetDescr(rel); @@ -3076,35 +3096,19 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) 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))); - - pfree(nsp_name); - - /* - * We need to find out the last value of the identity column in the table - * and last value of the identity sequence to compare and decide on the - * action that needs to be taken. - */ - scan = table_beginscan_catalog(rel, 0, NULL); - tuple = heap_getnext(scan, BackwardScanDirection); - - if (HeapTupleIsValid(tuple)) - { - max_identity_value = DatumGetInt64(heap_getattr(tuple, attnum+1, - tupdesc, &is_null)); - } - - RelationClose(rel); - table_endscan(scan); + nsp_name, table_name))); PG_TRY(); { @@ -3112,28 +3116,59 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) ObjectIdGetDatum(seqid)); cur_value_is_null = false; - if (dbcc_stmt.is_reseed) + if (dbcc_stmt.new_reseed_value) { - 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) + ereport(WARNING, + (errmsg("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, 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); + + if(max_identity_value_str) + max_identity_value = pg_strtoint64(max_identity_value_str); + + if (!dbcc_stmt.no_infomsgs) + ereport(WARNING, + (errmsg("Checking identity information: current" + " identity value '%ld', current column value " + "'%s'.\n", cur_identity_value, + max_identity_value_str ? + max_identity_value_str : "NULL"))); + + pfree(query); + SPI_freetuptable(SPI_tuptable); + + /* + * 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(reseed_value)); - } - else - { - - /* - * 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 (cur_identity_value < max_identity_value) - { - DirectFunctionCall2(setval_oid, - ObjectIdGetDatum(seqid), - Int64GetDatum(max_identity_value)); - } + Int64GetDatum(max_identity_value)); } } } @@ -3146,34 +3181,42 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) * 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) - DirectFunctionCall3(setval3_oid, - ObjectIdGetDatum(seqid), - Int64GetDatum(reseed_value), - BoolGetDatum(false)); + if (cur_value_is_null) + { + if (dbcc_stmt.new_reseed_value) + { + ereport(WARNING, + (errmsg("Checking identity information: current" + " identity value 'NULL'.\n"))); + + DirectFunctionCall3(setval3_oid, + ObjectIdGetDatum(seqid), + Int64GetDatum(reseed_value), + BoolGetDatum(false)); + } + else + { + ereport(WARNING, + (errmsg("Checking identity information: current" + " identity value 'NULL', current column value 'NULL'.\n"))); + } + } + else + PG_RE_THROW(); } PG_END_TRY(); - /* Do not print output if NO_INFOMSGS is provided */ + if (max_identity_value_str) + pfree(max_identity_value_str); + pfree(schema_name); + pfree(table_name); + pfree(nsp_name); + if (!dbcc_stmt.no_infomsgs) { - if (!dbcc_stmt.new_reseed_value) - { - ereport(WARNING, - (errmsg("Checking identity information: current identity value " - "'%ld', current column value '%ld'.\n" - "DBCC execution completed. If DBCC printed error messages, " - "contact your system administrator." - , cur_identity_value, max_identity_value))); - } - else - { - ereport(WARNING, - (errmsg("Checking identity information: current identity value " - "'%ld'.\n DBCC execution completed. If DBCC printed error " - "messages, contact your system administrator." - , cur_identity_value))); - } + ereport(WARNING, + (errmsg( "DBCC execution completed. If DBCC printed error messages," + " contact your system administrator."))); } } diff --git a/contrib/babelfishpg_tsql/src/pl_funcs-2.c b/contrib/babelfishpg_tsql/src/pl_funcs-2.c index 5d930e3ad9..731cf64ccd 100644 --- a/contrib/babelfishpg_tsql/src/pl_funcs-2.c +++ b/contrib/babelfishpg_tsql/src/pl_funcs-2.c @@ -726,7 +726,17 @@ dump_stmt_insert_bulk(PLtsql_stmt_insert_bulk *stmt_insert_bulk) void dump_stmt_dbcc(PLtsql_stmt_dbcc *stmt_dbcc) { - printf("DBCC STATEMENT\n"); + 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 diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index ea08619885..0430cd294e 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -5259,7 +5259,11 @@ makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx) { if (ctx->new_value) { - stmt->dbcc_stmt_data.dbcc_checkident.new_reseed_value = pstrdup((ctx->new_value->getText()).c_str()); + 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()) diff --git a/test/JDBC/expected/BABEL-3201-vu-cleanup.out b/test/JDBC/expected/BABEL-3201-vu-cleanup.out index a0808acee8..dc33e9f050 100644 --- a/test/JDBC/expected/BABEL-3201-vu-cleanup.out +++ b/test/JDBC/expected/BABEL-3201-vu-cleanup.out @@ -1,9 +1,37 @@ +DROP TABLE babel_3201_t_int; +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 LOGIN babel_3201_log1; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot drop the login 'babel_3201_log1', because it does not exist or you do not have permission.)~~ + + DROP SCHEMA babel_3201_sch1; GO diff --git a/test/JDBC/expected/BABEL-3201-vu-prepare.out b/test/JDBC/expected/BABEL-3201-vu-prepare.out index 0f7d031d15..d27a523ab3 100644 --- a/test/JDBC/expected/BABEL-3201-vu-prepare.out +++ b/test/JDBC/expected/BABEL-3201-vu-prepare.out @@ -4,10 +4,31 @@ GO 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_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_sch1.babel_3201_t2(a varchar(20), b int identity); +CREATE TABLE babel_3201_t2( a int, b int); GO INSERT INTO babel_3201_t1 VALUES (1); @@ -19,3 +40,94 @@ 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~~ + + diff --git a/test/JDBC/expected/BABEL-3201-vu-verify.out b/test/JDBC/expected/BABEL-3201-vu-verify.out index a1fa4b5a1c..53900553db 100644 --- a/test/JDBC/expected/BABEL-3201-vu-verify.out +++ b/test/JDBC/expected/BABEL-3201-vu-verify.out @@ -1,21 +1,153 @@ -DBCC CHECKIDENT(babel_3201_t1); +DBCC CHECKIDENT(babel_3201_t_int, 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 +~~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 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 + increment). +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, 3); +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 +6#!#8 +~~END~~ + + +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 +6#!#8 +12#!#9 +~~END~~ + + +-- no rows have been inserted in the table; both current identity value current +-- column value should be NULL (TO-DO) DBCC CHECKIDENT(babel_3201_t1, NORESEED); GO DBCC CHECKIDENT(babel_3201_t1, RESEED); GO +-- current identity value should be NULL (TO-DO), identity value inserted in +-- next INSERT operation should be new_reseed_value. DBCC CHECKIDENT(babel_3201_t1, RESEED, 5); GO -DBCC CHECKIDENT(babel_3201_t1) WITH NO_INFOMSGS; +INSERT INTO babel_3201_t_int VALUES (5); +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM babel_3201_t_int; +GO +~~START~~ +int#!#int +1#!#5 +2#!#6 +3#!#7 +4#!#8 +5#!#5 +~~END~~ + + +-- 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 +~~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~~ + +-- Incorrect DBCC command option DBCC CHECKIDENT(babel_3201_t1) WITH NO_INFO; GO ~~ERROR (Code: 33557097)~~ @@ -23,27 +155,38 @@ GO ~~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 1 and character position 16)~~ +~~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 1 and character position 31)~~ +~~ERROR (Message: syntax error near 'RESEE' at line 2 and character position 31)~~ -DBCC CHECKIDENT(babel_3201_t1, RESEED, abc); +-- Invalid datatype +DBCC CHECKIDENT(babel_3201_t1, RESEED, 1313abc); GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: syntax error near 'abc' at line 1 and character position 39)~~ +~~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)~~ @@ -51,9 +194,212 @@ GO ~~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)~~ + + +-- Table undefined +DBCC CHECKIDENT(babel_3201_t1, RESEED); +GO + +-- Schema undefined +DBCC CHECKIDENT(babel_3201_sch3.babel_3201_t1, NORESEED); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: schema "master_babel_3201_sch3" 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 +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value -15 is out of bounds for sequence "babel_3201_t_decimal_a_seq" (7..9223372036854775807))~~ + + +INSERT INTO babel_3201_t_decimal VALUES (8); +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM babel_3201_t_decimal; +GO +~~START~~ +bigint#!#int +7#!#5 +10#!#6 +13#!#7 +16#!#8 +~~END~~ + + + + +-- CREATE LOGIN babel_3201_log1 WITH PASSWORD='123456789'; +-- GO +-- CREATE USER babel_3201_user1 FOR LOGIN babel_3201_log1; +-- GO +-- tsql user=babel_3201_log1 password=123456789 +DBCC CHECKIDENT(babel_3201_t_decimal, RESEED); +GO + +begin tran; +DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 10); +INSERT INTO babel_3201_t_decimal VALUES (9); +commit; +go +~~ROW COUNT: 1~~ + + +SELECT * FROM babel_3201_t_decimal; +GO +~~START~~ +bigint#!#int +7#!#5 +10#!#6 +13#!#7 +16#!#8 +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 +16#!#8 +13#!#9 +~~END~~ + + +BEGIN TRAN; + DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 20); + INSERT INTO babel_3201_t_decimal VALUES (11); +ROLLBACK; +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM babel_3201_t_decimal; +GO +~~START~~ +bigint#!#int +7#!#5 +10#!#6 +13#!#7 +16#!#8 +13#!#9 +~~END~~ + diff --git a/test/JDBC/input/BABEL-3201-vu-cleanup.sql b/test/JDBC/input/BABEL-3201-vu-cleanup.sql index a0808acee8..42d90f0554 100644 --- a/test/JDBC/input/BABEL-3201-vu-cleanup.sql +++ b/test/JDBC/input/BABEL-3201-vu-cleanup.sql @@ -1,9 +1,33 @@ +DROP TABLE babel_3201_t_int; +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 LOGIN babel_3201_log1; +GO + DROP SCHEMA babel_3201_sch1; GO diff --git a/test/JDBC/input/BABEL-3201-vu-prepare.sql b/test/JDBC/input/BABEL-3201-vu-prepare.sql index d91421b5a2..a51bb2cede 100644 --- a/test/JDBC/input/BABEL-3201-vu-prepare.sql +++ b/test/JDBC/input/BABEL-3201-vu-prepare.sql @@ -4,10 +4,31 @@ GO 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_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_sch1.babel_3201_t2(a varchar(20), b int identity); +CREATE TABLE babel_3201_t2( a int, b int); GO INSERT INTO babel_3201_t1 VALUES (1); @@ -15,3 +36,58 @@ 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 + diff --git a/test/JDBC/input/BABEL-3201-vu-verify.sql b/test/JDBC/input/BABEL-3201-vu-verify.sql index 7b6759cafd..21f43ef785 100644 --- a/test/JDBC/input/BABEL-3201-vu-verify.sql +++ b/test/JDBC/input/BABEL-3201-vu-verify.sql @@ -1,35 +1,218 @@ -DBCC CHECKIDENT(babel_3201_t1); +DBCC CHECKIDENT(babel_3201_t_int, 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 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 + increment). +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, 3); +GO + +INSERT INTO babel_3201_t_bigint VALUES (8); +GO + +SELECT * from babel_3201_t_bigint; +GO + +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) DBCC CHECKIDENT(babel_3201_t1, NORESEED); GO DBCC CHECKIDENT(babel_3201_t1, RESEED); GO +-- current identity value should be NULL (TO-DO), identity value inserted in +-- next INSERT operation should be new_reseed_value. DBCC CHECKIDENT(babel_3201_t1, RESEED, 5); GO -DBCC CHECKIDENT(babel_3201_t1) WITH NO_INFOMSGS; +INSERT INTO babel_3201_t_int VALUES (5); +GO + +SELECT * FROM babel_3201_t_int; GO +-- 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 + +-- 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 -DBCC CHECKIDENT(babel_3201_t1, RESEED, abc); +-- 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 + +-- Table undefined +DBCC CHECKIDENT(babel_3201_t1, RESEED); +GO + +-- Schema undefined +DBCC CHECKIDENT(babel_3201_sch3.babel_3201_t1, NORESEED); +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 + +INSERT INTO babel_3201_t_decimal VALUES (8); +GO + +SELECT * FROM babel_3201_t_decimal; +GO + +-- CREATE LOGIN babel_3201_log1 WITH PASSWORD='123456789'; +-- GO + +-- CREATE USER babel_3201_user1 FOR LOGIN babel_3201_log1; +-- GO + +-- tsql user=babel_3201_log1 password=123456789 +DBCC CHECKIDENT(babel_3201_t_decimal, RESEED); +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 + +SELECT * FROM babel_3201_t_decimal; +GO From eef6981be79e5766539acd8ea1a42bd71ee464d1 Mon Sep 17 00:00:00 2001 From: Aditya Verma Date: Wed, 23 Aug 2023 09:13:08 +0000 Subject: [PATCH 08/17] updated test cases and moved position of permission check Signed-off-by: Aditya Verma --- contrib/babelfishpg_tsql/src/iterative_exec.c | 6 --- contrib/babelfishpg_tsql/src/pl_exec-2.c | 15 +++--- test/JDBC/expected/BABEL-3201-vu-cleanup.out | 7 ++- test/JDBC/expected/BABEL-3201-vu-prepare.out | 9 ++++ test/JDBC/expected/BABEL-3201-vu-verify.out | 50 ++++++++++++------- test/JDBC/input/BABEL-3201-vu-cleanup.sql | 5 +- test/JDBC/input/BABEL-3201-vu-prepare.sql | 9 ++++ ...vu-verify.sql => BABEL-3201-vu-verify.mix} | 24 +++++---- 8 files changed, 76 insertions(+), 49 deletions(-) rename test/JDBC/input/{BABEL-3201-vu-verify.sql => BABEL-3201-vu-verify.mix} (94%) diff --git a/contrib/babelfishpg_tsql/src/iterative_exec.c b/contrib/babelfishpg_tsql/src/iterative_exec.c index 9e369fac62..8c12f87a68 100644 --- a/contrib/babelfishpg_tsql/src/iterative_exec.c +++ b/contrib/babelfishpg_tsql/src/iterative_exec.c @@ -829,12 +829,6 @@ 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: - if (pltsql_explain_only) - { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for DBCC statment is not yet supported"))); - } exec_stmt_dbcc(estate, (PLtsql_stmt_dbcc *) stmt); break; default: diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index de80323011..87dbfc64eb 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -2999,7 +2999,6 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) Oid nsp_oid; Oid table_oid; Oid seqid = InvalidOid; - Oid userid = GetUserId(); volatile bool cur_value_is_null = true; bool login_is_db_owner; @@ -3028,7 +3027,7 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) pfree(db_name); } - login_is_db_owner = 0 == strncmp(GetUserNameFromId(userid, false), + login_is_db_owner = 0 == strncmp(GetUserNameFromId(GetSessionUserId(), false), get_owner_of_db(db_name), NAMEDATALEN); user = get_user_for_database(db_name); guest_role_name = get_guest_role_name(db_name); @@ -3071,6 +3070,12 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) errmsg("schema \"%s\" does not exist", schema_name))); } + /* Permission check */ + if (!(pg_namespace_ownercheck(nsp_oid, GetUserId()) || + has_privs_of_role(GetUserId(), get_role_oid("sysadmin", false)) || + login_is_db_owner)) + aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SCHEMA, nsp_name); + table_name = pstrdup(dbcc_stmt.table_name); table_oid = get_relname_relid(table_name, nsp_oid); if(!OidIsValid(table_oid)) @@ -3080,12 +3085,6 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) errmsg("relation \"%s\" does not exist", table_name))); } - /* Permission check */ - if (!pg_namespace_ownercheck(nsp_oid, userid) || - !(has_privs_of_role(userid, get_role_oid("sysadmin", false)) || - !login_is_db_owner)) - aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SCHEMA, nsp_name); - rel = RelationIdGetRelation(table_oid); tupdesc = RelationGetDescr(rel); diff --git a/test/JDBC/expected/BABEL-3201-vu-cleanup.out b/test/JDBC/expected/BABEL-3201-vu-cleanup.out index dc33e9f050..9f6a4496d2 100644 --- a/test/JDBC/expected/BABEL-3201-vu-cleanup.out +++ b/test/JDBC/expected/BABEL-3201-vu-cleanup.out @@ -25,12 +25,11 @@ GO DROP TABLE babel_3201_sch1.babel_3201_t2; GO -DROP LOGIN babel_3201_log1; +DROP PROCEDURE babel_3201_proc1; GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: Cannot drop the login 'babel_3201_log1', because it does not exist or you do not have permission.)~~ +DROP PROCEDURE babel_3201_proc2; +GO DROP SCHEMA babel_3201_sch1; GO diff --git a/test/JDBC/expected/BABEL-3201-vu-prepare.out b/test/JDBC/expected/BABEL-3201-vu-prepare.out index d27a523ab3..e1c759cb23 100644 --- a/test/JDBC/expected/BABEL-3201-vu-prepare.out +++ b/test/JDBC/expected/BABEL-3201-vu-prepare.out @@ -131,3 +131,12 @@ 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 diff --git a/test/JDBC/expected/BABEL-3201-vu-verify.out b/test/JDBC/expected/BABEL-3201-vu-verify.out index 53900553db..814b59cf78 100644 --- a/test/JDBC/expected/BABEL-3201-vu-verify.out +++ b/test/JDBC/expected/BABEL-3201-vu-verify.out @@ -309,12 +309,8 @@ 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); +DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 15.65); GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: setval: value -15 is out of bounds for sequence "babel_3201_t_decimal_a_seq" (7..9223372036854775807))~~ - INSERT INTO babel_3201_t_decimal VALUES (8); GO @@ -328,20 +324,10 @@ bigint#!#int 7#!#5 10#!#6 13#!#7 -16#!#8 +18#!#8 ~~END~~ - - --- CREATE LOGIN babel_3201_log1 WITH PASSWORD='123456789'; --- GO --- CREATE USER babel_3201_user1 FOR LOGIN babel_3201_log1; --- GO --- tsql user=babel_3201_log1 password=123456789 -DBCC CHECKIDENT(babel_3201_t_decimal, RESEED); -GO - begin tran; DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 10); INSERT INTO babel_3201_t_decimal VALUES (9); @@ -357,7 +343,7 @@ bigint#!#int 7#!#5 10#!#6 13#!#7 -16#!#8 +18#!#8 13#!#9 ~~END~~ @@ -379,7 +365,7 @@ bigint#!#int 7#!#5 10#!#6 13#!#7 -16#!#8 +18#!#8 13#!#9 ~~END~~ @@ -399,7 +385,33 @@ bigint#!#int 7#!#5 10#!#6 13#!#7 -16#!#8 +18#!#8 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))~~ + diff --git a/test/JDBC/input/BABEL-3201-vu-cleanup.sql b/test/JDBC/input/BABEL-3201-vu-cleanup.sql index 42d90f0554..9f6a4496d2 100644 --- a/test/JDBC/input/BABEL-3201-vu-cleanup.sql +++ b/test/JDBC/input/BABEL-3201-vu-cleanup.sql @@ -25,7 +25,10 @@ GO DROP TABLE babel_3201_sch1.babel_3201_t2; GO -DROP LOGIN babel_3201_log1; +DROP PROCEDURE babel_3201_proc1; +GO + +DROP PROCEDURE babel_3201_proc2; GO DROP SCHEMA babel_3201_sch1; diff --git a/test/JDBC/input/BABEL-3201-vu-prepare.sql b/test/JDBC/input/BABEL-3201-vu-prepare.sql index a51bb2cede..9815f337eb 100644 --- a/test/JDBC/input/BABEL-3201-vu-prepare.sql +++ b/test/JDBC/input/BABEL-3201-vu-prepare.sql @@ -91,3 +91,12 @@ 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 diff --git a/test/JDBC/input/BABEL-3201-vu-verify.sql b/test/JDBC/input/BABEL-3201-vu-verify.mix similarity index 94% rename from test/JDBC/input/BABEL-3201-vu-verify.sql rename to test/JDBC/input/BABEL-3201-vu-verify.mix index 21f43ef785..33585b9df7 100644 --- a/test/JDBC/input/BABEL-3201-vu-verify.sql +++ b/test/JDBC/input/BABEL-3201-vu-verify.mix @@ -171,7 +171,7 @@ 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); +DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 15.65); GO INSERT INTO babel_3201_t_decimal VALUES (8); @@ -180,16 +180,6 @@ GO SELECT * FROM babel_3201_t_decimal; GO --- CREATE LOGIN babel_3201_log1 WITH PASSWORD='123456789'; --- GO - --- CREATE USER babel_3201_user1 FOR LOGIN babel_3201_log1; --- GO - --- tsql user=babel_3201_log1 password=123456789 -DBCC CHECKIDENT(babel_3201_t_decimal, RESEED); -GO - begin tran; DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 10); INSERT INTO babel_3201_t_decimal VALUES (9); @@ -216,3 +206,15 @@ GO SELECT * FROM babel_3201_t_decimal; 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 From b640db67365d4cf7c8d3a4ac095858d01b42d402 Mon Sep 17 00:00:00 2001 From: Aditya Verma Date: Fri, 25 Aug 2023 07:59:14 +0000 Subject: [PATCH 09/17] made updates - added permission related tests - updated BABEL-UNSUPPORTED tests - added Relation lock on table Signed-off-by: Aditya Verma --- contrib/babelfishpg_tsql/src/pl_exec-2.c | 41 +++++++++++++++++--- test/JDBC/expected/BABEL-3201-vu-cleanup.out | 3 ++ test/JDBC/expected/BABEL-3201-vu-prepare.out | 9 +++++ test/JDBC/expected/BABEL-3201-vu-verify.out | 31 +++++++++++++++ test/JDBC/expected/BABEL-UNSUPPORTED.out | 2 +- test/JDBC/input/BABEL-3201-vu-cleanup.sql | 3 ++ test/JDBC/input/BABEL-3201-vu-prepare.sql | 9 +++++ test/JDBC/input/BABEL-3201-vu-verify.mix | 27 +++++++++++++ 8 files changed, 119 insertions(+), 6 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index 87dbfc64eb..024212c732 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 "pltsql_bulkcopy.h" #include "table_variable_mvcc.h" @@ -2992,6 +2993,7 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) int64 max_identity_value = 0; int64 cur_identity_value = 0; char *max_identity_value_str = NULL; + char *login = GetUserNameFromId(GetSessionUserId(), false); char *token; int attnum; int rc; @@ -2999,9 +3001,12 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) 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; + + bool is_cross_db = false; if(dbcc_stmt.new_reseed_value) { /* If float value is passed as reseed_value, only decimal part is considered.*/ @@ -3014,10 +3019,13 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) pfree(token); } - if (dbcc_stmt.db_name) - db_name = pstrdup(dbcc_stmt.db_name); - else - db_name = get_cur_db_name(); + db_name = get_cur_db_name(); + if (dbcc_stmt.db_name) + { + if (pg_strcasecmp(db_name, dbcc_stmt.db_name) != 0) + is_cross_db = true; + db_name = pstrdup(dbcc_stmt.db_name); + } if (!DbidIsValid(get_db_id(db_name))) { @@ -3032,6 +3040,19 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) user = get_user_for_database(db_name); guest_role_name = get_guest_role_name(db_name); + if(is_cross_db) + { + if (user) + SetCurrentRoleId(GetSessionUserId(), false); + else + 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))); + } + pfree(login); + if (dbcc_stmt.schema_name) { schema_name = pstrdup(dbcc_stmt.schema_name); @@ -3072,7 +3093,7 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) /* Permission check */ if (!(pg_namespace_ownercheck(nsp_oid, GetUserId()) || - has_privs_of_role(GetUserId(), get_role_oid("sysadmin", false)) || + has_privs_of_role(GetSessionUserId(), get_role_oid("sysadmin", false)) || login_is_db_owner)) aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SCHEMA, nsp_name); @@ -3111,6 +3132,9 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) PG_TRY(); { + /* Lock table to ensure concurrency. eaaaa*/ + LockRelationOid( table_oid, RowExclusiveLock); + cur_identity_value = DirectFunctionCall1(pg_sequence_last_value, ObjectIdGetDatum(seqid)); cur_value_is_null = false; @@ -3170,6 +3194,9 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) Int64GetDatum(max_identity_value)); } } + if (is_cross_db) + SetCurrentRoleId(current_user_id, false); + UnlockRelationOid(table_oid, RowExclusiveLock); } PG_CATCH(); { @@ -3202,6 +3229,10 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) } else PG_RE_THROW(); + if (is_cross_db) + SetCurrentRoleId(current_user_id, false); + + UnlockRelationOid(table_oid, RowExclusiveLock); } PG_END_TRY(); diff --git a/test/JDBC/expected/BABEL-3201-vu-cleanup.out b/test/JDBC/expected/BABEL-3201-vu-cleanup.out index 9f6a4496d2..a3c5ec1438 100644 --- a/test/JDBC/expected/BABEL-3201-vu-cleanup.out +++ b/test/JDBC/expected/BABEL-3201-vu-cleanup.out @@ -31,6 +31,9 @@ GO DROP PROCEDURE babel_3201_proc2; GO +DROP LOGIN babel_3201_log1; +GO + DROP SCHEMA babel_3201_sch1; GO diff --git a/test/JDBC/expected/BABEL-3201-vu-prepare.out b/test/JDBC/expected/BABEL-3201-vu-prepare.out index e1c759cb23..26b45f48cc 100644 --- a/test/JDBC/expected/BABEL-3201-vu-prepare.out +++ b/test/JDBC/expected/BABEL-3201-vu-prepare.out @@ -140,3 +140,12 @@ CREATE PROCEDURE babel_3201_proc2 AS DBCC CHECKIDENT(babel_3201_t_tinyint, RESEED, 257) GO + +CREATE LOGIN babel_3201_log1 WITH PASSWORD='12345678'; +GO + +USE babel_3201_db1; +GO + +GRANT CONNECT TO guest; +GO diff --git a/test/JDBC/expected/BABEL-3201-vu-verify.out b/test/JDBC/expected/BABEL-3201-vu-verify.out index 814b59cf78..c6607b6520 100644 --- a/test/JDBC/expected/BABEL-3201-vu-verify.out +++ b/test/JDBC/expected/BABEL-3201-vu-verify.out @@ -415,3 +415,34 @@ GO ~~ERROR (Message: setval: value 257 is out of bounds for sequence "babel_3201_t_tinyint_a_seq" (5..255))~~ + +-- tsql user=babel_3201_log1 password=12345678 +-- Permission Check +USE babel_3201_db1; +GO + +-- should throw error +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 + +DBCC CHECKIDENT(master.dbo.babel_3201_t_tinyint, RESEED, 10) +GO + +-- tsql +USE master; +GO diff --git a/test/JDBC/expected/BABEL-UNSUPPORTED.out b/test/JDBC/expected/BABEL-UNSUPPORTED.out index 5d833af09c..6249cdeb8a 100644 --- a/test/JDBC/expected/BABEL-UNSUPPORTED.out +++ b/test/JDBC/expected/BABEL-UNSUPPORTED.out @@ -2542,7 +2542,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 index 9f6a4496d2..a3c5ec1438 100644 --- a/test/JDBC/input/BABEL-3201-vu-cleanup.sql +++ b/test/JDBC/input/BABEL-3201-vu-cleanup.sql @@ -31,6 +31,9 @@ GO DROP PROCEDURE babel_3201_proc2; GO +DROP LOGIN babel_3201_log1; +GO + DROP SCHEMA babel_3201_sch1; GO diff --git a/test/JDBC/input/BABEL-3201-vu-prepare.sql b/test/JDBC/input/BABEL-3201-vu-prepare.sql index 9815f337eb..a98d26821a 100644 --- a/test/JDBC/input/BABEL-3201-vu-prepare.sql +++ b/test/JDBC/input/BABEL-3201-vu-prepare.sql @@ -100,3 +100,12 @@ CREATE PROCEDURE babel_3201_proc2 AS DBCC CHECKIDENT(babel_3201_t_tinyint, RESEED, 257) GO + +CREATE LOGIN babel_3201_log1 WITH PASSWORD='12345678'; +GO + +USE babel_3201_db1; +GO + +GRANT CONNECT TO guest; +GO diff --git a/test/JDBC/input/BABEL-3201-vu-verify.mix b/test/JDBC/input/BABEL-3201-vu-verify.mix index 33585b9df7..fd7f1611c4 100644 --- a/test/JDBC/input/BABEL-3201-vu-verify.mix +++ b/test/JDBC/input/BABEL-3201-vu-verify.mix @@ -218,3 +218,30 @@ GO EXEC babel_3201_proc2; GO + +-- Permission Check +-- tsql user=babel_3201_log1 password=12345678 +USE babel_3201_db1; +GO + +-- should throw error +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 + +DBCC CHECKIDENT(master.dbo.babel_3201_t_tinyint, RESEED, 10) +GO + +-- tsql +USE master; +GO From 2d740ac850551f299981f198dafb0d7cc477d8cb Mon Sep 17 00:00:00 2001 From: Sandeep Kumawat Date: Tue, 19 Sep 2023 17:58:31 +0000 Subject: [PATCH 10/17] implement output messages for dbcc checkident --- contrib/babelfishpg_tsql/src/pl_exec-2.c | 29 ++++++++------------- test/JDBC/expected/BABEL-3201-vu-verify.out | 10 +++++++ 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index a721662061..d6e0474c16 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -3161,6 +3161,7 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) Oid current_user_id = GetUserId(); volatile bool cur_value_is_null = true; bool login_is_db_owner; + char message[200]; bool is_cross_db = false; @@ -3303,9 +3304,7 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) * DBCC command option. */ if (!dbcc_stmt.no_infomsgs) - ereport(WARNING, - (errmsg("Checking identity information: current" - " identity value '%ld'.\n", cur_identity_value))); + snprintf(message, sizeof(message), "Checking identity information: current identity value '%ld'.\n", cur_identity_value); DirectFunctionCall2(setval_oid, ObjectIdGetDatum(seqid), @@ -3328,12 +3327,9 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) max_identity_value = pg_strtoint64(max_identity_value_str); if (!dbcc_stmt.no_infomsgs) - ereport(WARNING, - (errmsg("Checking identity information: current" - " identity value '%ld', current column value " - "'%s'.\n", cur_identity_value, - max_identity_value_str ? - max_identity_value_str : "NULL"))); + 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"); pfree(query); SPI_freetuptable(SPI_tuptable); @@ -3368,9 +3364,7 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) { if (dbcc_stmt.new_reseed_value) { - ereport(WARNING, - (errmsg("Checking identity information: current" - " identity value 'NULL'.\n"))); + snprintf(message, sizeof(message), "Checking identity information: current identity value 'NULL'.\n"); DirectFunctionCall3(setval3_oid, ObjectIdGetDatum(seqid), @@ -3379,9 +3373,7 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) } else { - ereport(WARNING, - (errmsg("Checking identity information: current" - " identity value 'NULL', current column value 'NULL'.\n"))); + snprintf(message, sizeof(message), "Checking identity information: current identity value 'NULL', current column value 'NULL'.\n"); } } else @@ -3401,9 +3393,10 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) if (!dbcc_stmt.no_infomsgs) { - ereport(WARNING, - (errmsg( "DBCC execution completed. If DBCC printed error messages," - " contact your system administrator."))); + 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); } } diff --git a/test/JDBC/expected/BABEL-3201-vu-verify.out b/test/JDBC/expected/BABEL-3201-vu-verify.out index c6607b6520..793f3025ba 100644 --- a/test/JDBC/expected/BABEL-3201-vu-verify.out +++ b/test/JDBC/expected/BABEL-3201-vu-verify.out @@ -333,6 +333,11 @@ 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 '18'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + ~~ROW COUNT: 1~~ @@ -375,6 +380,11 @@ BEGIN TRAN; 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~~ From a434ef73d16e7a6d36e00f00dc79b588069a98ef Mon Sep 17 00:00:00 2001 From: Siddhi Jain Date: Thu, 21 Sep 2023 19:10:50 +0000 Subject: [PATCH 11/17] Re-implemented lock --- contrib/babelfishpg_tsql/src/pl_exec-2.c | 23 +++++++++++++++------- contrib/babelfishpg_tsql/src/tsqlIface.cpp | 2 +- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index d6e0474c16..7a9203e729 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -3290,13 +3290,18 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) PG_TRY(); { - /* Lock table to ensure concurrency. eaaaa*/ - LockRelationOid( table_oid, RowExclusiveLock); - + // Lock table to ensure concurrency. + if(dbcc_stmt.is_reseed) + { + LockRelationOid( table_oid, AccessExclusiveLock); + } + else + { + LockRelationOid( table_oid, ShareLock); + } cur_identity_value = DirectFunctionCall1(pg_sequence_last_value, ObjectIdGetDatum(seqid)); cur_value_is_null = false; - if (dbcc_stmt.new_reseed_value) { /* @@ -3349,7 +3354,6 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) } if (is_cross_db) SetCurrentRoleId(current_user_id, false); - UnlockRelationOid(table_oid, RowExclusiveLock); } PG_CATCH(); { @@ -3380,10 +3384,9 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) PG_RE_THROW(); if (is_cross_db) SetCurrentRoleId(current_user_id, false); - - UnlockRelationOid(table_oid, RowExclusiveLock); } PG_END_TRY(); + if (max_identity_value_str) pfree(max_identity_value_str); @@ -3391,6 +3394,10 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) pfree(table_name); pfree(nsp_name); + if(!dbcc_stmt.is_reseed) + { + UnlockRelationOid(table_oid,ShareLock); + } if (!dbcc_stmt.no_infomsgs) { strcat(message, "DBCC execution completed. If DBCC printed error messages, contact your system administrator."); @@ -3398,6 +3405,8 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->send_info) ((*pltsql_protocol_plugin_ptr)->send_info) (0, 1, 0, message, 0); } + + } diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index 3fc0c31540..acd5916d73 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -5359,7 +5359,7 @@ makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx) } else if (ctx->NORESEED()) { - stmt->dbcc_stmt_data.dbcc_checkident.is_reseed = false; + is_reseed = false; } if(ctx->dbcc_options()) From 10a35bcd89a0fb799e2a38ab9084140125168915 Mon Sep 17 00:00:00 2001 From: Sandeep Kumawat Date: Sun, 1 Oct 2023 21:38:41 +0000 Subject: [PATCH 12/17] This commit includes- - fix for locking behaviour - tests in isolation test framework for concurrency - Add some missing jdbc tests - Address review comments Signed-off-by: Sandeep Kumawat --- contrib/babelfishpg_tsql/src/pl_exec-2.c | 150 +++++++++-------- test/JDBC/expected/BABEL-3201-vu-prepare.out | 5 - test/JDBC/expected/BABEL-3201-vu-verify.out | 160 +++++++++++++++---- test/JDBC/input/BABEL-3201-vu-prepare.sql | 3 - test/JDBC/input/BABEL-3201-vu-verify.mix | 75 +++++++-- test/python/expected/pyodbc/BABEL-3201.out | 56 +++++++ test/python/input/isolation/BABEL-3201.spec | 47 ++++++ 7 files changed, 372 insertions(+), 124 deletions(-) create mode 100644 test/python/expected/pyodbc/BABEL-3201.out create mode 100644 test/python/input/isolation/BABEL-3201.spec diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index 7a9203e729..ec22e41bf1 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -3180,7 +3180,7 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) db_name = get_cur_db_name(); if (dbcc_stmt.db_name) { - if (pg_strcasecmp(db_name, dbcc_stmt.db_name) != 0) + if (pg_strncasecmp(db_name, dbcc_stmt.db_name, NAMEDATALEN) != 0) is_cross_db = true; db_name = pstrdup(dbcc_stmt.db_name); } @@ -3290,73 +3290,32 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) PG_TRY(); { - // Lock table to ensure concurrency. - if(dbcc_stmt.is_reseed) - { - LockRelationOid( table_oid, AccessExclusiveLock); - } - else - { - LockRelationOid( table_oid, ShareLock); - } cur_identity_value = DirectFunctionCall1(pg_sequence_last_value, - ObjectIdGetDatum(seqid)); + ObjectIdGetDatum(seqid)); cur_value_is_null = false; - 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); + } + PG_CATCH(); + { + FlushErrorState(); + } + PG_END_TRY(); - DirectFunctionCall2(setval_oid, - ObjectIdGetDatum(seqid), - Int64GetDatum(reseed_value)); + 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 { - SPI_connect(); - query = psprintf("SELECT MAX(%s) FROM %s.%s", attname, - schema_name, 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); - - 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"); - - pfree(query); - SPI_freetuptable(SPI_tuptable); - - /* - * 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)); - } + LockRelationOid(table_oid, ShareLock); } - if (is_cross_db) - SetCurrentRoleId(current_user_id, false); - } - PG_CATCH(); - { + /* * 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 @@ -3380,24 +3339,82 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) snprintf(message, sizeof(message), "Checking identity information: current identity value 'NULL', current column value 'NULL'.\n"); } } + else - PG_RE_THROW(); + { + 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, 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); + + 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"); + + pfree(query); + SPI_freetuptable(SPI_tuptable); + + /* + * 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(); + { + PG_RE_THROW(); if (is_cross_db) SetCurrentRoleId(current_user_id, false); } PG_END_TRY(); - if (max_identity_value_str) pfree(max_identity_value_str); pfree(schema_name); pfree(table_name); pfree(nsp_name); - if(!dbcc_stmt.is_reseed) + if(!dbcc_stmt.new_reseed_value) { - UnlockRelationOid(table_oid,ShareLock); - } + UnlockRelationOid(table_oid, ShareLock); + } if (!dbcc_stmt.no_infomsgs) { strcat(message, "DBCC execution completed. If DBCC printed error messages, contact your system administrator."); @@ -3406,7 +3423,6 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) ((*pltsql_protocol_plugin_ptr)->send_info) (0, 1, 0, message, 0); } - } diff --git a/test/JDBC/expected/BABEL-3201-vu-prepare.out b/test/JDBC/expected/BABEL-3201-vu-prepare.out index 26b45f48cc..852f103f15 100644 --- a/test/JDBC/expected/BABEL-3201-vu-prepare.out +++ b/test/JDBC/expected/BABEL-3201-vu-prepare.out @@ -31,11 +31,6 @@ GO CREATE TABLE babel_3201_t2( a int, b int); GO -INSERT INTO babel_3201_t1 VALUES (1); -GO -~~ROW COUNT: 1~~ - - INSERT INTO babel_3201_sch1.babel_3201_t2 VALUES ('string 1'); GO ~~ROW COUNT: 1~~ diff --git a/test/JDBC/expected/BABEL-3201-vu-verify.out b/test/JDBC/expected/BABEL-3201-vu-verify.out index 793f3025ba..fd4b0cec1a 100644 --- a/test/JDBC/expected/BABEL-3201-vu-verify.out +++ b/test/JDBC/expected/BABEL-3201-vu-verify.out @@ -30,18 +30,16 @@ int#!#int DBCC CHECKIDENT(babel_3201_sch1.babel_3201_t2); GO --- Set identity value to 5 which is less than the maximum value of the identity +-- 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 + increment). -DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, 3); +-- 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~~ @@ -49,18 +47,17 @@ bigint#!#int 3#!#5 6#!#6 9#!#6 -6#!#8 +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~~ @@ -68,54 +65,101 @@ bigint#!#int 3#!#5 6#!#6 9#!#6 -6#!#8 +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)~~ -INSERT INTO babel_3201_t_int VALUES (5); -GO ~~ROW COUNT: 1~~ -SELECT * FROM babel_3201_t_int; +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 -1#!#5 -2#!#6 -3#!#7 -4#!#8 -5#!#5 +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~~ @@ -124,26 +168,61 @@ int#!#int ~~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 -13#!#5 +16#!#5 +30#!#32 ~~END~~ @@ -210,16 +289,20 @@ GO ~~ERROR (Message: database "fake_db" does not exist)~~ --- Table undefined -DBCC CHECKIDENT(babel_3201_t1, RESEED); +-- Schema undefined +DBCC CHECKIDENT(fake_schema.babel_3201_t1, NORESEED); GO +~~ERROR (Code: 33557097)~~ --- Schema undefined -DBCC CHECKIDENT(babel_3201_sch3.babel_3201_t1, NORESEED); +~~ERROR (Message: schema "master_fake_schema" does not exist)~~ + + +-- Table undefined +DBCC CHECKIDENT(fake_babel_3201_t1, RESEED); GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: schema "master_babel_3201_sch3" does not exist)~~ +~~ERROR (Message: relation "fake_babel_3201_t1" does not exist)~~ -- Table does not have identity column @@ -312,9 +395,15 @@ GO 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) +dbcc checkident(babel_3201_t_decimal, reseed, 0) INSERT INTO babel_3201_t_decimal VALUES (8); GO -~~ROW COUNT: 1~~ +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value -10 is out of bounds for sequence "babel_3201_t_decimal_a_seq" (7..9223372036854775807))~~ SELECT * FROM babel_3201_t_decimal; @@ -324,7 +413,6 @@ bigint#!#int 7#!#5 10#!#6 13#!#7 -18#!#8 ~~END~~ @@ -335,7 +423,7 @@ commit; go ~~WARNING (Code: 0)~~ -~~WARNING (Message: Checking identity information: current identity value '18'. +~~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~~ @@ -348,7 +436,6 @@ bigint#!#int 7#!#5 10#!#6 13#!#7 -18#!#8 13#!#9 ~~END~~ @@ -370,7 +457,6 @@ bigint#!#int 7#!#5 10#!#6 13#!#7 -18#!#8 13#!#9 ~~END~~ @@ -388,14 +474,24 @@ DBCC execution completed. If DBCC printed error messages, contact your system ad ~~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 -18#!#8 13#!#9 ~~END~~ diff --git a/test/JDBC/input/BABEL-3201-vu-prepare.sql b/test/JDBC/input/BABEL-3201-vu-prepare.sql index a98d26821a..a758c3b91b 100644 --- a/test/JDBC/input/BABEL-3201-vu-prepare.sql +++ b/test/JDBC/input/BABEL-3201-vu-prepare.sql @@ -31,9 +31,6 @@ GO CREATE TABLE babel_3201_t2( a int, b int); GO -INSERT INTO babel_3201_t1 VALUES (1); -GO - INSERT INTO babel_3201_sch1.babel_3201_t2 VALUES ('string 1'); GO diff --git a/test/JDBC/input/BABEL-3201-vu-verify.mix b/test/JDBC/input/BABEL-3201-vu-verify.mix index fd7f1611c4..01168b7da9 100644 --- a/test/JDBC/input/BABEL-3201-vu-verify.mix +++ b/test/JDBC/input/BABEL-3201-vu-verify.mix @@ -20,72 +20,103 @@ GO DBCC CHECKIDENT(babel_3201_sch1.babel_3201_t2); GO --- Set identity value to 5 which is less than the maximum value of the identity +-- 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 + increment). -DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, 3); +-- 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 -INSERT INTO babel_3201_t_int VALUES (5); +BEGIN TRAN; +DBCC CHECKIDENT(babel_3201_t1, NORESEED); +select * from babel_3201_t1; +COMMIT; GO -SELECT * FROM babel_3201_t_int; +-- 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 @@ -120,12 +151,12 @@ GO DBCC CHECKIDENT(fake_db.dbo.babel_3201_t1, NORESEED); GO --- Table undefined -DBCC CHECKIDENT(babel_3201_t1, RESEED); +-- Schema undefined +DBCC CHECKIDENT(fake_schema.babel_3201_t1, NORESEED); GO --- Schema undefined -DBCC CHECKIDENT(babel_3201_sch3.babel_3201_t1, NORESEED); +-- Table undefined +DBCC CHECKIDENT(fake_babel_3201_t1, RESEED); GO -- Table does not have identity column @@ -174,6 +205,10 @@ GO 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) +dbcc checkident(babel_3201_t_decimal, reseed, 0) + INSERT INTO babel_3201_t_decimal VALUES (8); GO @@ -204,7 +239,13 @@ BEGIN TRAN; 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; 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..5622d77db0 --- /dev/null +++ b/test/python/input/isolation/BABEL-3201.spec @@ -0,0 +1,47 @@ +setup +{ + + create database babel_3201_dbcc_check; + use babel_3201_dbcc_check; + 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 +{ + use master; + drop database babel_3201_dbcc_check; +} + +session s1 +setup { + use babel_3201_dbcc_check; + 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 { + use babel_3201_dbcc_check; + 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 + From 748739c9e9ab699c3da53227355674a4e7bc46fc Mon Sep 17 00:00:00 2001 From: Sandeep Kumawat Date: Wed, 4 Oct 2023 13:51:30 +0000 Subject: [PATCH 13/17] Fix: test failures Signed-off-by: Sandeep Kumawat --- contrib/babelfishpg_tsql/src/pl_exec-2.c | 4 ---- test/python/input/isolation/BABEL-3201.spec | 7 +------ 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index ec22e41bf1..aeb8f23251 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -3170,10 +3170,6 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) /* If float value is passed as reseed_value, only decimal part is considered.*/ token = strtok(dbcc_stmt.new_reseed_value, "."); reseed_value = pg_strtoint64(token); - if(reseed_value >= 0) - reseed_value = floor(reseed_value); - else - reseed_value = -floor(-reseed_value); pfree(token); } diff --git a/test/python/input/isolation/BABEL-3201.spec b/test/python/input/isolation/BABEL-3201.spec index 5622d77db0..4ebe71dc3e 100644 --- a/test/python/input/isolation/BABEL-3201.spec +++ b/test/python/input/isolation/BABEL-3201.spec @@ -1,8 +1,6 @@ setup { - create database babel_3201_dbcc_check; - use babel_3201_dbcc_check; create table dbcc_test_locks (a int identity, b int); INSERT INTO dbcc_test_locks VALUES (5); INSERT INTO dbcc_test_locks VALUES (7); @@ -11,13 +9,11 @@ setup teardown { - use master; - drop database babel_3201_dbcc_check; + drop table dbcc_test_locks; } session s1 setup { - use babel_3201_dbcc_check; BEGIN TRAN TR1; } step s1dbcc_noreseed { dbcc checkident(dbcc_test_locks, NORESEED) } @@ -29,7 +25,6 @@ step s1c { COMMIT; } session s2 setup { - use babel_3201_dbcc_check; BEGIN TRAN TR2; } step s2s { SELECT * from dbcc_test_locks; } From a8649df577284539d2b1d8fb28969ddbb76a69bc Mon Sep 17 00:00:00 2001 From: Sandeep Kumawat Date: Thu, 12 Oct 2023 00:24:29 +0000 Subject: [PATCH 14/17] This commit includes - Correct Parser Support for DBCC CHECKIDENT, in quotes is the correct way. - Update test files accordingly - Adds more test-cases for cross-db errors, db_name longer then 63, Mixed-cases names, etc. - Made updates to free memory in case of errors Signed-off-by: Sandeep Kumawat --- contrib/babelfishpg_tsql/antlr/TSqlParser.g4 | 13 +- contrib/babelfishpg_tsql/src/pl_exec-2.c | 178 +++++++++++-------- contrib/babelfishpg_tsql/src/tsqlIface.cpp | 87 ++++++--- test/JDBC/expected/BABEL-3201-vu-cleanup.out | 12 ++ test/JDBC/expected/BABEL-3201-vu-prepare.out | 21 ++- test/JDBC/expected/BABEL-3201-vu-verify.out | 172 +++++++++++++++++- test/JDBC/input/BABEL-3201-vu-cleanup.sql | 12 ++ test/JDBC/input/BABEL-3201-vu-prepare.sql | 21 ++- test/JDBC/input/BABEL-3201-vu-verify.mix | 148 ++++++++++++++- 9 files changed, 528 insertions(+), 136 deletions(-) diff --git a/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 b/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 index 0cf446bb56..88a8c42081 100644 --- a/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 +++ b/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 @@ -3094,7 +3094,7 @@ shutdown_statement ; dbcc_statement - : DBCC CHECKIDENT ( LR_BRACKET table_name ( (COMMA NORESEED) | (COMMA RESEED (COMMA MINUS? new_value=(DECIMAL | FLOAT))?) )? 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? @@ -3134,6 +3134,13 @@ dbcc_options : ID (COMMA ID)? ; + +table_name_string + : table = id + | char_string + ; + + execute_as_clause : (EXECUTE|EXEC) AS (CALLER | SELF | OWNER | char_string) ; @@ -5156,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/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index aeb8f23251..55e196c65c 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -3136,81 +3136,99 @@ int exec_stmt_dbcc(PLtsql_execstate *estate, PLtsql_stmt_dbcc *stmt) void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) { - struct dbcc_checkident dbcc_stmt = stmt->dbcc_stmt_data.dbcc_checkident; + struct dbcc_checkident dbcc_stmt = stmt->dbcc_stmt_data.dbcc_checkident; Relation rel; TupleDesc tupdesc; char *db_name = NULL; - char *schema_name = NULL; - char *nsp_name = NULL; - char *table_name; - char *query; + 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; - char *max_identity_value_str = NULL; - char *login = GetUserNameFromId(GetSessionUserId(), false); - char *token; - int attnum; - int rc; + int attnum; + int rc; int64 reseed_value = 0; - Oid nsp_oid; + Oid nsp_oid; Oid table_oid; - Oid seqid = InvalidOid; - Oid current_user_id = GetUserId(); + Oid seqid = InvalidOid; + Oid current_user_id = GetUserId(); volatile bool cur_value_is_null = true; bool login_is_db_owner; - char message[200]; - + char message[200]; + bool is_float_value; + bool is_cross_db = false; - bool is_cross_db = false; if(dbcc_stmt.new_reseed_value) { - /* If float value is passed as reseed_value, only decimal part is considered.*/ - token = strtok(dbcc_stmt.new_reseed_value, "."); - reseed_value = pg_strtoint64(token); - pfree(token); - } - - db_name = get_cur_db_name(); - if (dbcc_stmt.db_name) - { - if (pg_strncasecmp(db_name, dbcc_stmt.db_name, NAMEDATALEN) != 0) - is_cross_db = true; - db_name = pstrdup(dbcc_stmt.db_name); - } + /* 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 (!DbidIsValid(get_db_id(db_name))) - { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_DATABASE), - errmsg("database \"%s\" does not exist", db_name))); - pfree(db_name); + 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); - user = get_user_for_database(db_name); - guest_role_name = get_guest_role_name(db_name); - - if(is_cross_db) - { - if (user) - SetCurrentRoleId(GetSessionUserId(), false); - else - 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))); - } - pfree(login); + /* 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 = pstrdup(dbcc_stmt.schema_name); - nsp_name = get_physical_schema_name(db_name, schema_name); + schema_name = dbcc_stmt.schema_name; + nsp_name = get_physical_schema_name(db_name, dbcc_stmt.schema_name); } else { @@ -3218,26 +3236,37 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) * 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); if (!user) { + pfree(db_name); ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("user does not exist"))); + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("user does not exist"))); + } + 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 = pstrdup(get_guest_schema_name(db_name)); + nsp_name = get_guest_schema_name(db_name); } else { - schema_name = get_authid_user_ext_schema_name((const char *) db_name, user); - nsp_name = get_physical_schema_name(db_name, schema_name); + nsp_name = get_physical_schema_name(db_name, dbcc_stmt.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, @@ -3251,13 +3280,12 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) login_is_db_owner)) aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SCHEMA, nsp_name); - table_name = pstrdup(dbcc_stmt.table_name); - table_oid = get_relname_relid(table_name, nsp_oid); + 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", table_name))); + errmsg("relation \"%s\" does not exist", dbcc_stmt.table_name))); } rel = RelationIdGetRelation(table_oid); @@ -3279,10 +3307,12 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) RelationClose(rel); if (!OidIsValid(seqid)) + { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("'%s.%s' does not contain an identity column.", - nsp_name, table_name))); + nsp_name, dbcc_stmt.table_name))); + } PG_TRY(); { @@ -3355,7 +3385,7 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) { SPI_connect(); query = psprintf("SELECT MAX(%s) FROM %s.%s", attname, - schema_name, table_name); + schema_name, dbcc_stmt.table_name); rc = SPI_execute(query, true, 0); if (rc != SPI_OK_SELECT) @@ -3372,7 +3402,6 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) cur_identity_value, max_identity_value_str ? max_identity_value_str : "NULL"); - pfree(query); SPI_freetuptable(SPI_tuptable); /* @@ -3391,21 +3420,30 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) } if (is_cross_db) - SetCurrentRoleId(current_user_id, false); + 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(!dbcc_stmt.new_reseed_value) + { + UnlockRelationOid(table_oid, ShareLock); + } + PG_RE_THROW(); - if (is_cross_db) - SetCurrentRoleId(current_user_id, false); } PG_END_TRY(); + if(query) + pfree(query); if (max_identity_value_str) pfree(max_identity_value_str); - pfree(schema_name); - pfree(table_name); - pfree(nsp_name); if(!dbcc_stmt.new_reseed_value) { diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index f60887e83a..990db2947c 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -1893,12 +1893,9 @@ class tsqlBuilder : public tsqlCommonMutator void enterDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) override { if (ctx->CHECKIDENT()) - graft(makeDbccCheckidentStatement(ctx), peekContainer()); + graft(makeDbccCheckidentStatement(ctx), peekContainer()); clear_rewritten_query_fragment(); - // PLtsql_stmt_execsql *stmt = (PLtsql_stmt_execsql *) getPLtsql_fragment(ctx); - // Assert(stmt); - // statementMutator = std::make_unique(stmt->sqlstmt, ctx); } void exitDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) override @@ -5437,37 +5434,40 @@ makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx) { PLtsql_stmt_dbcc *stmt = (PLtsql_stmt_dbcc *) palloc0(sizeof(*stmt)); - std::string db_name; - std::string schema_name; - std::string table_name; - std::string new_reseed_value; - bool is_reseed = true; - bool no_infomsgs = false; + 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()) - { - if (ctx->table_name()->database) - db_name = stripQuoteFromId(ctx->table_name()->database); - if (ctx->table_name()->schema) - schema_name = stripQuoteFromId(ctx->table_name()->schema); - if (ctx->table_name()->table) - table_name = stripQuoteFromId(ctx->table_name()->table); - - if (!db_name.empty()) - stmt->dbcc_stmt_data.dbcc_checkident.db_name = pstrdup(downcase_truncate_identifier(db_name.c_str(), db_name.length(), true)); - if (!schema_name.empty()) - stmt->dbcc_stmt_data.dbcc_checkident.schema_name = pstrdup(downcase_truncate_identifier(schema_name.c_str(), schema_name.length(), true)); - if (!table_name.empty()) - stmt->dbcc_stmt_data.dbcc_checkident.table_name = pstrdup(downcase_truncate_identifier(table_name.c_str(), table_name.length(), true)); + 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()); @@ -5480,7 +5480,8 @@ makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx) if(ctx->dbcc_options()) { - if (pg_strcasecmp(::getFullText(ctx->dbcc_options()).c_str(), "NO_INFOMSGS") == 0){ + if (pg_strcasecmp(::getFullText(ctx->dbcc_options()).c_str(), "NO_INFOMSGS") == 0) + { no_infomsgs = true; } else @@ -5492,8 +5493,40 @@ makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx) } } } + + 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; } diff --git a/test/JDBC/expected/BABEL-3201-vu-cleanup.out b/test/JDBC/expected/BABEL-3201-vu-cleanup.out index a3c5ec1438..a8fd1ec7fd 100644 --- a/test/JDBC/expected/BABEL-3201-vu-cleanup.out +++ b/test/JDBC/expected/BABEL-3201-vu-cleanup.out @@ -1,6 +1,18 @@ 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 diff --git a/test/JDBC/expected/BABEL-3201-vu-prepare.out b/test/JDBC/expected/BABEL-3201-vu-prepare.out index 852f103f15..6db69d5bab 100644 --- a/test/JDBC/expected/BABEL-3201-vu-prepare.out +++ b/test/JDBC/expected/BABEL-3201-vu-prepare.out @@ -1,6 +1,3 @@ -CREATE DATABASE babel_3201_db1; -GO - CREATE SCHEMA babel_3201_sch1; GO @@ -10,6 +7,18 @@ 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 @@ -138,9 +147,3 @@ GO CREATE LOGIN babel_3201_log1 WITH PASSWORD='12345678'; GO - -USE babel_3201_db1; -GO - -GRANT CONNECT TO guest; -GO diff --git a/test/JDBC/expected/BABEL-3201-vu-verify.out b/test/JDBC/expected/BABEL-3201-vu-verify.out index fd4b0cec1a..e9b536e4e4 100644 --- a/test/JDBC/expected/BABEL-3201-vu-verify.out +++ b/test/JDBC/expected/BABEL-3201-vu-verify.out @@ -1,6 +1,52 @@ 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 @@ -27,7 +73,7 @@ int#!#int ~~END~~ -DBCC CHECKIDENT(babel_3201_sch1.babel_3201_t2); +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 @@ -282,7 +328,7 @@ GO -- Database undefined -DBCC CHECKIDENT(fake_db.dbo.babel_3201_t1, NORESEED); +DBCC CHECKIDENT('fake_db.dbo.babel_3201_t1', NORESEED); GO ~~ERROR (Code: 911)~~ @@ -290,7 +336,7 @@ GO -- Schema undefined -DBCC CHECKIDENT(fake_schema.babel_3201_t1, NORESEED); +DBCC CHECKIDENT('fake_schema.babel_3201_t1', NORESEED); GO ~~ERROR (Code: 33557097)~~ @@ -395,16 +441,31 @@ GO 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) -dbcc checkident(babel_3201_t_decimal, reseed, 0) -INSERT INTO babel_3201_t_decimal VALUES (8); 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))~~ + SELECT * FROM babel_3201_t_decimal; GO @@ -522,13 +583,105 @@ GO ~~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 + +-- drop this db because of single_mod +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 + +-- 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..t1', 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 -DBCC CHECKIDENT(master.dbo.babel_3201_t_tinyint, RESEED, 10) +-- should throw error - must be owner of schema master_dbo +DBCC CHECKIDENT('master.dbo.babel_3201_t_tinyint', RESEED, 10) GO ~~ERROR (Code: 33557097)~~ @@ -546,7 +699,8 @@ GO USE babel_3201_db1; GO -DBCC CHECKIDENT(master.dbo.babel_3201_t_tinyint, RESEED, 10) +-- This should work correctly +DBCC CHECKIDENT('master.dbo.babel_3201_t_tinyint', RESEED, 10) GO -- tsql diff --git a/test/JDBC/input/BABEL-3201-vu-cleanup.sql b/test/JDBC/input/BABEL-3201-vu-cleanup.sql index a3c5ec1438..a8fd1ec7fd 100644 --- a/test/JDBC/input/BABEL-3201-vu-cleanup.sql +++ b/test/JDBC/input/BABEL-3201-vu-cleanup.sql @@ -1,6 +1,18 @@ 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 diff --git a/test/JDBC/input/BABEL-3201-vu-prepare.sql b/test/JDBC/input/BABEL-3201-vu-prepare.sql index a758c3b91b..faa32eaeba 100644 --- a/test/JDBC/input/BABEL-3201-vu-prepare.sql +++ b/test/JDBC/input/BABEL-3201-vu-prepare.sql @@ -1,6 +1,3 @@ -CREATE DATABASE babel_3201_db1; -GO - CREATE SCHEMA babel_3201_sch1; GO @@ -10,6 +7,18 @@ 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 @@ -100,9 +109,3 @@ GO CREATE LOGIN babel_3201_log1 WITH PASSWORD='12345678'; GO - -USE babel_3201_db1; -GO - -GRANT CONNECT TO guest; -GO diff --git a/test/JDBC/input/BABEL-3201-vu-verify.mix b/test/JDBC/input/BABEL-3201-vu-verify.mix index 01168b7da9..a94b407dfc 100644 --- a/test/JDBC/input/BABEL-3201-vu-verify.mix +++ b/test/JDBC/input/BABEL-3201-vu-verify.mix @@ -1,6 +1,44 @@ 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 @@ -17,7 +55,7 @@ GO SELECT * FROM babel_3201_t_int; GO -DBCC CHECKIDENT(babel_3201_sch1.babel_3201_t2); +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 @@ -148,11 +186,11 @@ DBCC FAKE_COMMAND(t1); GO -- Database undefined -DBCC CHECKIDENT(fake_db.dbo.babel_3201_t1, NORESEED); +DBCC CHECKIDENT('fake_db.dbo.babel_3201_t1', NORESEED); GO -- Schema undefined -DBCC CHECKIDENT(fake_schema.babel_3201_t1, NORESEED); +DBCC CHECKIDENT('fake_schema.babel_3201_t1', NORESEED); GO -- Table undefined @@ -207,10 +245,13 @@ 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) -dbcc checkident(babel_3201_t_decimal, reseed, 0) - -INSERT INTO babel_3201_t_decimal VALUES (8); 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 SELECT * FROM babel_3201_t_decimal; GO @@ -260,13 +301,101 @@ 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 + +-- drop this db because of single_mod +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 + +-- 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..t1', 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 -DBCC CHECKIDENT(master.dbo.babel_3201_t_tinyint, RESEED, 10) +-- should throw error - must be owner of schema master_dbo +DBCC CHECKIDENT('master.dbo.babel_3201_t_tinyint', RESEED, 10) GO -- tsql @@ -280,7 +409,8 @@ GO USE babel_3201_db1; GO -DBCC CHECKIDENT(master.dbo.babel_3201_t_tinyint, RESEED, 10) +-- This should work correctly +DBCC CHECKIDENT('master.dbo.babel_3201_t_tinyint', RESEED, 10) GO -- tsql From a1a27c80833429942171f928e414cb472e6d0264 Mon Sep 17 00:00:00 2001 From: Sandeep Kumawat Date: Tue, 17 Oct 2023 20:55:33 +0000 Subject: [PATCH 15/17] Address review comments Signed-off-by: Sandeep Kumawat --- contrib/babelfishpg_tsql/antlr/TSqlParser.g4 | 1 - contrib/babelfishpg_tsql/src/pl_exec-2.c | 4 +--- contrib/babelfishpg_tsql/src/pltsql.h | 20 +++++++++---------- test/JDBC/expected/BABEL-3201-vu-verify.out | 21 +++++++++++++++++++- test/JDBC/input/BABEL-3201-vu-verify.mix | 17 +++++++++++++++- 5 files changed, 47 insertions(+), 16 deletions(-) diff --git a/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 b/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 index 88a8c42081..05f518847e 100644 --- a/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 +++ b/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 @@ -4307,7 +4307,6 @@ keyword | CHANGE_TRACKING | CHECKDB | CHECKFILEGROUP - | CHECKIDENT | CHECKSUM | CHECKSUM_AGG | CHECKTABLE diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index fef5c103ce..46f6fe958b 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -20,8 +20,6 @@ #include "pl_explain.h" #include "session.h" -#include - /* helper function to get current T-SQL estate */ PLtsql_execstate *get_current_tsql_estate(void); PLtsql_execstate *get_outermost_tsql_estate(int *nestlevel); @@ -3257,7 +3255,7 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) } else { - nsp_name = get_physical_schema_name(db_name, dbcc_stmt.schema_name); + nsp_name = get_physical_schema_name(db_name, schema_name); } } pfree(db_name); diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index 9dd98ab8cf..24cfbc490e 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -947,12 +947,12 @@ 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; + 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; @@ -962,10 +962,10 @@ typedef union PLtsql_dbcc_stmt_data */ 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; + int lineno; + PLtsql_stmt_type cmd_type; + PLtsql_dbcc_stmt_type dbcc_stmt_type; + PLtsql_dbcc_stmt_data dbcc_stmt_data; } PLtsql_stmt_dbcc; /* diff --git a/test/JDBC/expected/BABEL-3201-vu-verify.out b/test/JDBC/expected/BABEL-3201-vu-verify.out index e9b536e4e4..cbc9057da8 100644 --- a/test/JDBC/expected/BABEL-3201-vu-verify.out +++ b/test/JDBC/expected/BABEL-3201-vu-verify.out @@ -660,9 +660,28 @@ 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..t1', NORESEED); +DBCC CHECKIDENT('babel_3201_db1..babel_3201_db1_database_table1', NORESEED); GO ~~ERROR (Code: 33557097)~~ diff --git a/test/JDBC/input/BABEL-3201-vu-verify.mix b/test/JDBC/input/BABEL-3201-vu-verify.mix index a94b407dfc..308706cf5b 100644 --- a/test/JDBC/input/BABEL-3201-vu-verify.mix +++ b/test/JDBC/input/BABEL-3201-vu-verify.mix @@ -378,9 +378,24 @@ 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..t1', NORESEED); +DBCC CHECKIDENT('babel_3201_db1..babel_3201_db1_database_table1', NORESEED); GO -- tsql From 307681a54f1eae025e4f19caf45da8f92e952d1f Mon Sep 17 00:00:00 2001 From: Sandeep Kumawat Date: Wed, 18 Oct 2023 04:50:50 +0000 Subject: [PATCH 16/17] address test failures Signed-off-by: Sandeep Kumawat --- contrib/babelfishpg_tsql/src/pltsql.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index 24cfbc490e..622a57a2ec 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -962,8 +962,8 @@ typedef union PLtsql_dbcc_stmt_data */ typedef struct PLtsql_stmt_dbcc { - int lineno; PLtsql_stmt_type cmd_type; + int lineno; PLtsql_dbcc_stmt_type dbcc_stmt_type; PLtsql_dbcc_stmt_data dbcc_stmt_data; } PLtsql_stmt_dbcc; From b589b738827ad628d641893eda842b732ebbefab Mon Sep 17 00:00:00 2001 From: Sandeep Kumawat Date: Wed, 18 Oct 2023 22:54:28 +0000 Subject: [PATCH 17/17] This commit - - Address PR comments - Fixes locking behaviour Signed-off-by: Sandeep Kumawat --- contrib/babelfishpg_tsql/src/pl_exec-2.c | 64 ++++++++------ test/JDBC/expected/BABEL-3201-vu-cleanup.out | 6 ++ test/JDBC/expected/BABEL-3201-vu-prepare.out | 14 ++++ test/JDBC/expected/BABEL-3201-vu-verify.out | 88 +++++++++++++++++++- test/JDBC/input/BABEL-3201-vu-cleanup.sql | 6 ++ test/JDBC/input/BABEL-3201-vu-prepare.sql | 12 +++ test/JDBC/input/BABEL-3201-vu-verify.mix | 56 ++++++++++++- 7 files changed, 218 insertions(+), 28 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index 46f6fe958b..a30afeb1f4 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -3152,7 +3152,7 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) int64 max_identity_value = 0; int64 cur_identity_value = 0; int attnum; - int rc; + int rc = 0; int64 reseed_value = 0; Oid nsp_oid; Oid table_oid; @@ -3164,6 +3164,7 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) 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 */ @@ -3184,23 +3185,23 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) else reseed_value = pg_strtoint64(dbcc_stmt.new_reseed_value); } - - db_name = get_cur_db_name(); - if (dbcc_stmt.db_name) - { + + 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) - { + 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); + db_name = pstrdup(dbcc_stmt.db_name); } - } + } user = get_user_for_database(db_name); login_is_db_owner = 0 == strncmp(GetUserNameFromId(GetSessionUserId(), false), @@ -3208,11 +3209,11 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) /* Raise an error if the login does not have access to the database */ if(is_cross_db) - { - if (user) - SetCurrentRoleId(GetSessionUserId(), false); - else - { + { + if (user) + SetCurrentRoleId(GetSessionUserId(), false); + else + { login = GetUserNameFromId(GetSessionUserId(), false); pfree(db_name); ereport(ERROR, @@ -3221,7 +3222,7 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) "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) @@ -3237,13 +3238,10 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) */ guest_role_name = get_guest_role_name(db_name); dbo_role_name = get_dbo_role_name(db_name); - if (!user) - { - pfree(db_name); - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("user does not exist"))); - } + + /* 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)) { @@ -3392,7 +3390,9 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) 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); @@ -3401,8 +3401,6 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) cur_identity_value, max_identity_value_str ? max_identity_value_str : "NULL"); - SPI_freetuptable(SPI_tuptable); - /* * RESEED option only resets the identity column value if the * current identity value for a table is less than the maximum @@ -3430,6 +3428,13 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) 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); @@ -3443,11 +3448,18 @@ void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) 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."); diff --git a/test/JDBC/expected/BABEL-3201-vu-cleanup.out b/test/JDBC/expected/BABEL-3201-vu-cleanup.out index a8fd1ec7fd..455056962a 100644 --- a/test/JDBC/expected/BABEL-3201-vu-cleanup.out +++ b/test/JDBC/expected/BABEL-3201-vu-cleanup.out @@ -37,6 +37,9 @@ GO DROP TABLE babel_3201_sch1.babel_3201_t2; GO +DROP TABLE babel_3201_test_locks; +GO + DROP PROCEDURE babel_3201_proc1; GO @@ -46,6 +49,9 @@ GO DROP LOGIN babel_3201_log1; GO +DROP LOGIN babel_3201_test_locks; +GO + DROP SCHEMA babel_3201_sch1; GO diff --git a/test/JDBC/expected/BABEL-3201-vu-prepare.out b/test/JDBC/expected/BABEL-3201-vu-prepare.out index 6db69d5bab..4bef6e6006 100644 --- a/test/JDBC/expected/BABEL-3201-vu-prepare.out +++ b/test/JDBC/expected/BABEL-3201-vu-prepare.out @@ -40,6 +40,14 @@ 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~~ @@ -147,3 +155,9 @@ 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 index cbc9057da8..762aed89fd 100644 --- a/test/JDBC/expected/BABEL-3201-vu-verify.out +++ b/test/JDBC/expected/BABEL-3201-vu-verify.out @@ -466,6 +466,24 @@ Go ~~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 @@ -646,7 +664,11 @@ go 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_mod +-- 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 @@ -722,6 +744,70 @@ GO 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/input/BABEL-3201-vu-cleanup.sql b/test/JDBC/input/BABEL-3201-vu-cleanup.sql index a8fd1ec7fd..455056962a 100644 --- a/test/JDBC/input/BABEL-3201-vu-cleanup.sql +++ b/test/JDBC/input/BABEL-3201-vu-cleanup.sql @@ -37,6 +37,9 @@ GO DROP TABLE babel_3201_sch1.babel_3201_t2; GO +DROP TABLE babel_3201_test_locks; +GO + DROP PROCEDURE babel_3201_proc1; GO @@ -46,6 +49,9 @@ GO DROP LOGIN babel_3201_log1; GO +DROP LOGIN babel_3201_test_locks; +GO + DROP SCHEMA babel_3201_sch1; GO diff --git a/test/JDBC/input/BABEL-3201-vu-prepare.sql b/test/JDBC/input/BABEL-3201-vu-prepare.sql index faa32eaeba..0a033d32e1 100644 --- a/test/JDBC/input/BABEL-3201-vu-prepare.sql +++ b/test/JDBC/input/BABEL-3201-vu-prepare.sql @@ -40,6 +40,12 @@ 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 @@ -109,3 +115,9 @@ 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 index 308706cf5b..bb3bf5124b 100644 --- a/test/JDBC/input/BABEL-3201-vu-verify.mix +++ b/test/JDBC/input/BABEL-3201-vu-verify.mix @@ -252,6 +252,12 @@ 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 @@ -364,7 +370,11 @@ go 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_mod +-- 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 @@ -428,6 +438,50 @@ GO 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