-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for DBCC CHECKIDENT #1646
Support for DBCC CHECKIDENT #1646
Conversation
Signed-off-by: Aditya Verma <[email protected]>
Signed-off-by: Aditya Verma <[email protected]>
Signed-off-by: Aditya Verma <[email protected]>
Signed-off-by: Aditya Verma <[email protected]>
Signed-off-by: Aditya Verma <[email protected]>
Signed-off-by: Aditya Verma <[email protected]>
if (pltsql_explain_only) | ||
{ | ||
ereport(ERROR, | ||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | ||
errmsg("Showing Estimated Execution Plan for DBCC statment is not yet supported"))); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DBCC is utility command. It doesn't make sense to show an execution plan for the same. What's the SQL Server behavior?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Executing DBCC CHECKIDENT after SET SHOWPLAN_ALL ON in SQL Server does not throw and error but most of the fields come out to be NULL, I have removed the condition for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, which condition exactly have you removed? What's the Babelfish behavior with your changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies, I just saw that I hadn't included this file in the commit, I meant I have removed the pltsql_explain_only condition for now.
antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) | ||
{ | ||
|
||
if (ctx->dbcc_command()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add some telemetry for DBCC statements. Can be addressed separately.
/* | ||
* 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. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not clear what CHECKIDENT behavior we're trying to implement here. Also, we shouldn't do the relation scan if customer has already provided the new seed value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated the comments and finding the max value of the column where it's required ( not when new_reseed_value ) is already provided.
* 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we using catalog scan API to scan an user relation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we have to use MAX() to find out the maximum value, I have removed the catalog scan API.
|
||
if (HeapTupleIsValid(tuple)) | ||
{ | ||
max_identity_value = DatumGetInt64(heap_getattr(tuple, attnum+1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last value need not be the max value. We should execute the select max(id) from table query and fetch the result.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made the change in the latest commit. Thanks.
@@ -0,0 +1,35 @@ | |||
DBCC CHECKIDENT(babel_3201_t1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please try to add at least one test case for all the errors these changes are introducing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added test cases for all the functional scenarios, corner cases ( no rows have been inserted in table, rows are removed using TRUNCATE TABLE, rows are deleted using DELETE TABLE), and negative tests for syntax and datatype bounds.
@@ -0,0 +1,59 @@ | |||
DBCC CHECKIDENT(babel_3201_t1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also add some tests to validate transactional behaviour.
Running DBCC inside a transaction
DBCC running into error inside transaction
Calling DBCC from procedure/functions (with/without errors)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added tests for transactions and procedures. Please take a look. Thanks.
- 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 <[email protected]>
Signed-off-by: Aditya Verma <[email protected]>
- added permission related tests - updated BABEL-UNSUPPORTED tests - added Relation lock on table Signed-off-by: Aditya Verma <[email protected]>
- fix for locking behaviour - tests in isolation test framework for concurrency - Add some missing jdbc tests - Address review comments Signed-off-by: Sandeep Kumawat <[email protected]>
Signed-off-by: Sandeep Kumawat <[email protected]>
else | ||
{ | ||
/* | ||
* If schema_name is not provided, find default schema for current user | ||
* and get physical schema name | ||
*/ | ||
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); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing dbo user handling. Please refer set_search_path_for_user_schema() for more details.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
made changes. Please have a look.
if (ctx->table_name()->schema) | ||
schema_name = stripQuoteFromId(ctx->table_name()->schema); | ||
if (ctx->table_name()->table) | ||
table_name = stripQuoteFromId(ctx->table_name()->table); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indentaion
int64 max_identity_value = 0; | ||
int64 cur_identity_value = 0; | ||
char *max_identity_value_str = NULL; | ||
char *login = GetUserNameFromId(GetSessionUserId(), false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indentation
char message[200]; | ||
|
||
|
||
bool is_cross_db = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indentation
{ | ||
PG_RE_THROW(); | ||
if (is_cross_db) | ||
SetCurrentRoleId(current_user_id, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
control will never come here, we should first do set and then rethrow
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
made changes. please have a look.
} | ||
PG_CATCH(); | ||
{ | ||
PG_RE_THROW(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
who will release lock in case of errors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
made changes to release locks in case of errors.
|
||
if(!dbcc_stmt.new_reseed_value) | ||
{ | ||
UnlockRelationOid(table_oid, ShareLock); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about exclusive lock?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, we are trying to hold this shareLock on table only for the execution of this statement. We try to hold Exclusive Lock on a transaction level. We want to release this share lock as soon as we are done with the execution of DBCC CHECKIDENT() stmt. But Exclusive Lock will get release when transection gets commited or rollbacked.
} | ||
PG_END_TRY(); | ||
|
||
if (max_identity_value_str) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we want to free memory for error cases as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done. made changes in the next commit. please take a look.
if (is_cross_db) | ||
SetCurrentRoleId(current_user_id, false); | ||
} | ||
PG_CATCH(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we have test cases with different error and lock types?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So there are test-cases in isolation test framwork, when one transection made update to table t1 (by reseeding identity value via dbcc checkident) and other transection is not able to use t1 inside a dbcc checkident stmt.
- Correct Parser Support for DBCC CHECKIDENT,<table_name> 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 <[email protected]>
| CHECKDB | ||
| CHECKFILEGROUP | ||
| CHECKIDENT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still need these changes ? since in the dbcc_command rule we have already explicitly specified them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct. Removing.
@@ -19,6 +20,8 @@ | |||
#include "pl_explain.h" | |||
#include "session.h" | |||
|
|||
#include <math.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it needed?
I see we are using pg_strtoint64 which is there 'utils/builtins.h' which is indirectly included by some other header.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Removing it .
else | ||
{ | ||
nsp_name = get_physical_schema_name(db_name, dbcc_stmt.schema_name); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is incorrect. Here dbcc_stmt will be NULL We are missing coverage for this case otherwise it would have failed.
It should be schema_name instead. Move schema_name evaluation inside this condition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for pointing this out. Fixing it and also adding a test-case for the coverage. However as we do need schema_ name later ahead in the code, keeping schema_name evaluation out of this else condition
Signed-off-by: Sandeep Kumawat <[email protected]>
Signed-off-by: Sandeep Kumawat <[email protected]>
|
||
if (is_float_value) | ||
{ | ||
if (dbcc_stmt.new_reseed_value[0] == '.' || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
have we tried input like ".", "-" etc for testing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tested and added cases.
(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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make sure we have test cases for mixed case db name and DB name more than 64 chars (if allowed)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are test cases with db name longer then 64 char, mixed case db name.
} | ||
|
||
user = get_user_for_database(db_name); | ||
login_is_db_owner = 0 == strncmp(GetUserNameFromId(GetSessionUserId(), false), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make sure we have test cases for mixed case user name and user name more than 64 chars (if allowed)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added a test case where user name is longer then 64 chars.
*/ | ||
if (!user) | ||
{ | ||
ereport(ERROR, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not clear. can you test without cross db? also, if we cannot write a test case means that code path is not possible. If that is the case, add an assert (at-least for debug)
- Address PR comments - Fixes locking behaviour Signed-off-by: Sandeep Kumawat <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Verified user and permissions related changes. Looks good!
On leave and goes beyond code freeze. Will request Kuntal to review this again once he is back. Meanwhile all the comments are addressed and resolved.
2ad7351
into
babelfish-for-postgresql:BABEL_3_X_DEV
Description
This changes adds support for DBCC CHECKIDENT command in Babelfish that allows user to reset the current value of the identity column in a table. Earlier user had to do the same with Setval() command from pg end-point, with this change they can do it directly from T-SQL end-point. As this is the first time a DBCC command is implemented in Babelfish, this change also provides support to syntax for DBCC commands, and the design is kept scalable so that new DBCC commands can be better introduced in future.
Issues Resolved
BABEL-3201
Test Scenarios Covered
Use case based -
Yes
Boundary conditions -
Yes
Arbitrary inputs -
Yes
Negative test cases -
Yes
Minor version upgrade tests -
N/A
Major version upgrade tests -
N/A
Performance tests -
N/A
Tooling impact -
N/A
Client tests -
N/A
Check List
By submitting this pull request, I confirm that my contribution is under the terms of the Apache 2.0 and PostgreSQL licenses, and grant any person obtaining a copy of the contribution permission to relicense all or a portion of my contribution to the PostgreSQL License solely to contribute all or a portion of my contribution to the PostgreSQL open source project.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.