diff --git a/contrib/shark/dbcc.cpp b/contrib/shark/dbcc.cpp index 97b2bc893e1cd01f78334c86dc3af1ca8dfa48f7..c62ec02cbd1d32f00988eaad50615dc6be54ea61 100644 --- a/contrib/shark/dbcc.cpp +++ b/contrib/shark/dbcc.cpp @@ -2,6 +2,8 @@ #include "shark.h" #include "commands/sequence.h" #include "utils/builtins.h" +#include "executor/spi.h" + #define DBCC_RESULT_MAX_LENGTH 256 @@ -14,6 +16,40 @@ extern "C" Datum dbcc_check_ident_reseed(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(dbcc_check_ident_no_reseed); PG_FUNCTION_INFO_V1(dbcc_check_ident_reseed); + +bool is_relation_empty(text* txt) +{ + errno_t rc = EOK; + int ret = 0; + bool isnull = false; + char* table_name = TextDatumGetCString(txt); + char table_cnt_sql[FULL_TABLE_NAME_MAX_LENGTH] = {0}; + rc = snprintf_s(table_cnt_sql, FULL_TABLE_NAME_MAX_LENGTH, FULL_TABLE_NAME_MAX_LENGTH - 1, + "select 1 from %s limit 1;", table_name); + securec_check_ss(rc, "", ""); + + if (SPI_OK_CONNECT != SPI_connect()) { + ereport(ERROR, + (errcode(ERRCODE_SPI_CONNECTION_FAILURE), + errmsg("Unable to connect to execute internal select count value."))); + } + ret = SPI_execute(table_cnt_sql, true, 1); + if (ret < 0) { + ereport(ERROR, + (errcode(ERRCODE_SPI_EXECUTE_FAILURE), + errmsg("Call SPI_execute execute interval select count value failed."))); + } + + if (SPI_processed == 0) { + isnull = true; + } + + SPI_finish(); + + return isnull; +} + + Datum dbcc_check_ident_no_reseed(PG_FUNCTION_ARGS) { int64 last_value = 0; @@ -32,19 +68,27 @@ Datum dbcc_check_ident_no_reseed(PG_FUNCTION_ARGS) reseed_to_max = PG_GETARG_BOOL(2); } - get_last_value_and_max_value(txt, &last_value, ¤t_max_value); + bool is_empty_table = is_relation_empty(txt); - if (reseed_to_max && last_value < current_max_value) { - get_and_reset_last_value(txt, current_max_value, true); + if (!is_empty_table) { + get_last_value_and_max_value(txt, &last_value, ¤t_max_value); + if (reseed_to_max && last_value < current_max_value) { + get_and_reset_last_value(txt, current_max_value, true); + } } if (!withmsg) { PG_RETURN_NULL(); } - rc = snprintf_s(result, DBCC_RESULT_MAX_LENGTH, DBCC_RESULT_MAX_LENGTH - 1, - "Checking identity information: current identity value '%lld', current column value '%lld'.", - last_value, current_max_value); + if (is_empty_table) { + rc = snprintf_s(result, DBCC_RESULT_MAX_LENGTH, DBCC_RESULT_MAX_LENGTH - 1, + "Checking identity information: current identity value 'NULL', current column value 'NULL'."); + } else { + rc = snprintf_s(result, DBCC_RESULT_MAX_LENGTH, DBCC_RESULT_MAX_LENGTH - 1, + "Checking identity information: current identity value '%lld', current column value '%lld'.", + last_value, current_max_value); + } securec_check_ss(rc, "\0", "\0"); ereport(NOTICE, (errmsg("\"%s\"", result))); @@ -76,14 +120,23 @@ Datum dbcc_check_ident_reseed(PG_FUNCTION_ARGS) withmsg = !PG_GETARG_BOOL(2); } - last_value = get_and_reset_last_value(txt, new_seed, need_reseed); + bool is_empty_table = is_relation_empty(txt); + + if (!is_empty_table) { + last_value = get_and_reset_last_value(txt, new_seed, need_reseed); + } if (!withmsg) { PG_RETURN_NULL(); } - rc = snprintf_s(result, DBCC_RESULT_MAX_LENGTH, DBCC_RESULT_MAX_LENGTH - 1, - "Checking identity information: current identity value '%lld'.", last_value); + if (is_empty_table) { + rc = snprintf_s(result, DBCC_RESULT_MAX_LENGTH, DBCC_RESULT_MAX_LENGTH - 1, + "Checking identity information: current identity value 'NULL'."); + } else { + rc = snprintf_s(result, DBCC_RESULT_MAX_LENGTH, DBCC_RESULT_MAX_LENGTH - 1, + "Checking identity information: current identity value '%lld'.", last_value); + } securec_check_ss(rc, "\0", "\0"); ereport(NOTICE, (errmsg("\"%s\"", result))); diff --git a/contrib/shark/expected/test_dbcc.out b/contrib/shark/expected/test_dbcc.out index 9389aac518109870ed34a96c107c16b416259556..19bf43b16540885957f9b0fba17cf7e26b4a95b1 100644 --- a/contrib/shark/expected/test_dbcc.out +++ b/contrib/shark/expected/test_dbcc.out @@ -106,7 +106,10 @@ CONTEXT: referenced column: dbcc_check_ident_no_reseed -- error case expect DBCC CHECKIDENT ('Employees1', NORESEED); -ERROR: relation "employees1" does not exist +ERROR: relation "employees1" does not exist on datanode1 +LINE 1: select 1 from Employees1 limit 1; + ^ +QUERY: select 1 from Employees1 limit 1; CONTEXT: referenced column: dbcc_check_ident_no_reseed DBCC CHECKIDENT ('employees_employeeid_seq', NORESEED); ERROR: relation "employees_employeeid_seq" does not exist @@ -460,11 +463,15 @@ GRANT SELECT ON Employees to normalrole_user_002; GRANT SELECT,UPDATE ON Employees to normalrole_user_003; SET SESSION AUTHORIZATION normalrole_user_001 PASSWORD 'Gauss@123'; DBCC CHECKIDENT ('Employees', NORESEED); -ERROR: permission denied for sequence employees -CONTEXT: referenced column: dbcc_check_ident_no_reseed +ERROR: permission denied for relation employees +DETAIL: N/A +CONTEXT: SQL statement "select 1 from Employees limit 1;" +referenced column: dbcc_check_ident_no_reseed DBCC CHECKIDENT ('Employees', RESEED, 1); -ERROR: permission denied for sequence employees -CONTEXT: referenced column: dbcc_check_ident_reseed +ERROR: permission denied for relation employees +DETAIL: N/A +CONTEXT: SQL statement "select 1 from Employees limit 1;" +referenced column: dbcc_check_ident_reseed RESET SESSION AUTHORIZATION; SET SESSION AUTHORIZATION normalrole_user_002 PASSWORD 'Gauss@123'; DBCC CHECKIDENT ('Employees', NORESEED); @@ -501,6 +508,53 @@ drop user normalrole_user_001 cascade; drop user normalrole_user_002 cascade; drop user normalrole_user_003 cascade; drop table Employees; +-- empty table + CREATE TABLE Employees1 ( + EmployeeID serial , + Name VARCHAR(100) NOT NULL + ); +NOTICE: CREATE TABLE will create implicit sequence "employees1_employeeid_seq" for serial column "employees1.employeeid" +DBCC CHECKIDENT ('Employees1', NORESEED); +NOTICE: "Checking identity information: current identity value 'NULL', current column value 'NULL'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +-------------------------------------------------------------------------------------------- + Checking identity information: current identity value 'NULL', current column value 'NULL'. +(1 row) + +DBCC CHECKIDENT ('Employees1', RESEED, 1); +NOTICE: "Checking identity information: current identity value 'NULL'." +CONTEXT: referenced column: dbcc_check_ident_reseed + dbcc_check_ident_reseed +--------------------------------------------------------------- + Checking identity information: current identity value 'NULL'. +(1 row) + +DBCC CHECKIDENT ('Employees1', NORESEED); +NOTICE: "Checking identity information: current identity value 'NULL', current column value 'NULL'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +-------------------------------------------------------------------------------------------- + Checking identity information: current identity value 'NULL', current column value 'NULL'. +(1 row) + +DBCC CHECKIDENT ('Employees1', RESEED, 1); +NOTICE: "Checking identity information: current identity value 'NULL'." +CONTEXT: referenced column: dbcc_check_ident_reseed + dbcc_check_ident_reseed +--------------------------------------------------------------- + Checking identity information: current identity value 'NULL'. +(1 row) + +DBCC CHECKIDENT ('Employees1', NORESEED); +NOTICE: "Checking identity information: current identity value 'NULL', current column value 'NULL'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +-------------------------------------------------------------------------------------------- + Checking identity information: current identity value 'NULL', current column value 'NULL'. +(1 row) + +drop table Employees1; -- create table as create table t2(id int, name int); insert into t2 values (1, 1); diff --git a/contrib/shark/sql/test_dbcc.sql b/contrib/shark/sql/test_dbcc.sql index 131634e0ef511f7671a72e0e2d2c1ce4ba33e095..5f7a61d1b972cf6c7ac51004b98a73c3bd4239e7 100644 --- a/contrib/shark/sql/test_dbcc.sql +++ b/contrib/shark/sql/test_dbcc.sql @@ -275,6 +275,20 @@ drop user normalrole_user_002 cascade; drop user normalrole_user_003 cascade; drop table Employees; +-- empty table + CREATE TABLE Employees1 ( + EmployeeID serial , + Name VARCHAR(100) NOT NULL + ); + +DBCC CHECKIDENT ('Employees1', NORESEED); +DBCC CHECKIDENT ('Employees1', RESEED, 1); +DBCC CHECKIDENT ('Employees1', NORESEED); +DBCC CHECKIDENT ('Employees1', RESEED, 1); +DBCC CHECKIDENT ('Employees1', NORESEED); + +drop table Employees1; + -- create table as create table t2(id int, name int); insert into t2 values (1, 1);