Skip to content
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

Merged

Conversation

aadityavermaa
Copy link
Contributor

@aadityavermaa aadityavermaa commented Jul 25, 2023

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

  • Commits are signed per the DCO using --signoff

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.

@aadityavermaa aadityavermaa changed the title Parser support for DBCC CHECKIDENT Support for DBCC CHECKIDENT Aug 11, 2023
Comment on lines 832 to 837
if (pltsql_explain_only)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Showing Estimated Execution Plan for DBCC statment is not yet supported")));
}
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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?

Copy link
Contributor Author

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.

contrib/babelfishpg_tsql/src/pl_funcs-2.c Show resolved Hide resolved
antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitDbcc_statement(TSqlParser::Dbcc_statementContext *ctx)
{

if (ctx->dbcc_command())
Copy link
Contributor

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.

contrib/babelfishpg_tsql/src/pl_exec-2.c Show resolved Hide resolved
contrib/babelfishpg_tsql/src/pl_exec-2.c Outdated Show resolved Hide resolved
Comment on lines 3092 to 3096
/*
* 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.
*/
Copy link
Contributor

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.

Copy link
Contributor Author

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);
Copy link
Contributor

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?

Copy link
Contributor Author

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,
Copy link
Contributor

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.

Copy link
Contributor Author

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);
Copy link
Contributor

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.

Copy link
Contributor Author

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);
Copy link
Contributor

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)

Copy link
Contributor Author

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.

Aditya Verma and others added 7 commits August 22, 2023 06:05
- 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]>
- added permission related tests
- updated BABEL-UNSUPPORTED tests
- added Relation lock on table

Signed-off-by: Aditya Verma <[email protected]>
contrib/babelfishpg_tsql/src/pl_exec-2.c Show resolved Hide resolved
contrib/babelfishpg_tsql/src/pl_exec-2.c Outdated Show resolved Hide resolved
contrib/babelfishpg_tsql/src/pl_exec-2.c Outdated Show resolved Hide resolved
contrib/babelfishpg_tsql/src/pl_exec-2.c Show resolved Hide resolved
contrib/babelfishpg_tsql/src/pl_exec-2.c Outdated Show resolved Hide resolved
contrib/babelfishpg_tsql/src/pl_exec-2.c Show resolved Hide resolved
contrib/babelfishpg_tsql/src/pl_exec-2.c Outdated Show resolved Hide resolved
test/JDBC/input/BABEL-3201-vu-verify.mix Outdated Show resolved Hide resolved
test/JDBC/input/BABEL-3201-vu-verify.mix Show resolved Hide resolved
test/JDBC/input/BABEL-3201-vu-verify.mix Show resolved Hide resolved
Sandeep Kumawat added 3 commits October 3, 2023 05:28
- 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]>
contrib/babelfishpg_tsql/src/pl_exec-2.c Outdated Show resolved Hide resolved
Comment on lines 3215 to 3235
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);
}
Copy link
Contributor

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.

Copy link
Contributor

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.

contrib/babelfishpg_tsql/src/tsqlIface.cpp Outdated Show resolved Hide resolved
contrib/babelfishpg_tsql/src/tsqlIface.cpp Outdated Show resolved Hide resolved
if (ctx->table_name()->schema)
schema_name = stripQuoteFromId(ctx->table_name()->schema);
if (ctx->table_name()->table)
table_name = stripQuoteFromId(ctx->table_name()->table);
Copy link
Contributor

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);
Copy link
Contributor

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;
Copy link
Contributor

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);
Copy link
Contributor

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

Copy link
Contributor

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();
Copy link
Contributor

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?

Copy link
Contributor

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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about exclusive lock?

Copy link
Contributor

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)
Copy link
Contributor

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

Copy link
Contributor

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();
Copy link
Contributor

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?

Copy link
Contributor

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.

Sandeep Kumawat added 2 commits October 15, 2023 23:24
- 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]>
Comment on lines 4308 to 4310
| CHECKDB
| CHECKFILEGROUP
| CHECKIDENT
Copy link
Contributor

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.

Copy link
Contributor

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>
Copy link
Contributor

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Removing it .

Comment on lines 3258 to 3261
else
{
nsp_name = get_physical_schema_name(db_name, dbcc_stmt.schema_name);
}
Copy link
Contributor

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.

Copy link
Contributor

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

Sandeep Kumawat added 2 commits October 17, 2023 20:55
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] == '.' ||
Copy link
Contributor

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?

Copy link
Contributor

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)
Copy link
Contributor

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)

Copy link
Contributor

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),
Copy link
Contributor

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)

Copy link
Contributor

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,
Copy link
Contributor

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]>
Copy link
Contributor

@HarshLunagariya HarshLunagariya left a 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!

@jsudrik jsudrik dismissed kuntalghosh’s stale review October 23, 2023 08:25

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.

@jsudrik jsudrik merged commit 2ad7351 into babelfish-for-postgresql:BABEL_3_X_DEV Oct 23, 2023
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants